]>
Commit | Line | Data |
---|---|---|
1 | // Copyright (C) 2020-2025 Free Software Foundation, Inc. | |
2 | ||
3 | // This file is part of GCC. | |
4 | ||
5 | // GCC is free software; you can redistribute it and/or modify it under | |
6 | // the terms of the GNU General Public License as published by the Free | |
7 | // Software Foundation; either version 3, or (at your option) any later | |
8 | // version. | |
9 | ||
10 | // GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
11 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
13 | // for more details. | |
14 | ||
15 | // You should have received a copy of the GNU General Public License | |
16 | // along with GCC; see the file COPYING3. If not see | |
17 | // <http://www.gnu.org/licenses/>. | |
18 | ||
19 | /* Template implementation for Rust::Parser. Previously in rust-parse.cc (before | |
20 | * Parser was template). Separated from rust-parse.h for readability. */ | |
21 | ||
22 | /* DO NOT INCLUDE ANYWHERE - this is automatically included with rust-parse.h | |
23 | * This is also the reason why there are no include guards. */ | |
24 | ||
25 | #include "rust-common.h" | |
26 | #include "rust-expr.h" | |
27 | #include "rust-item.h" | |
28 | #include "rust-common.h" | |
29 | #include "rust-token.h" | |
30 | #define INCLUDE_ALGORITHM | |
31 | #include "rust-diagnostics.h" | |
32 | #include "rust-dir-owner.h" | |
33 | #include "rust-attribute-values.h" | |
34 | #include "rust-keyword-values.h" | |
35 | #include "rust-edition.h" | |
36 | ||
37 | #include "optional.h" | |
38 | ||
39 | namespace Rust { | |
40 | // Left binding powers of operations. | |
41 | enum binding_powers | |
42 | { | |
43 | // Highest priority | |
44 | LBP_HIGHEST = 100, | |
45 | ||
46 | LBP_PATH = 95, | |
47 | ||
48 | LBP_METHOD_CALL = 90, | |
49 | ||
50 | LBP_FIELD_EXPR = 85, | |
51 | ||
52 | LBP_FUNCTION_CALL = 80, | |
53 | LBP_ARRAY_REF = LBP_FUNCTION_CALL, | |
54 | ||
55 | LBP_QUESTION_MARK = 75, // unary postfix - counts as left | |
56 | ||
57 | LBP_UNARY_PLUS = 70, // Used only when the null denotation is + | |
58 | LBP_UNARY_MINUS = LBP_UNARY_PLUS, // Used only when the null denotation is - | |
59 | LBP_UNARY_ASTERISK = LBP_UNARY_PLUS, // deref operator - unary prefix | |
60 | LBP_UNARY_EXCLAM = LBP_UNARY_PLUS, | |
61 | LBP_UNARY_AMP = LBP_UNARY_PLUS, | |
62 | LBP_UNARY_AMP_MUT = LBP_UNARY_PLUS, | |
63 | ||
64 | LBP_AS = 65, | |
65 | ||
66 | LBP_MUL = 60, | |
67 | LBP_DIV = LBP_MUL, | |
68 | LBP_MOD = LBP_MUL, | |
69 | ||
70 | LBP_PLUS = 55, | |
71 | LBP_MINUS = LBP_PLUS, | |
72 | ||
73 | LBP_L_SHIFT = 50, | |
74 | LBP_R_SHIFT = LBP_L_SHIFT, | |
75 | ||
76 | LBP_AMP = 45, | |
77 | ||
78 | LBP_CARET = 40, | |
79 | ||
80 | LBP_PIPE = 35, | |
81 | ||
82 | LBP_EQUAL = 30, | |
83 | LBP_NOT_EQUAL = LBP_EQUAL, | |
84 | LBP_SMALLER_THAN = LBP_EQUAL, | |
85 | LBP_SMALLER_EQUAL = LBP_EQUAL, | |
86 | LBP_GREATER_THAN = LBP_EQUAL, | |
87 | LBP_GREATER_EQUAL = LBP_EQUAL, | |
88 | ||
89 | LBP_LOGICAL_AND = 25, | |
90 | ||
91 | LBP_LOGICAL_OR = 20, | |
92 | ||
93 | LBP_DOT_DOT = 15, | |
94 | LBP_DOT_DOT_EQ = LBP_DOT_DOT, | |
95 | ||
96 | // TODO: note all these assig operators are RIGHT associative! | |
97 | LBP_ASSIG = 10, | |
98 | LBP_PLUS_ASSIG = LBP_ASSIG, | |
99 | LBP_MINUS_ASSIG = LBP_ASSIG, | |
100 | LBP_MULT_ASSIG = LBP_ASSIG, | |
101 | LBP_DIV_ASSIG = LBP_ASSIG, | |
102 | LBP_MOD_ASSIG = LBP_ASSIG, | |
103 | LBP_AMP_ASSIG = LBP_ASSIG, | |
104 | LBP_PIPE_ASSIG = LBP_ASSIG, | |
105 | LBP_CARET_ASSIG = LBP_ASSIG, | |
106 | LBP_L_SHIFT_ASSIG = LBP_ASSIG, | |
107 | LBP_R_SHIFT_ASSIG = LBP_ASSIG, | |
108 | ||
109 | // return, break, and closures as lowest priority? | |
110 | LBP_RETURN = 5, | |
111 | LBP_BREAK = LBP_RETURN, | |
112 | LBP_CLOSURE = LBP_RETURN, // unary prefix operators | |
113 | ||
114 | #if 0 | |
115 | // rust precedences | |
116 | // used for closures | |
117 | PREC_CLOSURE = -40, | |
118 | // used for break, continue, return, and yield | |
119 | PREC_JUMP = -30, | |
120 | // used for range (although weird comment in rustc about this) | |
121 | PREC_RANGE = -10, | |
122 | // used for binary operators mentioned below - also cast, colon (type), | |
123 | // assign, assign_op | |
124 | PREC_BINOP = FROM_ASSOC_OP, | |
125 | // used for box, address_of, let, unary (again, weird comment on let) | |
126 | PREC_PREFIX = 50, | |
127 | // used for await, call, method call, field, index, try, | |
128 | // inline asm, macro invocation | |
129 | PREC_POSTFIX = 60, | |
130 | // used for array, repeat, tuple, literal, path, paren, if, | |
131 | // while, for, 'loop', match, block, try block, async, struct | |
132 | PREC_PAREN = 99, | |
133 | PREC_FORCE_PAREN = 100, | |
134 | #endif | |
135 | ||
136 | // lowest priority | |
137 | LBP_LOWEST = 0 | |
138 | }; | |
139 | ||
140 | /* Returns whether the token can start a type (i.e. there is a valid type | |
141 | * beginning with the token). */ | |
142 | inline bool | |
143 | can_tok_start_type (TokenId id) | |
144 | { | |
145 | switch (id) | |
146 | { | |
147 | case EXCLAM: | |
148 | case LEFT_SQUARE: | |
149 | case LEFT_ANGLE: | |
150 | case UNDERSCORE: | |
151 | case ASTERISK: | |
152 | case AMP: | |
153 | case LIFETIME: | |
154 | case IDENTIFIER: | |
155 | case SUPER: | |
156 | case SELF: | |
157 | case SELF_ALIAS: | |
158 | case CRATE: | |
159 | case DOLLAR_SIGN: | |
160 | case SCOPE_RESOLUTION: | |
161 | case LEFT_PAREN: | |
162 | case FOR: | |
163 | case ASYNC: | |
164 | case CONST: | |
165 | case UNSAFE: | |
166 | case EXTERN_KW: | |
167 | case FN_KW: | |
168 | case IMPL: | |
169 | case DYN: | |
170 | case QUESTION_MARK: | |
171 | return true; | |
172 | default: | |
173 | return false; | |
174 | } | |
175 | } | |
176 | ||
177 | /* Returns whether the token id is (or is likely to be) a right angle bracket. | |
178 | * i.e. '>', '>>', '>=' and '>>=' tokens. */ | |
179 | inline bool | |
180 | is_right_angle_tok (TokenId id) | |
181 | { | |
182 | switch (id) | |
183 | { | |
184 | case RIGHT_ANGLE: | |
185 | case RIGHT_SHIFT: | |
186 | case GREATER_OR_EQUAL: | |
187 | case RIGHT_SHIFT_EQ: | |
188 | return true; | |
189 | default: | |
190 | return false; | |
191 | } | |
192 | } | |
193 | ||
194 | /* HACK-y special handling for skipping a right angle token at the end of | |
195 | * generic arguments. | |
196 | * Currently, this replaces the "current token" with one that is identical | |
197 | * except has the leading '>' removed (e.g. '>>' becomes '>'). This is bad | |
198 | * for several reasons - it modifies the token stream to something that | |
199 | * actually doesn't make syntactic sense, it may not worked if the token | |
200 | * has already been skipped, etc. It was done because it would not | |
201 | * actually require inserting new items into the token stream (which I | |
202 | * thought would take more work to not mess up) and because I wasn't sure | |
203 | * if the "already seen right angle" flag in the parser would work | |
204 | * correctly. | |
205 | * Those two other approaches listed are in my opinion actually better | |
206 | * long-term - insertion is probably best as it reflects syntactically | |
207 | * what occurs. On the other hand, I need to do a code audit to make sure | |
208 | * that insertion doesn't mess anything up. So that's a FIXME. */ | |
209 | template <typename ManagedTokenSource> | |
210 | bool | |
211 | Parser<ManagedTokenSource>::skip_generics_right_angle () | |
212 | { | |
213 | /* OK, new great idea. Have a lexer method called | |
214 | * "split_current_token(TokenType newLeft, TokenType newRight)", which is | |
215 | * called here with whatever arguments are appropriate. That lexer method | |
216 | * handles "replacing" the current token with the "newLeft" and "inserting" | |
217 | * the next token with the "newRight" (and creating a location, etc. for it) | |
218 | */ | |
219 | ||
220 | /* HACK: special handling for right shift '>>', greater or equal '>=', and | |
221 | * right shift assig */ | |
222 | // '>>=' | |
223 | const_TokenPtr tok = lexer.peek_token (); | |
224 | switch (tok->get_id ()) | |
225 | { | |
226 | case RIGHT_ANGLE: | |
227 | // this is good - skip token | |
228 | lexer.skip_token (); | |
229 | return true; | |
230 | case RIGHT_SHIFT: { | |
231 | // new implementation that should be better | |
232 | lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE); | |
233 | lexer.skip_token (); | |
234 | return true; | |
235 | } | |
236 | case GREATER_OR_EQUAL: { | |
237 | // new implementation that should be better | |
238 | lexer.split_current_token (RIGHT_ANGLE, EQUAL); | |
239 | lexer.skip_token (); | |
240 | return true; | |
241 | } | |
242 | case RIGHT_SHIFT_EQ: { | |
243 | // new implementation that should be better | |
244 | lexer.split_current_token (RIGHT_ANGLE, GREATER_OR_EQUAL); | |
245 | lexer.skip_token (); | |
246 | return true; | |
247 | } | |
248 | default: | |
249 | add_error (Error (tok->get_locus (), | |
250 | "expected %<>%> at end of generic argument - found %qs", | |
251 | tok->get_token_description ())); | |
252 | return false; | |
253 | } | |
254 | } | |
255 | ||
256 | /* Gets left binding power for specified token. | |
257 | * Not suitable for use at the moment or possibly ever because binding power | |
258 | * cannot be purely determined from operator token with Rust grammar - e.g. | |
259 | * method call and field access have | |
260 | * different left binding powers but the same operator token. */ | |
261 | template <typename ManagedTokenSource> | |
262 | int | |
263 | Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token) | |
264 | { | |
265 | // HACK: called with "peek_token()", so lookahead is "peek_token(1)" | |
266 | switch (token->get_id ()) | |
267 | { | |
268 | /* TODO: issue here - distinguish between method calls and field access | |
269 | * somehow? Also would have to distinguish between paths and function | |
270 | * calls (:: operator), maybe more stuff. */ | |
271 | /* Current plan for tackling LBP - don't do it based on token, use | |
272 | * lookahead. Or alternatively, only use Pratt parsing for OperatorExpr | |
273 | * and handle other expressions without it. rustc only considers | |
274 | * arithmetic, logical/relational, 'as', | |
275 | * '?=', ranges, colons, and assignment to have operator precedence and | |
276 | * associativity rules applicable. It then has | |
277 | * a separate "ExprPrecedence" that also includes binary operators. */ | |
278 | ||
279 | // TODO: handle operator overloading - have a function replace the | |
280 | // operator? | |
281 | ||
282 | /*case DOT: | |
283 | return LBP_DOT;*/ | |
284 | ||
285 | case SCOPE_RESOLUTION: | |
286 | rust_debug ( | |
287 | "possible error - looked up LBP of scope resolution operator. should " | |
288 | "be handled elsewhere."); | |
289 | return LBP_PATH; | |
290 | ||
291 | /* Resolved by lookahead HACK that should work with current code. If next | |
292 | * token is identifier and token after that isn't parenthesised expression | |
293 | * list, it is a field reference. */ | |
294 | case DOT: | |
295 | if (lexer.peek_token (1)->get_id () == IDENTIFIER | |
296 | && lexer.peek_token (2)->get_id () != LEFT_PAREN) | |
297 | { | |
298 | return LBP_FIELD_EXPR; | |
299 | } | |
300 | return LBP_METHOD_CALL; | |
301 | ||
302 | case LEFT_PAREN: | |
303 | return LBP_FUNCTION_CALL; | |
304 | ||
305 | case LEFT_SQUARE: | |
306 | return LBP_ARRAY_REF; | |
307 | ||
308 | // postfix question mark (i.e. error propagation expression) | |
309 | case QUESTION_MARK: | |
310 | return LBP_QUESTION_MARK; | |
311 | ||
312 | case AS: | |
313 | return LBP_AS; | |
314 | ||
315 | case ASTERISK: | |
316 | return LBP_MUL; | |
317 | case DIV: | |
318 | return LBP_DIV; | |
319 | case PERCENT: | |
320 | return LBP_MOD; | |
321 | ||
322 | case PLUS: | |
323 | return LBP_PLUS; | |
324 | case MINUS: | |
325 | return LBP_MINUS; | |
326 | ||
327 | case LEFT_SHIFT: | |
328 | return LBP_L_SHIFT; | |
329 | case RIGHT_SHIFT: | |
330 | return LBP_R_SHIFT; | |
331 | ||
332 | // binary & operator | |
333 | case AMP: | |
334 | return LBP_AMP; | |
335 | ||
336 | // binary ^ operator | |
337 | case CARET: | |
338 | return LBP_CARET; | |
339 | ||
340 | // binary | operator | |
341 | case PIPE: | |
342 | return LBP_PIPE; | |
343 | ||
344 | case EQUAL_EQUAL: | |
345 | return LBP_EQUAL; | |
346 | case NOT_EQUAL: | |
347 | return LBP_NOT_EQUAL; | |
348 | case RIGHT_ANGLE: | |
349 | return LBP_GREATER_THAN; | |
350 | case GREATER_OR_EQUAL: | |
351 | return LBP_GREATER_EQUAL; | |
352 | case LEFT_ANGLE: | |
353 | return LBP_SMALLER_THAN; | |
354 | case LESS_OR_EQUAL: | |
355 | return LBP_SMALLER_EQUAL; | |
356 | ||
357 | case LOGICAL_AND: | |
358 | return LBP_LOGICAL_AND; | |
359 | ||
360 | case OR: | |
361 | return LBP_LOGICAL_OR; | |
362 | ||
363 | case DOT_DOT: | |
364 | return LBP_DOT_DOT; | |
365 | ||
366 | case DOT_DOT_EQ: | |
367 | return LBP_DOT_DOT_EQ; | |
368 | ||
369 | case EQUAL: | |
370 | return LBP_ASSIG; | |
371 | case PLUS_EQ: | |
372 | return LBP_PLUS_ASSIG; | |
373 | case MINUS_EQ: | |
374 | return LBP_MINUS_ASSIG; | |
375 | case ASTERISK_EQ: | |
376 | return LBP_MULT_ASSIG; | |
377 | case DIV_EQ: | |
378 | return LBP_DIV_ASSIG; | |
379 | case PERCENT_EQ: | |
380 | return LBP_MOD_ASSIG; | |
381 | case AMP_EQ: | |
382 | return LBP_AMP_ASSIG; | |
383 | case PIPE_EQ: | |
384 | return LBP_PIPE_ASSIG; | |
385 | case CARET_EQ: | |
386 | return LBP_CARET_ASSIG; | |
387 | case LEFT_SHIFT_EQ: | |
388 | return LBP_L_SHIFT_ASSIG; | |
389 | case RIGHT_SHIFT_EQ: | |
390 | return LBP_R_SHIFT_ASSIG; | |
391 | ||
392 | /* HACK: float literal due to lexer misidentifying a dot then an integer as | |
393 | * a float */ | |
394 | case FLOAT_LITERAL: | |
395 | return LBP_FIELD_EXPR; | |
396 | // field expr is same as tuple expr in precedence, i imagine | |
397 | // TODO: is this needed anymore? lexer shouldn't do that anymore | |
398 | ||
399 | // anything that can't appear in an infix position is given lowest priority | |
400 | default: | |
401 | return LBP_LOWEST; | |
402 | } | |
403 | } | |
404 | ||
405 | // Returns true when current token is EOF. | |
406 | template <typename ManagedTokenSource> | |
407 | bool | |
408 | Parser<ManagedTokenSource>::done_end_of_file () | |
409 | { | |
410 | return lexer.peek_token ()->get_id () == END_OF_FILE; | |
411 | } | |
412 | ||
413 | // Parses a sequence of items within a module or the implicit top-level module | |
414 | // in a crate | |
415 | template <typename ManagedTokenSource> | |
416 | std::vector<std::unique_ptr<AST::Item>> | |
417 | Parser<ManagedTokenSource>::parse_items () | |
418 | { | |
419 | std::vector<std::unique_ptr<AST::Item>> items; | |
420 | ||
421 | const_TokenPtr t = lexer.peek_token (); | |
422 | while (t->get_id () != END_OF_FILE) | |
423 | { | |
424 | std::unique_ptr<AST::Item> item = parse_item (false); | |
425 | if (item == nullptr) | |
426 | { | |
427 | Error error (lexer.peek_token ()->get_locus (), | |
428 | "failed to parse item in crate"); | |
429 | add_error (std::move (error)); | |
430 | ||
431 | // TODO: should all items be cleared? | |
432 | items = std::vector<std::unique_ptr<AST::Item>> (); | |
433 | break; | |
434 | } | |
435 | ||
436 | items.push_back (std::move (item)); | |
437 | ||
438 | t = lexer.peek_token (); | |
439 | } | |
440 | ||
441 | return items; | |
442 | } | |
443 | ||
444 | // Parses a crate (compilation unit) - entry point | |
445 | template <typename ManagedTokenSource> | |
446 | std::unique_ptr<AST::Crate> | |
447 | Parser<ManagedTokenSource>::parse_crate () | |
448 | { | |
449 | // parse inner attributes | |
450 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
451 | ||
452 | // parse items | |
453 | std::vector<std::unique_ptr<AST::Item>> items = parse_items (); | |
454 | ||
455 | // emit all errors | |
456 | for (const auto &error : error_table) | |
457 | error.emit (); | |
458 | ||
459 | return std::unique_ptr<AST::Crate> ( | |
460 | new AST::Crate (std::move (items), std::move (inner_attrs))); | |
461 | } | |
462 | ||
463 | // Parse a contiguous block of inner attributes. | |
464 | template <typename ManagedTokenSource> | |
465 | AST::AttrVec | |
466 | Parser<ManagedTokenSource>::parse_inner_attributes () | |
467 | { | |
468 | AST::AttrVec inner_attributes; | |
469 | ||
470 | // only try to parse it if it starts with "#!" not only "#" | |
471 | while ((lexer.peek_token ()->get_id () == HASH | |
472 | && lexer.peek_token (1)->get_id () == EXCLAM) | |
473 | || lexer.peek_token ()->get_id () == INNER_DOC_COMMENT) | |
474 | { | |
475 | AST::Attribute inner_attr = parse_inner_attribute (); | |
476 | ||
477 | /* Ensure only valid inner attributes are added to the inner_attributes | |
478 | * list */ | |
479 | if (!inner_attr.is_empty ()) | |
480 | { | |
481 | inner_attributes.push_back (std::move (inner_attr)); | |
482 | } | |
483 | else | |
484 | { | |
485 | /* If no more valid inner attributes, break out of loop (only | |
486 | * contiguous inner attributes parsed). */ | |
487 | break; | |
488 | } | |
489 | } | |
490 | ||
491 | inner_attributes.shrink_to_fit (); | |
492 | return inner_attributes; | |
493 | } | |
494 | ||
495 | // Parse a inner or outer doc comment into an doc attribute | |
496 | template <typename ManagedTokenSource> | |
497 | std::tuple<AST::SimplePath, std::unique_ptr<AST::AttrInput>, location_t> | |
498 | Parser<ManagedTokenSource>::parse_doc_comment () | |
499 | { | |
500 | const_TokenPtr token = lexer.peek_token (); | |
501 | location_t locus = token->get_locus (); | |
502 | AST::SimplePathSegment segment (Values::Attributes::DOC, locus); | |
503 | std::vector<AST::SimplePathSegment> segments; | |
504 | segments.push_back (std::move (segment)); | |
505 | AST::SimplePath attr_path (std::move (segments), false, locus); | |
506 | AST::LiteralExpr lit_expr (token->get_str (), AST::Literal::STRING, | |
507 | PrimitiveCoreType::CORETYPE_STR, {}, locus); | |
508 | std::unique_ptr<AST::AttrInput> attr_input ( | |
509 | new AST::AttrInputLiteral (std::move (lit_expr))); | |
510 | lexer.skip_token (); | |
511 | return std::make_tuple (std::move (attr_path), std::move (attr_input), locus); | |
512 | } | |
513 | ||
514 | // Parse a single inner attribute. | |
515 | template <typename ManagedTokenSource> | |
516 | AST::Attribute | |
517 | Parser<ManagedTokenSource>::parse_inner_attribute () | |
518 | { | |
519 | if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT) | |
520 | { | |
521 | auto values = parse_doc_comment (); | |
522 | auto path = std::move (std::get<0> (values)); | |
523 | auto input = std::move (std::get<1> (values)); | |
524 | auto loc = std::get<2> (values); | |
525 | return AST::Attribute (std::move (path), std::move (input), loc, true); | |
526 | } | |
527 | ||
528 | if (lexer.peek_token ()->get_id () != HASH) | |
529 | { | |
530 | Error error (lexer.peek_token ()->get_locus (), | |
531 | "BUG: token %<#%> is missing, but %<parse_inner_attribute%> " | |
532 | "was invoked"); | |
533 | add_error (std::move (error)); | |
534 | ||
535 | return AST::Attribute::create_empty (); | |
536 | } | |
537 | lexer.skip_token (); | |
538 | ||
539 | if (lexer.peek_token ()->get_id () != EXCLAM) | |
540 | { | |
541 | Error error (lexer.peek_token ()->get_locus (), | |
542 | "expected %<!%> or %<[%> for inner attribute"); | |
543 | add_error (std::move (error)); | |
544 | ||
545 | return AST::Attribute::create_empty (); | |
546 | } | |
547 | lexer.skip_token (); | |
548 | ||
549 | if (!skip_token (LEFT_SQUARE)) | |
550 | return AST::Attribute::create_empty (); | |
551 | ||
552 | auto values = parse_attribute_body (); | |
553 | ||
554 | auto path = std::move (std::get<0> (values)); | |
555 | auto input = std::move (std::get<1> (values)); | |
556 | auto loc = std::get<2> (values); | |
557 | auto actual_attribute | |
558 | = AST::Attribute (std::move (path), std::move (input), loc, true); | |
559 | ||
560 | if (!skip_token (RIGHT_SQUARE)) | |
561 | return AST::Attribute::create_empty (); | |
562 | ||
563 | return actual_attribute; | |
564 | } | |
565 | ||
566 | // Parses the body of an attribute (inner or outer). | |
567 | template <typename ManagedTokenSource> | |
568 | std::tuple<AST::SimplePath, std::unique_ptr<AST::AttrInput>, location_t> | |
569 | Parser<ManagedTokenSource>::parse_attribute_body () | |
570 | { | |
571 | location_t locus = lexer.peek_token ()->get_locus (); | |
572 | ||
573 | AST::SimplePath attr_path = parse_simple_path (); | |
574 | // ensure path is valid to parse attribute input | |
575 | if (attr_path.is_empty ()) | |
576 | { | |
577 | Error error (lexer.peek_token ()->get_locus (), | |
578 | "empty simple path in attribute"); | |
579 | add_error (std::move (error)); | |
580 | ||
581 | // Skip past potential further info in attribute (i.e. attr_input) | |
582 | skip_after_end_attribute (); | |
583 | return std::make_tuple (std::move (attr_path), nullptr, UNDEF_LOCATION); | |
584 | } | |
585 | ||
586 | std::unique_ptr<AST::AttrInput> attr_input = parse_attr_input (); | |
587 | // AttrInput is allowed to be null, so no checks here | |
588 | ||
589 | return std::make_tuple (std::move (attr_path), std::move (attr_input), locus); | |
590 | } | |
591 | ||
592 | /* Determines whether token is a valid simple path segment. This does not | |
593 | * include scope resolution operators. */ | |
594 | inline bool | |
595 | is_simple_path_segment (TokenId id) | |
596 | { | |
597 | switch (id) | |
598 | { | |
599 | case IDENTIFIER: | |
600 | case SUPER: | |
601 | case SELF: | |
602 | case CRATE: | |
603 | return true; | |
604 | case DOLLAR_SIGN: | |
605 | // assume that dollar sign leads to $crate | |
606 | return true; | |
607 | default: | |
608 | return false; | |
609 | } | |
610 | } | |
611 | ||
612 | // Parses a SimplePath AST node, if it exists. Does nothing otherwise. | |
613 | template <typename ManagedTokenSource> | |
614 | AST::SimplePath | |
615 | Parser<ManagedTokenSource>::parse_simple_path () | |
616 | { | |
617 | bool has_opening_scope_resolution = false; | |
618 | location_t locus = UNKNOWN_LOCATION; | |
619 | ||
620 | // don't parse anything if not a path upfront | |
621 | if (!is_simple_path_segment (lexer.peek_token ()->get_id ()) | |
622 | && !is_simple_path_segment (lexer.peek_token (1)->get_id ())) | |
623 | return AST::SimplePath::create_empty (); | |
624 | ||
625 | /* Checks for opening scope resolution (i.e. global scope fully-qualified | |
626 | * path) */ | |
627 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION) | |
628 | { | |
629 | has_opening_scope_resolution = true; | |
630 | ||
631 | locus = lexer.peek_token ()->get_locus (); | |
632 | ||
633 | lexer.skip_token (); | |
634 | } | |
635 | ||
636 | // Parse single required simple path segment | |
637 | AST::SimplePathSegment segment = parse_simple_path_segment (); | |
638 | ||
639 | // get location if not gotten already | |
640 | if (locus == UNKNOWN_LOCATION) | |
641 | locus = segment.get_locus (); | |
642 | ||
643 | std::vector<AST::SimplePathSegment> segments; | |
644 | ||
645 | // Return empty vector if first, actually required segment is an error | |
646 | if (segment.is_error ()) | |
647 | return AST::SimplePath::create_empty (); | |
648 | ||
649 | segments.push_back (std::move (segment)); | |
650 | ||
651 | // Parse all other simple path segments | |
652 | while (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION) | |
653 | { | |
654 | // Skip scope resolution operator | |
655 | lexer.skip_token (); | |
656 | ||
657 | AST::SimplePathSegment new_segment = parse_simple_path_segment (); | |
658 | ||
659 | // Return path as currently constructed if segment in error state. | |
660 | if (new_segment.is_error ()) | |
661 | break; | |
662 | ||
663 | segments.push_back (std::move (new_segment)); | |
664 | } | |
665 | ||
666 | // DEBUG: check for any empty segments | |
667 | for (const auto &seg : segments) | |
668 | { | |
669 | if (seg.is_error ()) | |
670 | { | |
671 | rust_debug ( | |
672 | "when parsing simple path, somehow empty path segment was " | |
673 | "not filtered out. Path begins with '%s'", | |
674 | segments.at (0).as_string ().c_str ()); | |
675 | } | |
676 | } | |
677 | ||
678 | return AST::SimplePath (std::move (segments), has_opening_scope_resolution, | |
679 | locus); | |
680 | /* TODO: now that is_simple_path_segment exists, could probably start | |
681 | * actually making errors upon parse failure of segments and whatever */ | |
682 | } | |
683 | ||
684 | /* Parses a single SimplePathSegment (does not handle the scope resolution | |
685 | * operators) */ | |
686 | template <typename ManagedTokenSource> | |
687 | AST::SimplePathSegment | |
688 | Parser<ManagedTokenSource>::parse_simple_path_segment () | |
689 | { | |
690 | using namespace Values; | |
691 | const_TokenPtr t = lexer.peek_token (); | |
692 | switch (t->get_id ()) | |
693 | { | |
694 | case IDENTIFIER: | |
695 | lexer.skip_token (); | |
696 | ||
697 | return AST::SimplePathSegment (t->get_str (), t->get_locus ()); | |
698 | case SUPER: | |
699 | lexer.skip_token (); | |
700 | ||
701 | return AST::SimplePathSegment (Keywords::SUPER, t->get_locus ()); | |
702 | case SELF: | |
703 | lexer.skip_token (); | |
704 | ||
705 | return AST::SimplePathSegment (Keywords::SELF, t->get_locus ()); | |
706 | case CRATE: | |
707 | lexer.skip_token (); | |
708 | ||
709 | return AST::SimplePathSegment (Keywords::CRATE, t->get_locus ()); | |
710 | case DOLLAR_SIGN: | |
711 | if (lexer.peek_token (1)->get_id () == CRATE) | |
712 | { | |
713 | lexer.skip_token (1); | |
714 | ||
715 | return AST::SimplePathSegment ("$crate", t->get_locus ()); | |
716 | } | |
717 | gcc_fallthrough (); | |
718 | default: | |
719 | // do nothing but inactivates warning from gcc when compiling | |
720 | /* could put the rust_error_at thing here but fallthrough (from failing | |
721 | * $crate condition) isn't completely obvious if it is. */ | |
722 | ||
723 | // test prevent error | |
724 | return AST::SimplePathSegment::create_error (); | |
725 | } | |
726 | rust_unreachable (); | |
727 | /*rust_error_at( | |
728 | t->get_locus(), "invalid token '%s' in simple path segment", | |
729 | t->get_token_description());*/ | |
730 | // this is not necessarily an error, e.g. end of path | |
731 | // return AST::SimplePathSegment::create_error(); | |
732 | } | |
733 | ||
734 | // Parses a PathIdentSegment - an identifier segment of a non-SimplePath path. | |
735 | template <typename ManagedTokenSource> | |
736 | AST::PathIdentSegment | |
737 | Parser<ManagedTokenSource>::parse_path_ident_segment () | |
738 | { | |
739 | const_TokenPtr t = lexer.peek_token (); | |
740 | switch (t->get_id ()) | |
741 | { | |
742 | case IDENTIFIER: | |
743 | lexer.skip_token (); | |
744 | ||
745 | return AST::PathIdentSegment (t->get_str (), t->get_locus ()); | |
746 | case SUPER: | |
747 | lexer.skip_token (); | |
748 | ||
749 | return AST::PathIdentSegment (Values::Keywords::SUPER, t->get_locus ()); | |
750 | case SELF: | |
751 | lexer.skip_token (); | |
752 | ||
753 | return AST::PathIdentSegment (Values::Keywords::SELF, t->get_locus ()); | |
754 | case SELF_ALIAS: | |
755 | lexer.skip_token (); | |
756 | ||
757 | return AST::PathIdentSegment (Values::Keywords::SELF_ALIAS, | |
758 | t->get_locus ()); | |
759 | case CRATE: | |
760 | lexer.skip_token (); | |
761 | ||
762 | return AST::PathIdentSegment (Values::Keywords::CRATE, t->get_locus ()); | |
763 | case DOLLAR_SIGN: | |
764 | if (lexer.peek_token (1)->get_id () == CRATE) | |
765 | { | |
766 | lexer.skip_token (1); | |
767 | ||
768 | return AST::PathIdentSegment ("$crate", t->get_locus ()); | |
769 | } | |
770 | gcc_fallthrough (); | |
771 | default: | |
772 | /* do nothing but inactivates warning from gcc when compiling | |
773 | * could put the error_at thing here but fallthrough (from failing $crate | |
774 | * condition) isn't completely obvious if it is. */ | |
775 | ||
776 | // test prevent error | |
777 | return AST::PathIdentSegment::create_error (); | |
778 | } | |
779 | rust_unreachable (); | |
780 | // not necessarily an error | |
781 | } | |
782 | ||
783 | // Parses an AttrInput AST node (polymorphic, as AttrInput is abstract) | |
784 | template <typename ManagedTokenSource> | |
785 | std::unique_ptr<AST::AttrInput> | |
786 | Parser<ManagedTokenSource>::parse_attr_input () | |
787 | { | |
788 | const_TokenPtr t = lexer.peek_token (); | |
789 | switch (t->get_id ()) | |
790 | { | |
791 | case LEFT_PAREN: | |
792 | case LEFT_SQUARE: | |
793 | case LEFT_CURLY: { | |
794 | // must be a delimited token tree, so parse that | |
795 | std::unique_ptr<AST::AttrInput> input_tree ( | |
796 | new AST::DelimTokenTree (parse_delim_token_tree ())); | |
797 | ||
798 | // TODO: potential checks on DelimTokenTree before returning | |
799 | ||
800 | return input_tree; | |
801 | } | |
802 | case EQUAL: { | |
803 | // = LiteralExpr | |
804 | lexer.skip_token (); | |
805 | ||
806 | t = lexer.peek_token (); | |
807 | ||
808 | // attempt to parse macro | |
809 | // TODO: macros may/may not be allowed in attributes | |
810 | // this is needed for "#[doc = include_str!(...)]" | |
811 | if (is_simple_path_segment (t->get_id ())) | |
812 | { | |
813 | std::unique_ptr<AST::MacroInvocation> invoke | |
814 | = parse_macro_invocation ({}); | |
815 | ||
816 | if (!invoke) | |
817 | return nullptr; | |
818 | ||
819 | return std::unique_ptr<AST::AttrInput> ( | |
820 | new AST::AttrInputMacro (std::move (invoke))); | |
821 | } | |
822 | ||
823 | /* Ensure token is a "literal expression" (literally only a literal | |
824 | * token of any type) */ | |
825 | if (!t->is_literal ()) | |
826 | { | |
827 | Error error ( | |
828 | t->get_locus (), | |
829 | "unknown token %qs in attribute body - literal expected", | |
830 | t->get_token_description ()); | |
831 | add_error (std::move (error)); | |
832 | ||
833 | skip_after_end_attribute (); | |
834 | return nullptr; | |
835 | } | |
836 | ||
837 | AST::Literal::LitType lit_type = AST::Literal::STRING; | |
838 | // Crappy mapping of token type to literal type | |
839 | switch (t->get_id ()) | |
840 | { | |
841 | case INT_LITERAL: | |
842 | lit_type = AST::Literal::INT; | |
843 | break; | |
844 | case FLOAT_LITERAL: | |
845 | lit_type = AST::Literal::FLOAT; | |
846 | break; | |
847 | case CHAR_LITERAL: | |
848 | lit_type = AST::Literal::CHAR; | |
849 | break; | |
850 | case BYTE_CHAR_LITERAL: | |
851 | lit_type = AST::Literal::BYTE; | |
852 | break; | |
853 | case BYTE_STRING_LITERAL: | |
854 | lit_type = AST::Literal::BYTE_STRING; | |
855 | break; | |
856 | case RAW_STRING_LITERAL: | |
857 | lit_type = AST::Literal::RAW_STRING; | |
858 | break; | |
859 | case STRING_LITERAL: | |
860 | default: | |
861 | lit_type = AST::Literal::STRING; | |
862 | break; // TODO: raw string? don't eliminate it from lexer? | |
863 | } | |
864 | ||
865 | // create actual LiteralExpr | |
866 | AST::LiteralExpr lit_expr (t->get_str (), lit_type, t->get_type_hint (), | |
867 | {}, t->get_locus ()); | |
868 | lexer.skip_token (); | |
869 | ||
870 | std::unique_ptr<AST::AttrInput> attr_input_lit ( | |
871 | new AST::AttrInputLiteral (std::move (lit_expr))); | |
872 | ||
873 | // do checks or whatever? none required, really | |
874 | ||
875 | // FIXME: shouldn't a skip token be required here? | |
876 | ||
877 | return attr_input_lit; | |
878 | } | |
879 | break; | |
880 | case RIGHT_SQUARE: | |
881 | // means AttrInput is missing, which is allowed | |
882 | return nullptr; | |
883 | default: | |
884 | add_error ( | |
885 | Error (t->get_locus (), | |
886 | "unknown token %qs in attribute body - attribute input or " | |
887 | "none expected", | |
888 | t->get_token_description ())); | |
889 | ||
890 | skip_after_end_attribute (); | |
891 | return nullptr; | |
892 | } | |
893 | rust_unreachable (); | |
894 | // TODO: find out how to stop gcc error on "no return value" | |
895 | } | |
896 | ||
897 | /* Returns true if the token id matches the delimiter type. Note that this only | |
898 | * operates for END delimiter tokens. */ | |
899 | inline bool | |
900 | token_id_matches_delims (TokenId token_id, AST::DelimType delim_type) | |
901 | { | |
902 | return ((token_id == RIGHT_PAREN && delim_type == AST::PARENS) | |
903 | || (token_id == RIGHT_SQUARE && delim_type == AST::SQUARE) | |
904 | || (token_id == RIGHT_CURLY && delim_type == AST::CURLY)); | |
905 | } | |
906 | ||
907 | /* Returns true if the likely result of parsing the next few tokens is a path. | |
908 | * Not guaranteed, though, especially in the case of syntax errors. */ | |
909 | inline bool | |
910 | is_likely_path_next (TokenId next_token_id) | |
911 | { | |
912 | switch (next_token_id) | |
913 | { | |
914 | case IDENTIFIER: | |
915 | case SUPER: | |
916 | case SELF: | |
917 | case SELF_ALIAS: | |
918 | case CRATE: | |
919 | // maybe - maybe do extra check. But then requires another TokenId. | |
920 | case DOLLAR_SIGN: | |
921 | case SCOPE_RESOLUTION: | |
922 | return true; | |
923 | default: | |
924 | return false; | |
925 | } | |
926 | } | |
927 | ||
928 | // Parses a delimited token tree | |
929 | template <typename ManagedTokenSource> | |
930 | AST::DelimTokenTree | |
931 | Parser<ManagedTokenSource>::parse_delim_token_tree () | |
932 | { | |
933 | const_TokenPtr t = lexer.peek_token (); | |
934 | lexer.skip_token (); | |
935 | location_t initial_loc = t->get_locus (); | |
936 | ||
937 | // save delim type to ensure it is reused later | |
938 | AST::DelimType delim_type = AST::PARENS; | |
939 | ||
940 | // Map tokens to DelimType | |
941 | switch (t->get_id ()) | |
942 | { | |
943 | case LEFT_PAREN: | |
944 | delim_type = AST::PARENS; | |
945 | break; | |
946 | case LEFT_SQUARE: | |
947 | delim_type = AST::SQUARE; | |
948 | break; | |
949 | case LEFT_CURLY: | |
950 | delim_type = AST::CURLY; | |
951 | break; | |
952 | default: | |
953 | add_error (Error (t->get_locus (), | |
954 | "unexpected token %qs - expecting delimiters (for a " | |
955 | "delimited token tree)", | |
956 | t->get_token_description ())); | |
957 | ||
958 | return AST::DelimTokenTree::create_empty (); | |
959 | } | |
960 | ||
961 | // parse actual token tree vector - 0 or more | |
962 | std::vector<std::unique_ptr<AST::TokenTree>> token_trees_in_tree; | |
963 | auto delim_open | |
964 | = std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
965 | token_trees_in_tree.push_back (std::move (delim_open)); | |
966 | ||
967 | // repeat loop until finding the matching delimiter | |
968 | t = lexer.peek_token (); | |
969 | while (!token_id_matches_delims (t->get_id (), delim_type) | |
970 | && t->get_id () != END_OF_FILE) | |
971 | { | |
972 | std::unique_ptr<AST::TokenTree> tok_tree = parse_token_tree (); | |
973 | ||
974 | if (tok_tree == nullptr) | |
975 | { | |
976 | // TODO: is this error handling appropriate? | |
977 | Error error ( | |
978 | t->get_locus (), | |
979 | "failed to parse token tree in delimited token tree - found %qs", | |
980 | t->get_token_description ()); | |
981 | add_error (std::move (error)); | |
982 | ||
983 | return AST::DelimTokenTree::create_empty (); | |
984 | } | |
985 | ||
986 | token_trees_in_tree.push_back (std::move (tok_tree)); | |
987 | ||
988 | // lexer.skip_token(); | |
989 | t = lexer.peek_token (); | |
990 | } | |
991 | auto delim_close | |
992 | = std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
993 | token_trees_in_tree.push_back (std::move (delim_close)); | |
994 | ||
995 | AST::DelimTokenTree token_tree (delim_type, std::move (token_trees_in_tree), | |
996 | initial_loc); | |
997 | ||
998 | // parse end delimiters | |
999 | t = lexer.peek_token (); | |
1000 | ||
1001 | if (token_id_matches_delims (t->get_id (), delim_type)) | |
1002 | { | |
1003 | // tokens match opening delimiter, so skip. | |
1004 | lexer.skip_token (); | |
1005 | ||
1006 | // DEBUG | |
1007 | rust_debug ("finished parsing new delim token tree - peeked token is now " | |
1008 | "'%s' while t is '%s'", | |
1009 | lexer.peek_token ()->get_token_description (), | |
1010 | t->get_token_description ()); | |
1011 | ||
1012 | return token_tree; | |
1013 | } | |
1014 | else | |
1015 | { | |
1016 | // tokens don't match opening delimiters, so produce error | |
1017 | Error error (t->get_locus (), | |
1018 | "unexpected token %qs - expecting closing delimiter %qs " | |
1019 | "(for a delimited token tree)", | |
1020 | t->get_token_description (), | |
1021 | (delim_type == AST::PARENS | |
1022 | ? ")" | |
1023 | : (delim_type == AST::SQUARE ? "]" : "}"))); | |
1024 | add_error (std::move (error)); | |
1025 | ||
1026 | /* return empty token tree despite possibly parsing valid token tree - | |
1027 | * TODO is this a good idea? */ | |
1028 | return AST::DelimTokenTree::create_empty (); | |
1029 | } | |
1030 | } | |
1031 | ||
1032 | // Parses an identifier/keyword as a Token | |
1033 | template <typename ManagedTokenSource> | |
1034 | std::unique_ptr<AST::Token> | |
1035 | Parser<ManagedTokenSource>::parse_identifier_or_keyword_token () | |
1036 | { | |
1037 | const_TokenPtr t = lexer.peek_token (); | |
1038 | ||
1039 | if (t->get_id () == IDENTIFIER || token_id_is_keyword (t->get_id ())) | |
1040 | { | |
1041 | lexer.skip_token (); | |
1042 | return std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
1043 | } | |
1044 | else | |
1045 | { | |
1046 | return nullptr; | |
1047 | } | |
1048 | } | |
1049 | ||
1050 | /* Parses a TokenTree syntactical production. This is either a delimited token | |
1051 | * tree or a non-delimiter token. */ | |
1052 | template <typename ManagedTokenSource> | |
1053 | std::unique_ptr<AST::TokenTree> | |
1054 | Parser<ManagedTokenSource>::parse_token_tree () | |
1055 | { | |
1056 | const_TokenPtr t = lexer.peek_token (); | |
1057 | ||
1058 | switch (t->get_id ()) | |
1059 | { | |
1060 | case LEFT_PAREN: | |
1061 | case LEFT_SQUARE: | |
1062 | case LEFT_CURLY: | |
1063 | // Parse delimited token tree | |
1064 | // TODO: use move rather than copy constructor | |
1065 | return std::unique_ptr<AST::DelimTokenTree> ( | |
1066 | new AST::DelimTokenTree (parse_delim_token_tree ())); | |
1067 | case RIGHT_PAREN: | |
1068 | case RIGHT_SQUARE: | |
1069 | case RIGHT_CURLY: | |
1070 | // error - should not be called when this a token | |
1071 | add_error ( | |
1072 | Error (t->get_locus (), | |
1073 | "unexpected closing delimiter %qs - token tree requires " | |
1074 | "either paired delimiters or non-delimiter tokens", | |
1075 | t->get_token_description ())); | |
1076 | ||
1077 | lexer.skip_token (); | |
1078 | return nullptr; | |
1079 | default: | |
1080 | // parse token itself as TokenTree | |
1081 | lexer.skip_token (); | |
1082 | return std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
1083 | } | |
1084 | } | |
1085 | ||
1086 | template <typename ManagedTokenSource> | |
1087 | bool | |
1088 | Parser<ManagedTokenSource>::is_macro_rules_def (const_TokenPtr t) | |
1089 | { | |
1090 | auto macro_name = lexer.peek_token (2)->get_id (); | |
1091 | ||
1092 | bool allowed_macro_name = (macro_name == IDENTIFIER || macro_name == TRY); | |
1093 | ||
1094 | return t->get_str () == Values::WeakKeywords::MACRO_RULES | |
1095 | && lexer.peek_token (1)->get_id () == EXCLAM && allowed_macro_name; | |
1096 | } | |
1097 | ||
1098 | // Parses a single item | |
1099 | template <typename ManagedTokenSource> | |
1100 | std::unique_ptr<AST::Item> | |
1101 | Parser<ManagedTokenSource>::parse_item (bool called_from_statement) | |
1102 | { | |
1103 | // has a "called_from_statement" parameter for better error message handling | |
1104 | ||
1105 | // parse outer attributes for item | |
1106 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
1107 | const_TokenPtr t = lexer.peek_token (); | |
1108 | ||
1109 | switch (t->get_id ()) | |
1110 | { | |
1111 | case END_OF_FILE: | |
1112 | // not necessarily an error, unless we just read outer | |
1113 | // attributes which needs to be attached | |
1114 | if (!outer_attrs.empty ()) | |
1115 | { | |
1116 | Rust::AST::Attribute attr = outer_attrs.back (); | |
1117 | Error error (attr.get_locus (), | |
1118 | "expected item after outer attribute or doc comment"); | |
1119 | add_error (std::move (error)); | |
1120 | } | |
1121 | return nullptr; | |
1122 | ||
1123 | case ASYNC: | |
1124 | case PUB: | |
1125 | case MOD: | |
1126 | case EXTERN_KW: | |
1127 | case USE: | |
1128 | case FN_KW: | |
1129 | case TYPE: | |
1130 | case STRUCT_KW: | |
1131 | case ENUM_KW: | |
1132 | case CONST: | |
1133 | case STATIC_KW: | |
1134 | case AUTO: | |
1135 | case TRAIT: | |
1136 | case IMPL: | |
1137 | case MACRO: | |
1138 | /* TODO: implement union keyword but not really because of | |
1139 | * context-dependence crappy hack way to parse a union written below to | |
1140 | * separate it from the good code. */ | |
1141 | // case UNION: | |
1142 | case UNSAFE: // maybe - unsafe traits are a thing | |
1143 | // if any of these (should be all possible VisItem prefixes), parse a | |
1144 | // VisItem | |
1145 | return parse_vis_item (std::move (outer_attrs)); | |
1146 | break; | |
1147 | case SUPER: | |
1148 | case SELF: | |
1149 | case CRATE: | |
1150 | case DOLLAR_SIGN: | |
1151 | // almost certainly macro invocation semi | |
1152 | return parse_macro_invocation_semi (std::move (outer_attrs)); | |
1153 | break; | |
1154 | // crappy hack to do union "keyword" | |
1155 | case IDENTIFIER: | |
1156 | // TODO: ensure std::string and literal comparison works | |
1157 | if (t->get_str () == Values::WeakKeywords::UNION | |
1158 | && lexer.peek_token (1)->get_id () == IDENTIFIER) | |
1159 | { | |
1160 | return parse_vis_item (std::move (outer_attrs)); | |
1161 | // or should this go straight to parsing union? | |
1162 | } | |
1163 | else if (t->get_str () == Values::WeakKeywords::DEFAULT | |
1164 | && lexer.peek_token (1)->get_id () != EXCLAM) | |
1165 | { | |
1166 | add_error (Error (t->get_locus (), | |
1167 | "%qs is only allowed on items within %qs blocks", | |
1168 | "default", "impl")); | |
1169 | return nullptr; | |
1170 | } | |
1171 | else if (is_macro_rules_def (t)) | |
1172 | { | |
1173 | // macro_rules! macro item | |
1174 | return parse_macro_rules_def (std::move (outer_attrs)); | |
1175 | } | |
1176 | else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION | |
1177 | || lexer.peek_token (1)->get_id () == EXCLAM) | |
1178 | { | |
1179 | /* path (probably) or macro invocation, so probably a macro invocation | |
1180 | * semi */ | |
1181 | return parse_macro_invocation_semi (std::move (outer_attrs)); | |
1182 | } | |
1183 | gcc_fallthrough (); | |
1184 | default: | |
1185 | // otherwise unrecognised | |
1186 | add_error (Error (t->get_locus (), | |
1187 | "unrecognised token %qs for start of %s", | |
1188 | t->get_token_description (), | |
1189 | called_from_statement ? "statement" : "item")); | |
1190 | ||
1191 | // skip somewhere? | |
1192 | return nullptr; | |
1193 | break; | |
1194 | } | |
1195 | } | |
1196 | ||
1197 | // Parses a contiguous block of outer attributes. | |
1198 | template <typename ManagedTokenSource> | |
1199 | AST::AttrVec | |
1200 | Parser<ManagedTokenSource>::parse_outer_attributes () | |
1201 | { | |
1202 | AST::AttrVec outer_attributes; | |
1203 | ||
1204 | while (lexer.peek_token ()->get_id () | |
1205 | == HASH /* Can also be #!, which catches errors. */ | |
1206 | || lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT | |
1207 | || lexer.peek_token ()->get_id () | |
1208 | == INNER_DOC_COMMENT) /* For error handling. */ | |
1209 | { | |
1210 | AST::Attribute outer_attr = parse_outer_attribute (); | |
1211 | ||
1212 | /* Ensure only valid outer attributes are added to the outer_attributes | |
1213 | * list */ | |
1214 | if (!outer_attr.is_empty ()) | |
1215 | { | |
1216 | outer_attributes.push_back (std::move (outer_attr)); | |
1217 | } | |
1218 | else | |
1219 | { | |
1220 | /* If no more valid outer attributes, break out of loop (only | |
1221 | * contiguous outer attributes parsed). */ | |
1222 | break; | |
1223 | } | |
1224 | } | |
1225 | ||
1226 | outer_attributes.shrink_to_fit (); | |
1227 | return outer_attributes; | |
1228 | ||
1229 | /* TODO: this shares basically all code with parse_inner_attributes except | |
1230 | * function call - find way of making it more modular? function pointer? */ | |
1231 | } | |
1232 | ||
1233 | // Parse a single outer attribute. | |
1234 | template <typename ManagedTokenSource> | |
1235 | AST::Attribute | |
1236 | Parser<ManagedTokenSource>::parse_outer_attribute () | |
1237 | { | |
1238 | if (lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT) | |
1239 | { | |
1240 | auto values = parse_doc_comment (); | |
1241 | auto path = std::move (std::get<0> (values)); | |
1242 | auto input = std::move (std::get<1> (values)); | |
1243 | auto loc = std::get<2> (values); | |
1244 | return AST::Attribute (std::move (path), std::move (input), loc, false); | |
1245 | } | |
1246 | ||
1247 | if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT) | |
1248 | { | |
1249 | Error error ( | |
1250 | lexer.peek_token ()->get_locus (), ErrorCode::E0753, | |
1251 | "expected outer doc comment, inner doc (%<//!%> or %</*!%>) only " | |
1252 | "allowed at start of item " | |
1253 | "and before any outer attribute or doc (%<#[%>, %<///%> or %</**%>)"); | |
1254 | add_error (std::move (error)); | |
1255 | lexer.skip_token (); | |
1256 | return AST::Attribute::create_empty (); | |
1257 | } | |
1258 | ||
1259 | /* OuterAttribute -> '#' '[' Attr ']' */ | |
1260 | ||
1261 | if (lexer.peek_token ()->get_id () != HASH) | |
1262 | return AST::Attribute::create_empty (); | |
1263 | ||
1264 | lexer.skip_token (); | |
1265 | ||
1266 | TokenId id = lexer.peek_token ()->get_id (); | |
1267 | if (id != LEFT_SQUARE) | |
1268 | { | |
1269 | if (id == EXCLAM) | |
1270 | { | |
1271 | // this is inner attribute syntax, so throw error | |
1272 | // inner attributes were either already parsed or not allowed here. | |
1273 | Error error ( | |
1274 | lexer.peek_token ()->get_locus (), | |
1275 | "token %<!%> found, indicating inner attribute definition. Inner " | |
1276 | "attributes are not possible at this location"); | |
1277 | add_error (std::move (error)); | |
1278 | } | |
1279 | return AST::Attribute::create_empty (); | |
1280 | } | |
1281 | ||
1282 | lexer.skip_token (); | |
1283 | ||
1284 | auto values = parse_attribute_body (); | |
1285 | auto path = std::move (std::get<0> (values)); | |
1286 | auto input = std::move (std::get<1> (values)); | |
1287 | auto loc = std::get<2> (values); | |
1288 | auto actual_attribute | |
1289 | = AST::Attribute (std::move (path), std::move (input), loc, false); | |
1290 | ||
1291 | if (lexer.peek_token ()->get_id () != RIGHT_SQUARE) | |
1292 | return AST::Attribute::create_empty (); | |
1293 | ||
1294 | lexer.skip_token (); | |
1295 | ||
1296 | return actual_attribute; | |
1297 | } | |
1298 | ||
1299 | // Parses a VisItem (item that can have non-default visibility). | |
1300 | template <typename ManagedTokenSource> | |
1301 | std::unique_ptr<AST::VisItem> | |
1302 | Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs) | |
1303 | { | |
1304 | // parse visibility, which may or may not exist | |
1305 | AST::Visibility vis = parse_visibility (); | |
1306 | ||
1307 | // select VisItem to create depending on keyword | |
1308 | const_TokenPtr t = lexer.peek_token (); | |
1309 | ||
1310 | switch (t->get_id ()) | |
1311 | { | |
1312 | case MOD: | |
1313 | return parse_module (std::move (vis), std::move (outer_attrs)); | |
1314 | case EXTERN_KW: | |
1315 | // lookahead to resolve syntactical production | |
1316 | t = lexer.peek_token (1); | |
1317 | ||
1318 | switch (t->get_id ()) | |
1319 | { | |
1320 | case CRATE: | |
1321 | return parse_extern_crate (std::move (vis), std::move (outer_attrs)); | |
1322 | case FN_KW: // extern function | |
1323 | return parse_function (std::move (vis), std::move (outer_attrs)); | |
1324 | case LEFT_CURLY: // extern block | |
1325 | return parse_extern_block (std::move (vis), std::move (outer_attrs)); | |
1326 | case STRING_LITERAL: // for specifying extern ABI | |
1327 | // could be extern block or extern function, so more lookahead | |
1328 | t = lexer.peek_token (2); | |
1329 | ||
1330 | switch (t->get_id ()) | |
1331 | { | |
1332 | case FN_KW: | |
1333 | return parse_function (std::move (vis), std::move (outer_attrs)); | |
1334 | case LEFT_CURLY: | |
1335 | return parse_extern_block (std::move (vis), | |
1336 | std::move (outer_attrs)); | |
1337 | default: | |
1338 | add_error ( | |
1339 | Error (t->get_locus (), | |
1340 | "unexpected token %qs in some sort of extern production", | |
1341 | t->get_token_description ())); | |
1342 | ||
1343 | lexer.skip_token (2); // TODO: is this right thing to do? | |
1344 | return nullptr; | |
1345 | } | |
1346 | default: | |
1347 | add_error ( | |
1348 | Error (t->get_locus (), | |
1349 | "unexpected token %qs in some sort of extern production", | |
1350 | t->get_token_description ())); | |
1351 | ||
1352 | lexer.skip_token (1); // TODO: is this right thing to do? | |
1353 | return nullptr; | |
1354 | } | |
1355 | case USE: | |
1356 | return parse_use_decl (std::move (vis), std::move (outer_attrs)); | |
1357 | case FN_KW: | |
1358 | return parse_function (std::move (vis), std::move (outer_attrs)); | |
1359 | case TYPE: | |
1360 | return parse_type_alias (std::move (vis), std::move (outer_attrs)); | |
1361 | case STRUCT_KW: | |
1362 | return parse_struct (std::move (vis), std::move (outer_attrs)); | |
1363 | case ENUM_KW: | |
1364 | return parse_enum (std::move (vis), std::move (outer_attrs)); | |
1365 | // TODO: implement union keyword but not really because of | |
1366 | // context-dependence case UNION: crappy hack to do union "keyword" | |
1367 | case IDENTIFIER: | |
1368 | if (t->get_str () == Values::WeakKeywords::UNION | |
1369 | && lexer.peek_token (1)->get_id () == IDENTIFIER) | |
1370 | { | |
1371 | return parse_union (std::move (vis), std::move (outer_attrs)); | |
1372 | // or should item switch go straight to parsing union? | |
1373 | } | |
1374 | else | |
1375 | { | |
1376 | break; | |
1377 | } | |
1378 | case CONST: | |
1379 | // lookahead to resolve syntactical production | |
1380 | t = lexer.peek_token (1); | |
1381 | ||
1382 | switch (t->get_id ()) | |
1383 | { | |
1384 | case IDENTIFIER: | |
1385 | case UNDERSCORE: | |
1386 | return parse_const_item (std::move (vis), std::move (outer_attrs)); | |
1387 | case ASYNC: | |
1388 | return parse_async_item (std::move (vis), std::move (outer_attrs)); | |
1389 | case UNSAFE: | |
1390 | case EXTERN_KW: | |
1391 | case FN_KW: | |
1392 | return parse_function (std::move (vis), std::move (outer_attrs)); | |
1393 | default: | |
1394 | add_error ( | |
1395 | Error (t->get_locus (), | |
1396 | "unexpected token %qs in some sort of const production", | |
1397 | t->get_token_description ())); | |
1398 | ||
1399 | lexer.skip_token (1); // TODO: is this right thing to do? | |
1400 | return nullptr; | |
1401 | } | |
1402 | // for async functions | |
1403 | case ASYNC: | |
1404 | return parse_async_item (std::move (vis), std::move (outer_attrs)); | |
1405 | ||
1406 | case STATIC_KW: | |
1407 | return parse_static_item (std::move (vis), std::move (outer_attrs)); | |
1408 | case AUTO: | |
1409 | case TRAIT: | |
1410 | return parse_trait (std::move (vis), std::move (outer_attrs)); | |
1411 | case IMPL: | |
1412 | return parse_impl (std::move (vis), std::move (outer_attrs)); | |
1413 | case UNSAFE: // unsafe traits, unsafe functions, unsafe impls (trait impls), | |
1414 | // lookahead to resolve syntactical production | |
1415 | t = lexer.peek_token (1); | |
1416 | ||
1417 | switch (t->get_id ()) | |
1418 | { | |
1419 | case AUTO: | |
1420 | case TRAIT: | |
1421 | return parse_trait (std::move (vis), std::move (outer_attrs)); | |
1422 | case EXTERN_KW: | |
1423 | case FN_KW: | |
1424 | return parse_function (std::move (vis), std::move (outer_attrs)); | |
1425 | case IMPL: | |
1426 | return parse_impl (std::move (vis), std::move (outer_attrs)); | |
1427 | case MOD: | |
1428 | return parse_module (std::move (vis), std::move (outer_attrs)); | |
1429 | default: | |
1430 | add_error ( | |
1431 | Error (t->get_locus (), | |
1432 | "unexpected token %qs in some sort of unsafe production", | |
1433 | t->get_token_description ())); | |
1434 | ||
1435 | lexer.skip_token (1); // TODO: is this right thing to do? | |
1436 | return nullptr; | |
1437 | } | |
1438 | case MACRO: | |
1439 | return parse_decl_macro_def (std::move (vis), std::move (outer_attrs)); | |
1440 | default: | |
1441 | // otherwise vis item clearly doesn't exist, which is not an error | |
1442 | // has a catch-all post-switch return to allow other breaks to occur | |
1443 | break; | |
1444 | } | |
1445 | return nullptr; | |
1446 | } | |
1447 | ||
1448 | template <typename ManagedTokenSource> | |
1449 | std::unique_ptr<AST::Function> | |
1450 | Parser<ManagedTokenSource>::parse_async_item (AST::Visibility vis, | |
1451 | AST::AttrVec outer_attrs) | |
1452 | { | |
1453 | auto offset = (lexer.peek_token ()->get_id () == CONST) ? 1 : 0; | |
1454 | const_TokenPtr t = lexer.peek_token (offset); | |
1455 | ||
1456 | if (get_rust_edition () == Edition::E2015) | |
1457 | { | |
1458 | add_error (Error (t->get_locus (), ErrorCode::E0670, | |
1459 | "%<async fn%> is not permitted in Rust 2015")); | |
1460 | add_error ( | |
1461 | Error::Hint (t->get_locus (), | |
1462 | "to use %<async fn%>, switch to Rust 2018 or later")); | |
1463 | } | |
1464 | ||
1465 | t = lexer.peek_token (offset + 1); | |
1466 | ||
1467 | switch (t->get_id ()) | |
1468 | { | |
1469 | case UNSAFE: | |
1470 | case FN_KW: | |
1471 | return parse_function (std::move (vis), std::move (outer_attrs)); | |
1472 | ||
1473 | default: | |
1474 | add_error ( | |
1475 | Error (t->get_locus (), "expected item, found keyword %<async%>")); | |
1476 | ||
1477 | lexer.skip_token (1); | |
1478 | return nullptr; | |
1479 | } | |
1480 | } | |
1481 | ||
1482 | // Parses a macro rules definition syntax extension whatever thing. | |
1483 | template <typename ManagedTokenSource> | |
1484 | std::unique_ptr<AST::MacroRulesDefinition> | |
1485 | Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs) | |
1486 | { | |
1487 | // ensure that first token is identifier saying "macro_rules" | |
1488 | const_TokenPtr t = lexer.peek_token (); | |
1489 | if (t->get_id () != IDENTIFIER | |
1490 | || t->get_str () != Values::WeakKeywords::MACRO_RULES) | |
1491 | { | |
1492 | Error error ( | |
1493 | t->get_locus (), | |
1494 | "macro rules definition does not start with %<macro_rules%>"); | |
1495 | add_error (std::move (error)); | |
1496 | ||
1497 | // skip after somewhere? | |
1498 | return nullptr; | |
1499 | } | |
1500 | lexer.skip_token (); | |
1501 | location_t macro_locus = t->get_locus (); | |
1502 | ||
1503 | if (!skip_token (EXCLAM)) | |
1504 | { | |
1505 | // skip after somewhere? | |
1506 | return nullptr; | |
1507 | } | |
1508 | ||
1509 | // parse macro name | |
1510 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
1511 | if (ident_tok == nullptr) | |
1512 | { | |
1513 | return nullptr; | |
1514 | } | |
1515 | Identifier rule_name{ident_tok}; | |
1516 | ||
1517 | // DEBUG | |
1518 | rust_debug ("in macro rules def, about to parse parens."); | |
1519 | ||
1520 | // save delim type to ensure it is reused later | |
1521 | AST::DelimType delim_type = AST::PARENS; | |
1522 | ||
1523 | // Map tokens to DelimType | |
1524 | t = lexer.peek_token (); | |
1525 | switch (t->get_id ()) | |
1526 | { | |
1527 | case LEFT_PAREN: | |
1528 | delim_type = AST::PARENS; | |
1529 | break; | |
1530 | case LEFT_SQUARE: | |
1531 | delim_type = AST::SQUARE; | |
1532 | break; | |
1533 | case LEFT_CURLY: | |
1534 | delim_type = AST::CURLY; | |
1535 | break; | |
1536 | default: | |
1537 | add_error (Error (t->get_locus (), | |
1538 | "unexpected token %qs - expecting delimiters (for a " | |
1539 | "macro rules definition)", | |
1540 | t->get_token_description ())); | |
1541 | ||
1542 | return nullptr; | |
1543 | } | |
1544 | lexer.skip_token (); | |
1545 | ||
1546 | // parse actual macro rules | |
1547 | std::vector<AST::MacroRule> macro_rules; | |
1548 | ||
1549 | // must be at least one macro rule, so parse it | |
1550 | AST::MacroRule initial_rule = parse_macro_rule (); | |
1551 | if (initial_rule.is_error ()) | |
1552 | { | |
1553 | Error error (lexer.peek_token ()->get_locus (), | |
1554 | "required first macro rule in macro rules definition " | |
1555 | "could not be parsed"); | |
1556 | add_error (std::move (error)); | |
1557 | ||
1558 | // skip after somewhere? | |
1559 | return nullptr; | |
1560 | } | |
1561 | macro_rules.push_back (std::move (initial_rule)); | |
1562 | ||
1563 | // DEBUG | |
1564 | rust_debug ("successfully pushed back initial macro rule"); | |
1565 | ||
1566 | t = lexer.peek_token (); | |
1567 | // parse macro rules | |
1568 | while (t->get_id () == SEMICOLON) | |
1569 | { | |
1570 | // skip semicolon | |
1571 | lexer.skip_token (); | |
1572 | ||
1573 | // don't parse if end of macro rules | |
1574 | if (token_id_matches_delims (lexer.peek_token ()->get_id (), delim_type)) | |
1575 | { | |
1576 | // DEBUG | |
1577 | rust_debug ( | |
1578 | "broke out of parsing macro rules loop due to finding delim"); | |
1579 | ||
1580 | break; | |
1581 | } | |
1582 | ||
1583 | // try to parse next rule | |
1584 | AST::MacroRule rule = parse_macro_rule (); | |
1585 | if (rule.is_error ()) | |
1586 | { | |
1587 | Error error (lexer.peek_token ()->get_locus (), | |
1588 | "failed to parse macro rule in macro rules definition"); | |
1589 | add_error (std::move (error)); | |
1590 | ||
1591 | return nullptr; | |
1592 | } | |
1593 | ||
1594 | macro_rules.push_back (std::move (rule)); | |
1595 | ||
1596 | // DEBUG | |
1597 | rust_debug ("successfully pushed back another macro rule"); | |
1598 | ||
1599 | t = lexer.peek_token (); | |
1600 | } | |
1601 | ||
1602 | // parse end delimiters | |
1603 | t = lexer.peek_token (); | |
1604 | if (token_id_matches_delims (t->get_id (), delim_type)) | |
1605 | { | |
1606 | // tokens match opening delimiter, so skip. | |
1607 | lexer.skip_token (); | |
1608 | ||
1609 | if (delim_type != AST::CURLY) | |
1610 | { | |
1611 | // skip semicolon at end of non-curly macro definitions | |
1612 | if (!skip_token (SEMICOLON)) | |
1613 | { | |
1614 | // as this is the end, allow recovery (probably) - may change | |
1615 | return std::unique_ptr<AST::MacroRulesDefinition> ( | |
1616 | AST::MacroRulesDefinition::mbe ( | |
1617 | std::move (rule_name), delim_type, std::move (macro_rules), | |
1618 | std::move (outer_attrs), macro_locus)); | |
1619 | } | |
1620 | } | |
1621 | ||
1622 | return std::unique_ptr<AST::MacroRulesDefinition> ( | |
1623 | AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type, | |
1624 | std::move (macro_rules), | |
1625 | std::move (outer_attrs), macro_locus)); | |
1626 | } | |
1627 | else | |
1628 | { | |
1629 | // tokens don't match opening delimiters, so produce error | |
1630 | Error error (t->get_locus (), | |
1631 | "unexpected token %qs - expecting closing delimiter %qs " | |
1632 | "(for a macro rules definition)", | |
1633 | t->get_token_description (), | |
1634 | (delim_type == AST::PARENS | |
1635 | ? ")" | |
1636 | : (delim_type == AST::SQUARE ? "]" : "}"))); | |
1637 | add_error (std::move (error)); | |
1638 | ||
1639 | /* return empty macro definiton despite possibly parsing mostly valid one | |
1640 | * - TODO is this a good idea? */ | |
1641 | return nullptr; | |
1642 | } | |
1643 | } | |
1644 | ||
1645 | // Parses a declarative macro 2.0 definition. | |
1646 | template <typename ManagedTokenSource> | |
1647 | std::unique_ptr<AST::MacroRulesDefinition> | |
1648 | Parser<ManagedTokenSource>::parse_decl_macro_def (AST::Visibility vis, | |
1649 | AST::AttrVec outer_attrs) | |
1650 | { | |
1651 | // ensure that first token is identifier saying "macro" | |
1652 | const_TokenPtr t = lexer.peek_token (); | |
1653 | if (t->get_id () != MACRO) | |
1654 | { | |
1655 | Error error ( | |
1656 | t->get_locus (), | |
1657 | "declarative macro definition does not start with %<macro%>"); | |
1658 | add_error (std::move (error)); | |
1659 | ||
1660 | // skip after somewhere? | |
1661 | return nullptr; | |
1662 | } | |
1663 | lexer.skip_token (); | |
1664 | location_t macro_locus = t->get_locus (); | |
1665 | ||
1666 | // parse macro name | |
1667 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
1668 | if (ident_tok == nullptr) | |
1669 | { | |
1670 | return nullptr; | |
1671 | } | |
1672 | Identifier rule_name{ident_tok}; | |
1673 | ||
1674 | t = lexer.peek_token (); | |
1675 | if (t->get_id () == LEFT_PAREN) | |
1676 | { | |
1677 | // single definiton of macro rule | |
1678 | // e.g. `macro foo($e:expr) {}` | |
1679 | ||
1680 | // parse macro matcher | |
1681 | location_t locus = lexer.peek_token ()->get_locus (); | |
1682 | AST::MacroMatcher matcher = parse_macro_matcher (); | |
1683 | if (matcher.is_error ()) | |
1684 | return nullptr; | |
1685 | ||
1686 | // check delimiter of macro matcher | |
1687 | if (matcher.get_delim_type () != AST::DelimType::PARENS) | |
1688 | { | |
1689 | Error error (locus, "only parenthesis can be used for a macro " | |
1690 | "matcher in declarative macro definition"); | |
1691 | add_error (std::move (error)); | |
1692 | return nullptr; | |
1693 | } | |
1694 | ||
1695 | location_t transcriber_loc = lexer.peek_token ()->get_locus (); | |
1696 | AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree (); | |
1697 | AST::MacroTranscriber transcriber (delim_tok_tree, transcriber_loc); | |
1698 | ||
1699 | if (transcriber.get_token_tree ().get_delim_type () | |
1700 | != AST::DelimType::CURLY) | |
1701 | { | |
1702 | Error error (transcriber_loc, | |
1703 | "only braces can be used for a macro transcriber " | |
1704 | "in declarative macro definition"); | |
1705 | add_error (std::move (error)); | |
1706 | return nullptr; | |
1707 | } | |
1708 | ||
1709 | AST::MacroRule macro_rule | |
1710 | = AST::MacroRule (std::move (matcher), std::move (transcriber), locus); | |
1711 | std::vector<AST::MacroRule> macro_rules; | |
1712 | macro_rules.push_back (macro_rule); | |
1713 | ||
1714 | return std::unique_ptr<AST::MacroRulesDefinition> ( | |
1715 | AST::MacroRulesDefinition::decl_macro (std::move (rule_name), | |
1716 | macro_rules, | |
1717 | std::move (outer_attrs), | |
1718 | macro_locus, vis)); | |
1719 | } | |
1720 | else if (t->get_id () == LEFT_CURLY) | |
1721 | { | |
1722 | // multiple definitions of macro rule separated by comma | |
1723 | // e.g. `macro foo { () => {}, ($e:expr) => {}, }` | |
1724 | ||
1725 | // parse left curly | |
1726 | const_TokenPtr left_curly = expect_token (LEFT_CURLY); | |
1727 | if (left_curly == nullptr) | |
1728 | { | |
1729 | return nullptr; | |
1730 | } | |
1731 | ||
1732 | // parse actual macro rules | |
1733 | std::vector<AST::MacroRule> macro_rules; | |
1734 | ||
1735 | // must be at least one macro rule, so parse it | |
1736 | AST::MacroRule initial_rule = parse_macro_rule (); | |
1737 | if (initial_rule.is_error ()) | |
1738 | { | |
1739 | Error error ( | |
1740 | lexer.peek_token ()->get_locus (), | |
1741 | "required first macro rule in declarative macro definition " | |
1742 | "could not be parsed"); | |
1743 | add_error (std::move (error)); | |
1744 | ||
1745 | // skip after somewhere? | |
1746 | return nullptr; | |
1747 | } | |
1748 | macro_rules.push_back (std::move (initial_rule)); | |
1749 | ||
1750 | t = lexer.peek_token (); | |
1751 | // parse macro rules | |
1752 | while (t->get_id () == COMMA) | |
1753 | { | |
1754 | // skip comma | |
1755 | lexer.skip_token (); | |
1756 | ||
1757 | // don't parse if end of macro rules | |
1758 | if (token_id_matches_delims (lexer.peek_token ()->get_id (), | |
1759 | AST::CURLY)) | |
1760 | { | |
1761 | break; | |
1762 | } | |
1763 | ||
1764 | // try to parse next rule | |
1765 | AST::MacroRule rule = parse_macro_rule (); | |
1766 | if (rule.is_error ()) | |
1767 | { | |
1768 | Error error ( | |
1769 | lexer.peek_token ()->get_locus (), | |
1770 | "failed to parse macro rule in declarative macro definition"); | |
1771 | add_error (std::move (error)); | |
1772 | ||
1773 | return nullptr; | |
1774 | } | |
1775 | ||
1776 | macro_rules.push_back (std::move (rule)); | |
1777 | ||
1778 | t = lexer.peek_token (); | |
1779 | } | |
1780 | ||
1781 | // parse right curly | |
1782 | const_TokenPtr right_curly = expect_token (RIGHT_CURLY); | |
1783 | if (right_curly == nullptr) | |
1784 | { | |
1785 | return nullptr; | |
1786 | } | |
1787 | ||
1788 | return std::unique_ptr<AST::MacroRulesDefinition> ( | |
1789 | AST::MacroRulesDefinition::decl_macro (std::move (rule_name), | |
1790 | std::move (macro_rules), | |
1791 | std::move (outer_attrs), | |
1792 | macro_locus, vis)); | |
1793 | } | |
1794 | else | |
1795 | { | |
1796 | add_error (Error (t->get_locus (), | |
1797 | "unexpected token %qs - expecting delimiters " | |
1798 | "(for a declarative macro definiton)", | |
1799 | t->get_token_description ())); | |
1800 | return nullptr; | |
1801 | } | |
1802 | } | |
1803 | ||
1804 | // Parses a semi-coloned (except for full block) macro invocation item. | |
1805 | template <typename ManagedTokenSource> | |
1806 | std::unique_ptr<AST::MacroInvocation> | |
1807 | Parser<ManagedTokenSource>::parse_macro_invocation_semi ( | |
1808 | AST::AttrVec outer_attrs) | |
1809 | { | |
1810 | location_t macro_locus = lexer.peek_token ()->get_locus (); | |
1811 | AST::SimplePath path = parse_simple_path (); | |
1812 | ||
1813 | if (!skip_token (EXCLAM)) | |
1814 | { | |
1815 | // skip after somewhere? | |
1816 | return nullptr; | |
1817 | } | |
1818 | ||
1819 | // save delim type to ensure it is reused later | |
1820 | AST::DelimType delim_type = AST::PARENS; | |
1821 | ||
1822 | // Map tokens to DelimType | |
1823 | const_TokenPtr t = lexer.peek_token (); | |
1824 | switch (t->get_id ()) | |
1825 | { | |
1826 | case LEFT_PAREN: | |
1827 | delim_type = AST::PARENS; | |
1828 | break; | |
1829 | case LEFT_SQUARE: | |
1830 | delim_type = AST::SQUARE; | |
1831 | break; | |
1832 | case LEFT_CURLY: | |
1833 | delim_type = AST::CURLY; | |
1834 | break; | |
1835 | default: | |
1836 | add_error (Error (t->get_locus (), | |
1837 | "unexpected token %qs - expecting delimiters (for a " | |
1838 | "macro invocation semi body)", | |
1839 | t->get_token_description ())); | |
1840 | ||
1841 | return nullptr; | |
1842 | } | |
1843 | location_t tok_tree_locus = t->get_locus (); | |
1844 | lexer.skip_token (); | |
1845 | ||
1846 | // parse actual token trees | |
1847 | std::vector<std::unique_ptr<AST::TokenTree>> token_trees; | |
1848 | auto delim_open | |
1849 | = std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
1850 | token_trees.push_back (std::move (delim_open)); | |
1851 | ||
1852 | t = lexer.peek_token (); | |
1853 | // parse token trees until the initial delimiter token is found again | |
1854 | while (!token_id_matches_delims (t->get_id (), delim_type)) | |
1855 | { | |
1856 | std::unique_ptr<AST::TokenTree> tree = parse_token_tree (); | |
1857 | ||
1858 | if (tree == nullptr) | |
1859 | { | |
1860 | Error error (t->get_locus (), | |
1861 | "failed to parse token tree for macro invocation semi " | |
1862 | "- found %qs", | |
1863 | t->get_token_description ()); | |
1864 | add_error (std::move (error)); | |
1865 | ||
1866 | return nullptr; | |
1867 | } | |
1868 | ||
1869 | token_trees.push_back (std::move (tree)); | |
1870 | ||
1871 | t = lexer.peek_token (); | |
1872 | } | |
1873 | auto delim_close | |
1874 | = std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
1875 | token_trees.push_back (std::move (delim_close)); | |
1876 | ||
1877 | AST::DelimTokenTree delim_tok_tree (delim_type, std::move (token_trees), | |
1878 | tok_tree_locus); | |
1879 | AST::MacroInvocData invoc_data (std::move (path), std::move (delim_tok_tree)); | |
1880 | ||
1881 | // parse end delimiters | |
1882 | t = lexer.peek_token (); | |
1883 | if (token_id_matches_delims (t->get_id (), delim_type)) | |
1884 | { | |
1885 | // tokens match opening delimiter, so skip. | |
1886 | lexer.skip_token (); | |
1887 | ||
1888 | if (delim_type != AST::CURLY) | |
1889 | { | |
1890 | // skip semicolon at end of non-curly macro invocation semis | |
1891 | if (!skip_token (SEMICOLON)) | |
1892 | { | |
1893 | // as this is the end, allow recovery (probably) - may change | |
1894 | ||
1895 | return AST::MacroInvocation::Regular (std::move (invoc_data), | |
1896 | std::move (outer_attrs), | |
1897 | macro_locus, true); | |
1898 | } | |
1899 | } | |
1900 | ||
1901 | // DEBUG: | |
1902 | rust_debug ("skipped token is '%s', next token (current peek) is '%s'", | |
1903 | t->get_token_description (), | |
1904 | lexer.peek_token ()->get_token_description ()); | |
1905 | ||
1906 | return AST::MacroInvocation::Regular (std::move (invoc_data), | |
1907 | std::move (outer_attrs), | |
1908 | macro_locus, true); | |
1909 | } | |
1910 | else | |
1911 | { | |
1912 | // tokens don't match opening delimiters, so produce error | |
1913 | Error error (t->get_locus (), | |
1914 | "unexpected token %qs - expecting closing delimiter %qs " | |
1915 | "(for a macro invocation semi)", | |
1916 | t->get_token_description (), | |
1917 | (delim_type == AST::PARENS | |
1918 | ? ")" | |
1919 | : (delim_type == AST::SQUARE ? "]" : "}"))); | |
1920 | add_error (std::move (error)); | |
1921 | ||
1922 | /* return empty macro invocation despite possibly parsing mostly valid one | |
1923 | * - TODO is this a good idea? */ | |
1924 | return nullptr; | |
1925 | } | |
1926 | } | |
1927 | ||
1928 | // Parses a non-semicoloned macro invocation (i.e. as pattern or expression). | |
1929 | template <typename ManagedTokenSource> | |
1930 | std::unique_ptr<AST::MacroInvocation> | |
1931 | Parser<ManagedTokenSource>::parse_macro_invocation (AST::AttrVec outer_attrs) | |
1932 | { | |
1933 | // parse macro path | |
1934 | AST::SimplePath macro_path = parse_simple_path (); | |
1935 | if (macro_path.is_empty ()) | |
1936 | { | |
1937 | Error error (lexer.peek_token ()->get_locus (), | |
1938 | "failed to parse macro invocation path"); | |
1939 | add_error (std::move (error)); | |
1940 | ||
1941 | // skip? | |
1942 | return nullptr; | |
1943 | } | |
1944 | ||
1945 | if (!skip_token (EXCLAM)) | |
1946 | { | |
1947 | // skip after somewhere? | |
1948 | return nullptr; | |
1949 | } | |
1950 | ||
1951 | // parse internal delim token tree | |
1952 | AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree (); | |
1953 | ||
1954 | location_t macro_locus = macro_path.get_locus (); | |
1955 | ||
1956 | return AST::MacroInvocation::Regular ( | |
1957 | AST::MacroInvocData (std::move (macro_path), std::move (delim_tok_tree)), | |
1958 | std::move (outer_attrs), macro_locus); | |
1959 | } | |
1960 | ||
1961 | // Parses a macro rule definition - does not parse semicolons. | |
1962 | template <typename ManagedTokenSource> | |
1963 | AST::MacroRule | |
1964 | Parser<ManagedTokenSource>::parse_macro_rule () | |
1965 | { | |
1966 | location_t locus = lexer.peek_token ()->get_locus (); | |
1967 | ||
1968 | // parse macro matcher | |
1969 | AST::MacroMatcher matcher = parse_macro_matcher (); | |
1970 | ||
1971 | if (matcher.is_error ()) | |
1972 | return AST::MacroRule::create_error (locus); | |
1973 | ||
1974 | if (!skip_token (MATCH_ARROW)) | |
1975 | { | |
1976 | // skip after somewhere? | |
1977 | return AST::MacroRule::create_error (locus); | |
1978 | } | |
1979 | ||
1980 | // parse transcriber (this is just a delim token tree) | |
1981 | location_t token_tree_loc = lexer.peek_token ()->get_locus (); | |
1982 | AST::MacroTranscriber transcriber (parse_delim_token_tree (), token_tree_loc); | |
1983 | ||
1984 | return AST::MacroRule (std::move (matcher), std::move (transcriber), locus); | |
1985 | } | |
1986 | ||
1987 | // Parses a macro matcher (part of a macro rule definition). | |
1988 | template <typename ManagedTokenSource> | |
1989 | AST::MacroMatcher | |
1990 | Parser<ManagedTokenSource>::parse_macro_matcher () | |
1991 | { | |
1992 | // save delim type to ensure it is reused later | |
1993 | AST::DelimType delim_type = AST::PARENS; | |
1994 | ||
1995 | // DEBUG | |
1996 | rust_debug ("begun parsing macro matcher"); | |
1997 | ||
1998 | // Map tokens to DelimType | |
1999 | const_TokenPtr t = lexer.peek_token (); | |
2000 | location_t locus = t->get_locus (); | |
2001 | switch (t->get_id ()) | |
2002 | { | |
2003 | case LEFT_PAREN: | |
2004 | delim_type = AST::PARENS; | |
2005 | break; | |
2006 | case LEFT_SQUARE: | |
2007 | delim_type = AST::SQUARE; | |
2008 | break; | |
2009 | case LEFT_CURLY: | |
2010 | delim_type = AST::CURLY; | |
2011 | break; | |
2012 | default: | |
2013 | add_error (Error ( | |
2014 | t->get_locus (), | |
2015 | "unexpected token %qs - expecting delimiters (for a macro matcher)", | |
2016 | t->get_token_description ())); | |
2017 | ||
2018 | return AST::MacroMatcher::create_error (t->get_locus ()); | |
2019 | } | |
2020 | lexer.skip_token (); | |
2021 | ||
2022 | // parse actual macro matches | |
2023 | std::vector<std::unique_ptr<AST::MacroMatch>> matches; | |
2024 | // Set of possible preceding macro matches to make sure follow-set | |
2025 | // restrictions are respected. | |
2026 | // TODO: Consider using std::reference_wrapper instead of raw pointers? | |
2027 | std::vector<const AST::MacroMatch *> last_matches; | |
2028 | ||
2029 | t = lexer.peek_token (); | |
2030 | // parse token trees until the initial delimiter token is found again | |
2031 | while (!token_id_matches_delims (t->get_id (), delim_type)) | |
2032 | { | |
2033 | std::unique_ptr<AST::MacroMatch> match = parse_macro_match (); | |
2034 | ||
2035 | if (match == nullptr) | |
2036 | { | |
2037 | Error error ( | |
2038 | t->get_locus (), | |
2039 | "failed to parse macro match for macro matcher - found %qs", | |
2040 | t->get_token_description ()); | |
2041 | add_error (std::move (error)); | |
2042 | ||
2043 | return AST::MacroMatcher::create_error (t->get_locus ()); | |
2044 | } | |
2045 | ||
2046 | if (matches.size () > 0) | |
2047 | { | |
2048 | const auto *last_match = matches.back ().get (); | |
2049 | ||
2050 | // We want to check if we are dealing with a zeroable repetition | |
2051 | bool zeroable = false; | |
2052 | if (last_match->get_macro_match_type () | |
2053 | == AST::MacroMatch::MacroMatchType::Repetition) | |
2054 | { | |
2055 | auto repetition | |
2056 | = static_cast<const AST::MacroMatchRepetition *> (last_match); | |
2057 | ||
2058 | if (repetition->get_op () | |
2059 | != AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE) | |
2060 | zeroable = true; | |
2061 | } | |
2062 | ||
2063 | if (!zeroable) | |
2064 | last_matches.clear (); | |
2065 | ||
2066 | last_matches.emplace_back (last_match); | |
2067 | ||
2068 | for (auto last : last_matches) | |
2069 | if (!is_match_compatible (*last, *match)) | |
2070 | return AST::MacroMatcher::create_error ( | |
2071 | match->get_match_locus ()); | |
2072 | } | |
2073 | ||
2074 | matches.push_back (std::move (match)); | |
2075 | ||
2076 | // DEBUG | |
2077 | rust_debug ("pushed back a match in macro matcher"); | |
2078 | ||
2079 | t = lexer.peek_token (); | |
2080 | } | |
2081 | ||
2082 | // parse end delimiters | |
2083 | t = lexer.peek_token (); | |
2084 | if (token_id_matches_delims (t->get_id (), delim_type)) | |
2085 | { | |
2086 | // tokens match opening delimiter, so skip. | |
2087 | lexer.skip_token (); | |
2088 | ||
2089 | return AST::MacroMatcher (delim_type, std::move (matches), locus); | |
2090 | } | |
2091 | else | |
2092 | { | |
2093 | // tokens don't match opening delimiters, so produce error | |
2094 | Error error (t->get_locus (), | |
2095 | "unexpected token %qs - expecting closing delimiter %qs " | |
2096 | "(for a macro matcher)", | |
2097 | t->get_token_description (), | |
2098 | (delim_type == AST::PARENS | |
2099 | ? ")" | |
2100 | : (delim_type == AST::SQUARE ? "]" : "}"))); | |
2101 | add_error (std::move (error)); | |
2102 | ||
2103 | /* return error macro matcher despite possibly parsing mostly correct one? | |
2104 | * TODO is this the best idea? */ | |
2105 | return AST::MacroMatcher::create_error (t->get_locus ()); | |
2106 | } | |
2107 | } | |
2108 | ||
2109 | // Parses a macro match (syntax match inside a matcher in a macro rule). | |
2110 | template <typename ManagedTokenSource> | |
2111 | std::unique_ptr<AST::MacroMatch> | |
2112 | Parser<ManagedTokenSource>::parse_macro_match () | |
2113 | { | |
2114 | // branch based on token available | |
2115 | const_TokenPtr t = lexer.peek_token (); | |
2116 | switch (t->get_id ()) | |
2117 | { | |
2118 | case LEFT_PAREN: | |
2119 | case LEFT_SQUARE: | |
2120 | case LEFT_CURLY: { | |
2121 | // must be macro matcher as delimited | |
2122 | AST::MacroMatcher matcher = parse_macro_matcher (); | |
2123 | if (matcher.is_error ()) | |
2124 | { | |
2125 | Error error (lexer.peek_token ()->get_locus (), | |
2126 | "failed to parse macro matcher in macro match"); | |
2127 | add_error (std::move (error)); | |
2128 | ||
2129 | return nullptr; | |
2130 | } | |
2131 | return std::unique_ptr<AST::MacroMatcher> ( | |
2132 | new AST::MacroMatcher (std::move (matcher))); | |
2133 | } | |
2134 | case DOLLAR_SIGN: { | |
2135 | // have to do more lookahead to determine if fragment or repetition | |
2136 | const_TokenPtr t2 = lexer.peek_token (1); | |
2137 | switch (t2->get_id ()) | |
2138 | { | |
2139 | case IDENTIFIER: | |
2140 | case UNDERSCORE: | |
2141 | // macro fragment | |
2142 | return parse_macro_match_fragment (); | |
2143 | case LEFT_PAREN: | |
2144 | // macro repetition | |
2145 | return parse_macro_match_repetition (); | |
2146 | default: | |
2147 | if (token_id_is_keyword (t2->get_id ()) && t2->get_id () != CRATE) | |
2148 | { | |
2149 | // keyword as macro fragment | |
2150 | return parse_macro_match_fragment (); | |
2151 | } | |
2152 | else | |
2153 | { | |
2154 | // error: unrecognised | |
2155 | add_error (Error ( | |
2156 | t2->get_locus (), | |
2157 | "unrecognised token combination %<$%s%> at start of " | |
2158 | "macro match - did you mean %<$identifier%> or %<$(%>?", | |
2159 | t2->get_token_description ())); | |
2160 | ||
2161 | // skip somewhere? | |
2162 | return nullptr; | |
2163 | } | |
2164 | } | |
2165 | } | |
2166 | case RIGHT_PAREN: | |
2167 | case RIGHT_SQUARE: | |
2168 | case RIGHT_CURLY: | |
2169 | // not allowed | |
2170 | add_error (Error ( | |
2171 | t->get_locus (), | |
2172 | "closing delimiters like %qs are not allowed at the start of a macro " | |
2173 | "match", | |
2174 | t->get_token_description ())); | |
2175 | ||
2176 | // skip somewhere? | |
2177 | return nullptr; | |
2178 | default: | |
2179 | // just the token | |
2180 | lexer.skip_token (); | |
2181 | return std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
2182 | } | |
2183 | } | |
2184 | ||
2185 | // Parses a fragment macro match. | |
2186 | template <typename ManagedTokenSource> | |
2187 | std::unique_ptr<AST::MacroMatchFragment> | |
2188 | Parser<ManagedTokenSource>::parse_macro_match_fragment () | |
2189 | { | |
2190 | location_t fragment_locus = lexer.peek_token ()->get_locus (); | |
2191 | skip_token (DOLLAR_SIGN); | |
2192 | ||
2193 | Identifier ident; | |
2194 | auto identifier = lexer.peek_token (); | |
2195 | if (identifier->get_id () == UNDERSCORE) | |
2196 | ident = {Values::Keywords::UNDERSCORE, identifier->get_locus ()}; | |
2197 | else | |
2198 | ident = {identifier}; | |
2199 | ||
2200 | if (ident.empty ()) | |
2201 | { | |
2202 | Error error (lexer.peek_token ()->get_locus (), | |
2203 | "missing identifier in macro match fragment"); | |
2204 | add_error (std::move (error)); | |
2205 | ||
2206 | return nullptr; | |
2207 | } | |
2208 | skip_token (identifier->get_id ()); | |
2209 | ||
2210 | if (!skip_token (COLON)) | |
2211 | { | |
2212 | // skip after somewhere? | |
2213 | return nullptr; | |
2214 | } | |
2215 | ||
2216 | // get MacroFragSpec for macro | |
2217 | const_TokenPtr t = expect_token (IDENTIFIER); | |
2218 | if (t == nullptr) | |
2219 | return nullptr; | |
2220 | ||
2221 | AST::MacroFragSpec frag | |
2222 | = AST::MacroFragSpec::get_frag_spec_from_str (t->get_str ()); | |
2223 | if (frag.is_error ()) | |
2224 | { | |
2225 | Error error (t->get_locus (), | |
2226 | "invalid fragment specifier %qs in fragment macro match", | |
2227 | t->get_str ().c_str ()); | |
2228 | add_error (std::move (error)); | |
2229 | ||
2230 | return nullptr; | |
2231 | } | |
2232 | ||
2233 | return std::unique_ptr<AST::MacroMatchFragment> ( | |
2234 | new AST::MacroMatchFragment (std::move (ident), frag, fragment_locus)); | |
2235 | } | |
2236 | ||
2237 | // Parses a repetition macro match. | |
2238 | template <typename ManagedTokenSource> | |
2239 | std::unique_ptr<AST::MacroMatchRepetition> | |
2240 | Parser<ManagedTokenSource>::parse_macro_match_repetition () | |
2241 | { | |
2242 | skip_token (DOLLAR_SIGN); | |
2243 | skip_token (LEFT_PAREN); | |
2244 | ||
2245 | std::vector<std::unique_ptr<AST::MacroMatch>> matches; | |
2246 | ||
2247 | // parse required first macro match | |
2248 | std::unique_ptr<AST::MacroMatch> initial_match = parse_macro_match (); | |
2249 | if (initial_match == nullptr) | |
2250 | { | |
2251 | Error error ( | |
2252 | lexer.peek_token ()->get_locus (), | |
2253 | "could not parse required first macro match in macro match repetition"); | |
2254 | add_error (std::move (error)); | |
2255 | ||
2256 | // skip after somewhere? | |
2257 | return nullptr; | |
2258 | } | |
2259 | matches.push_back (std::move (initial_match)); | |
2260 | ||
2261 | // parse optional later macro matches | |
2262 | const_TokenPtr t = lexer.peek_token (); | |
2263 | while (t->get_id () != RIGHT_PAREN) | |
2264 | { | |
2265 | std::unique_ptr<AST::MacroMatch> match = parse_macro_match (); | |
2266 | ||
2267 | if (match == nullptr) | |
2268 | { | |
2269 | Error error (lexer.peek_token ()->get_locus (), | |
2270 | "failed to parse macro match in macro match repetition"); | |
2271 | add_error (std::move (error)); | |
2272 | ||
2273 | return nullptr; | |
2274 | } | |
2275 | ||
2276 | matches.push_back (std::move (match)); | |
2277 | ||
2278 | t = lexer.peek_token (); | |
2279 | } | |
2280 | ||
2281 | if (!skip_token (RIGHT_PAREN)) | |
2282 | { | |
2283 | // skip after somewhere? | |
2284 | return nullptr; | |
2285 | } | |
2286 | ||
2287 | t = lexer.peek_token (); | |
2288 | // see if separator token exists | |
2289 | std::unique_ptr<AST::Token> separator = nullptr; | |
2290 | switch (t->get_id ()) | |
2291 | { | |
2292 | // repetition operators | |
2293 | case ASTERISK: | |
2294 | case PLUS: | |
2295 | case QUESTION_MARK: | |
2296 | // delimiters | |
2297 | case LEFT_PAREN: | |
2298 | case LEFT_CURLY: | |
2299 | case LEFT_SQUARE: | |
2300 | case RIGHT_PAREN: | |
2301 | case RIGHT_CURLY: | |
2302 | case RIGHT_SQUARE: | |
2303 | // separator does not exist, so still null and don't skip token | |
2304 | break; | |
2305 | default: | |
2306 | // separator does exist | |
2307 | separator = std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
2308 | lexer.skip_token (); | |
2309 | break; | |
2310 | } | |
2311 | ||
2312 | // parse repetition operator | |
2313 | t = lexer.peek_token (); | |
2314 | AST::MacroMatchRepetition::MacroRepOp op = AST::MacroMatchRepetition::NONE; | |
2315 | switch (t->get_id ()) | |
2316 | { | |
2317 | case ASTERISK: | |
2318 | op = AST::MacroMatchRepetition::ANY; | |
2319 | lexer.skip_token (); | |
2320 | break; | |
2321 | case PLUS: | |
2322 | op = AST::MacroMatchRepetition::ONE_OR_MORE; | |
2323 | lexer.skip_token (); | |
2324 | break; | |
2325 | case QUESTION_MARK: | |
2326 | op = AST::MacroMatchRepetition::ZERO_OR_ONE; | |
2327 | lexer.skip_token (); | |
2328 | ||
2329 | if (separator != nullptr) | |
2330 | { | |
2331 | add_error ( | |
2332 | Error (separator->get_locus (), | |
2333 | "the %<?%> macro repetition operator does not take a " | |
2334 | "separator")); | |
2335 | separator = nullptr; | |
2336 | } | |
2337 | ||
2338 | break; | |
2339 | default: | |
2340 | add_error ( | |
2341 | Error (t->get_locus (), | |
2342 | "expected macro repetition operator (%<*%>, %<+%>, or %<?%>) in " | |
2343 | "macro match - found %qs", | |
2344 | t->get_token_description ())); | |
2345 | ||
2346 | // skip after somewhere? | |
2347 | return nullptr; | |
2348 | } | |
2349 | ||
2350 | return std::unique_ptr<AST::MacroMatchRepetition> ( | |
2351 | new AST::MacroMatchRepetition (std::move (matches), op, | |
2352 | std::move (separator), t->get_locus ())); | |
2353 | } | |
2354 | ||
2355 | /* Parses a visibility syntactical production (i.e. creating a non-default | |
2356 | * visibility) */ | |
2357 | template <typename ManagedTokenSource> | |
2358 | AST::Visibility | |
2359 | Parser<ManagedTokenSource>::parse_visibility () | |
2360 | { | |
2361 | // check for no visibility | |
2362 | if (lexer.peek_token ()->get_id () != PUB) | |
2363 | { | |
2364 | return AST::Visibility::create_private (); | |
2365 | } | |
2366 | ||
2367 | auto vis_loc = lexer.peek_token ()->get_locus (); | |
2368 | lexer.skip_token (); | |
2369 | ||
2370 | // create simple pub visibility if | |
2371 | // - found no parentheses | |
2372 | // - found unit type `()` | |
2373 | if (lexer.peek_token ()->get_id () != LEFT_PAREN | |
2374 | || lexer.peek_token (1)->get_id () == RIGHT_PAREN) | |
2375 | { | |
2376 | return AST::Visibility::create_public (vis_loc); | |
2377 | // or whatever | |
2378 | } | |
2379 | ||
2380 | lexer.skip_token (); | |
2381 | ||
2382 | const_TokenPtr t = lexer.peek_token (); | |
2383 | auto path_loc = t->get_locus (); | |
2384 | ||
2385 | switch (t->get_id ()) | |
2386 | { | |
2387 | case CRATE: | |
2388 | lexer.skip_token (); | |
2389 | ||
2390 | skip_token (RIGHT_PAREN); | |
2391 | ||
2392 | return AST::Visibility::create_crate (path_loc, vis_loc); | |
2393 | case SELF: | |
2394 | lexer.skip_token (); | |
2395 | ||
2396 | skip_token (RIGHT_PAREN); | |
2397 | ||
2398 | return AST::Visibility::create_self (path_loc, vis_loc); | |
2399 | case SUPER: | |
2400 | lexer.skip_token (); | |
2401 | ||
2402 | skip_token (RIGHT_PAREN); | |
2403 | ||
2404 | return AST::Visibility::create_super (path_loc, vis_loc); | |
2405 | case IN: { | |
2406 | lexer.skip_token (); | |
2407 | ||
2408 | // parse the "in" path as well | |
2409 | AST::SimplePath path = parse_simple_path (); | |
2410 | if (path.is_empty ()) | |
2411 | { | |
2412 | Error error (lexer.peek_token ()->get_locus (), | |
2413 | "missing path in pub(in path) visibility"); | |
2414 | add_error (std::move (error)); | |
2415 | ||
2416 | // skip after somewhere? | |
2417 | return AST::Visibility::create_error (); | |
2418 | } | |
2419 | ||
2420 | skip_token (RIGHT_PAREN); | |
2421 | ||
2422 | return AST::Visibility::create_in_path (std::move (path), vis_loc); | |
2423 | } | |
2424 | default: | |
2425 | add_error (Error (t->get_locus (), "unexpected token %qs in visibility", | |
2426 | t->get_token_description ())); | |
2427 | ||
2428 | lexer.skip_token (); | |
2429 | return AST::Visibility::create_error (); | |
2430 | } | |
2431 | } | |
2432 | ||
2433 | // Parses a module - either a bodied module or a module defined in another file. | |
2434 | template <typename ManagedTokenSource> | |
2435 | std::unique_ptr<AST::Module> | |
2436 | Parser<ManagedTokenSource>::parse_module (AST::Visibility vis, | |
2437 | AST::AttrVec outer_attrs) | |
2438 | { | |
2439 | location_t locus = lexer.peek_token ()->get_locus (); | |
2440 | ||
2441 | Unsafety safety = Unsafety::Normal; | |
2442 | if (lexer.peek_token ()->get_id () == UNSAFE) | |
2443 | { | |
2444 | safety = Unsafety::Unsafe; | |
2445 | skip_token (UNSAFE); | |
2446 | } | |
2447 | ||
2448 | skip_token (MOD); | |
2449 | ||
2450 | const_TokenPtr module_name = expect_token (IDENTIFIER); | |
2451 | if (module_name == nullptr) | |
2452 | { | |
2453 | return nullptr; | |
2454 | } | |
2455 | Identifier name{module_name}; | |
2456 | ||
2457 | const_TokenPtr t = lexer.peek_token (); | |
2458 | ||
2459 | switch (t->get_id ()) | |
2460 | { | |
2461 | case SEMICOLON: | |
2462 | lexer.skip_token (); | |
2463 | ||
2464 | // Construct an external module | |
2465 | return std::unique_ptr<AST::Module> ( | |
2466 | new AST::Module (std::move (name), std::move (vis), | |
2467 | std::move (outer_attrs), locus, safety, | |
2468 | lexer.get_filename (), inline_module_stack)); | |
2469 | case LEFT_CURLY: { | |
2470 | lexer.skip_token (); | |
2471 | ||
2472 | // parse inner attributes | |
2473 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
2474 | ||
2475 | std::string default_path = name.as_string (); | |
2476 | ||
2477 | if (inline_module_stack.empty ()) | |
2478 | { | |
2479 | std::string filename = lexer.get_filename (); | |
2480 | auto slash_idx = filename.rfind (file_separator); | |
2481 | if (slash_idx == std::string::npos) | |
2482 | slash_idx = 0; | |
2483 | else | |
2484 | slash_idx++; | |
2485 | filename = filename.substr (slash_idx); | |
2486 | ||
2487 | std::string subdir; | |
2488 | if (get_file_subdir (filename, subdir)) | |
2489 | default_path = subdir + file_separator + name.as_string (); | |
2490 | } | |
2491 | ||
2492 | std::string module_path_name | |
2493 | = extract_module_path (inner_attrs, outer_attrs, default_path); | |
2494 | InlineModuleStackScope scope (*this, std::move (module_path_name)); | |
2495 | ||
2496 | // parse items | |
2497 | std::vector<std::unique_ptr<AST::Item>> items; | |
2498 | const_TokenPtr tok = lexer.peek_token (); | |
2499 | while (tok->get_id () != RIGHT_CURLY) | |
2500 | { | |
2501 | std::unique_ptr<AST::Item> item = parse_item (false); | |
2502 | if (item == nullptr) | |
2503 | { | |
2504 | Error error (tok->get_locus (), | |
2505 | "failed to parse item in module"); | |
2506 | add_error (std::move (error)); | |
2507 | ||
2508 | return nullptr; | |
2509 | } | |
2510 | ||
2511 | items.push_back (std::move (item)); | |
2512 | ||
2513 | tok = lexer.peek_token (); | |
2514 | } | |
2515 | ||
2516 | if (!skip_token (RIGHT_CURLY)) | |
2517 | { | |
2518 | // skip somewhere? | |
2519 | return nullptr; | |
2520 | } | |
2521 | ||
2522 | return std::unique_ptr<AST::Module> ( | |
2523 | new AST::Module (std::move (name), locus, std::move (items), | |
2524 | std::move (vis), safety, std::move (inner_attrs), | |
2525 | std::move (outer_attrs))); // module name? | |
2526 | } | |
2527 | default: | |
2528 | add_error ( | |
2529 | Error (t->get_locus (), | |
2530 | "unexpected token %qs in module declaration/definition item", | |
2531 | t->get_token_description ())); | |
2532 | ||
2533 | lexer.skip_token (); | |
2534 | return nullptr; | |
2535 | } | |
2536 | } | |
2537 | ||
2538 | // Parses an extern crate declaration (dependency on external crate) | |
2539 | template <typename ManagedTokenSource> | |
2540 | std::unique_ptr<AST::ExternCrate> | |
2541 | Parser<ManagedTokenSource>::parse_extern_crate (AST::Visibility vis, | |
2542 | AST::AttrVec outer_attrs) | |
2543 | { | |
2544 | location_t locus = lexer.peek_token ()->get_locus (); | |
2545 | if (!skip_token (EXTERN_KW)) | |
2546 | { | |
2547 | skip_after_semicolon (); | |
2548 | return nullptr; | |
2549 | } | |
2550 | ||
2551 | if (!skip_token (CRATE)) | |
2552 | { | |
2553 | skip_after_semicolon (); | |
2554 | return nullptr; | |
2555 | } | |
2556 | ||
2557 | /* parse crate reference name - this has its own syntactical rule in reference | |
2558 | * but seems to not be used elsewhere, so i'm putting it here */ | |
2559 | const_TokenPtr crate_name_tok = lexer.peek_token (); | |
2560 | std::string crate_name; | |
2561 | ||
2562 | switch (crate_name_tok->get_id ()) | |
2563 | { | |
2564 | case IDENTIFIER: | |
2565 | crate_name = crate_name_tok->get_str (); | |
2566 | lexer.skip_token (); | |
2567 | break; | |
2568 | case SELF: | |
2569 | crate_name = Values::Keywords::SELF; | |
2570 | lexer.skip_token (); | |
2571 | break; | |
2572 | default: | |
2573 | add_error ( | |
2574 | Error (crate_name_tok->get_locus (), | |
2575 | "expecting crate name (identifier or %<self%>), found %qs", | |
2576 | crate_name_tok->get_token_description ())); | |
2577 | ||
2578 | skip_after_semicolon (); | |
2579 | return nullptr; | |
2580 | } | |
2581 | ||
2582 | // don't parse as clause if it doesn't exist | |
2583 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
2584 | { | |
2585 | lexer.skip_token (); | |
2586 | ||
2587 | return std::unique_ptr<AST::ExternCrate> ( | |
2588 | new AST::ExternCrate (std::move (crate_name), std::move (vis), | |
2589 | std::move (outer_attrs), locus)); | |
2590 | } | |
2591 | ||
2592 | /* parse as clause - this also has its own syntactical rule in reference and | |
2593 | * also seems to not be used elsewhere, so including here again. */ | |
2594 | if (!skip_token (AS)) | |
2595 | { | |
2596 | skip_after_semicolon (); | |
2597 | return nullptr; | |
2598 | } | |
2599 | ||
2600 | const_TokenPtr as_name_tok = lexer.peek_token (); | |
2601 | std::string as_name; | |
2602 | ||
2603 | switch (as_name_tok->get_id ()) | |
2604 | { | |
2605 | case IDENTIFIER: | |
2606 | as_name = as_name_tok->get_str (); | |
2607 | lexer.skip_token (); | |
2608 | break; | |
2609 | case UNDERSCORE: | |
2610 | as_name = Values::Keywords::UNDERSCORE; | |
2611 | lexer.skip_token (); | |
2612 | break; | |
2613 | default: | |
2614 | add_error ( | |
2615 | Error (as_name_tok->get_locus (), | |
2616 | "expecting as clause name (identifier or %<_%>), found %qs", | |
2617 | as_name_tok->get_token_description ())); | |
2618 | ||
2619 | skip_after_semicolon (); | |
2620 | return nullptr; | |
2621 | } | |
2622 | ||
2623 | if (!skip_token (SEMICOLON)) | |
2624 | { | |
2625 | skip_after_semicolon (); | |
2626 | return nullptr; | |
2627 | } | |
2628 | ||
2629 | return std::unique_ptr<AST::ExternCrate> ( | |
2630 | new AST::ExternCrate (std::move (crate_name), std::move (vis), | |
2631 | std::move (outer_attrs), locus, std::move (as_name))); | |
2632 | } | |
2633 | ||
2634 | // Parses a use declaration. | |
2635 | template <typename ManagedTokenSource> | |
2636 | std::unique_ptr<AST::UseDeclaration> | |
2637 | Parser<ManagedTokenSource>::parse_use_decl (AST::Visibility vis, | |
2638 | AST::AttrVec outer_attrs) | |
2639 | { | |
2640 | location_t locus = lexer.peek_token ()->get_locus (); | |
2641 | if (!skip_token (USE)) | |
2642 | { | |
2643 | skip_after_semicolon (); | |
2644 | return nullptr; | |
2645 | } | |
2646 | ||
2647 | // parse use tree, which is required | |
2648 | std::unique_ptr<AST::UseTree> use_tree = parse_use_tree (); | |
2649 | if (use_tree == nullptr) | |
2650 | { | |
2651 | Error error (lexer.peek_token ()->get_locus (), | |
2652 | "could not parse use tree in use declaration"); | |
2653 | add_error (std::move (error)); | |
2654 | ||
2655 | skip_after_semicolon (); | |
2656 | return nullptr; | |
2657 | } | |
2658 | ||
2659 | if (!skip_token (SEMICOLON)) | |
2660 | { | |
2661 | skip_after_semicolon (); | |
2662 | return nullptr; | |
2663 | } | |
2664 | ||
2665 | return std::unique_ptr<AST::UseDeclaration> ( | |
2666 | new AST::UseDeclaration (std::move (use_tree), std::move (vis), | |
2667 | std::move (outer_attrs), locus)); | |
2668 | } | |
2669 | ||
2670 | // Parses a use tree (which can be recursive and is actually a base class). | |
2671 | template <typename ManagedTokenSource> | |
2672 | std::unique_ptr<AST::UseTree> | |
2673 | Parser<ManagedTokenSource>::parse_use_tree () | |
2674 | { | |
2675 | /* potential syntax definitions in attempt to get algorithm: | |
2676 | * Glob: | |
2677 | * <- SimplePath :: * | |
2678 | * <- :: * | |
2679 | * <- * | |
2680 | * Nested tree thing: | |
2681 | * <- SimplePath :: { COMPLICATED_INNER_TREE_THING } | |
2682 | * <- :: COMPLICATED_INNER_TREE_THING } | |
2683 | * <- { COMPLICATED_INNER_TREE_THING } | |
2684 | * Rebind thing: | |
2685 | * <- SimplePath as IDENTIFIER | |
2686 | * <- SimplePath as _ | |
2687 | * <- SimplePath | |
2688 | */ | |
2689 | ||
2690 | /* current plan of attack: try to parse SimplePath first - if fails, one of | |
2691 | * top two then try parse :: - if fails, one of top two. Next is deciding | |
2692 | * character for top two. */ | |
2693 | ||
2694 | /* Thus, parsing smaller parts of use tree may require feeding into function | |
2695 | * via parameters (or could handle all in this single function because other | |
2696 | * use tree types aren't recognised as separate in the spec) */ | |
2697 | ||
2698 | // TODO: I think this function is too complex, probably should split it | |
2699 | ||
2700 | location_t locus = lexer.peek_token ()->get_locus (); | |
2701 | ||
2702 | // bool has_path = false; | |
2703 | AST::SimplePath path = parse_simple_path (); | |
2704 | ||
2705 | if (path.is_empty ()) | |
2706 | { | |
2707 | // has no path, so must be glob or nested tree UseTree type | |
2708 | ||
2709 | bool is_global = false; | |
2710 | ||
2711 | // check for global scope resolution operator | |
2712 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION) | |
2713 | { | |
2714 | lexer.skip_token (); | |
2715 | is_global = true; | |
2716 | } | |
2717 | ||
2718 | const_TokenPtr t = lexer.peek_token (); | |
2719 | switch (t->get_id ()) | |
2720 | { | |
2721 | case ASTERISK: | |
2722 | // glob UseTree type | |
2723 | lexer.skip_token (); | |
2724 | ||
2725 | if (is_global) | |
2726 | return std::unique_ptr<AST::UseTreeGlob> ( | |
2727 | new AST::UseTreeGlob (AST::UseTreeGlob::GLOBAL, | |
2728 | AST::SimplePath::create_empty (), locus)); | |
2729 | else | |
2730 | return std::unique_ptr<AST::UseTreeGlob> ( | |
2731 | new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH, | |
2732 | AST::SimplePath::create_empty (), locus)); | |
2733 | case LEFT_CURLY: { | |
2734 | // nested tree UseTree type | |
2735 | lexer.skip_token (); | |
2736 | ||
2737 | std::vector<std::unique_ptr<AST::UseTree>> use_trees; | |
2738 | ||
2739 | const_TokenPtr t = lexer.peek_token (); | |
2740 | while (t->get_id () != RIGHT_CURLY) | |
2741 | { | |
2742 | std::unique_ptr<AST::UseTree> use_tree = parse_use_tree (); | |
2743 | if (use_tree == nullptr) | |
2744 | { | |
2745 | break; | |
2746 | } | |
2747 | ||
2748 | use_trees.push_back (std::move (use_tree)); | |
2749 | ||
2750 | if (lexer.peek_token ()->get_id () != COMMA) | |
2751 | break; | |
2752 | ||
2753 | lexer.skip_token (); | |
2754 | t = lexer.peek_token (); | |
2755 | } | |
2756 | ||
2757 | // skip end curly delimiter | |
2758 | if (!skip_token (RIGHT_CURLY)) | |
2759 | { | |
2760 | // skip after somewhere? | |
2761 | return nullptr; | |
2762 | } | |
2763 | ||
2764 | if (is_global) | |
2765 | return std::unique_ptr<AST::UseTreeList> ( | |
2766 | new AST::UseTreeList (AST::UseTreeList::GLOBAL, | |
2767 | AST::SimplePath::create_empty (), | |
2768 | std::move (use_trees), locus)); | |
2769 | else | |
2770 | return std::unique_ptr<AST::UseTreeList> ( | |
2771 | new AST::UseTreeList (AST::UseTreeList::NO_PATH, | |
2772 | AST::SimplePath::create_empty (), | |
2773 | std::move (use_trees), locus)); | |
2774 | } | |
2775 | case AS: | |
2776 | // this is not allowed | |
2777 | add_error (Error ( | |
2778 | t->get_locus (), | |
2779 | "use declaration with rebind %<as%> requires a valid simple path - " | |
2780 | "none found")); | |
2781 | ||
2782 | skip_after_semicolon (); | |
2783 | return nullptr; | |
2784 | default: | |
2785 | add_error (Error (t->get_locus (), | |
2786 | "unexpected token %qs in use tree with " | |
2787 | "no valid simple path (i.e. list" | |
2788 | " or glob use tree)", | |
2789 | t->get_token_description ())); | |
2790 | ||
2791 | skip_after_semicolon (); | |
2792 | return nullptr; | |
2793 | } | |
2794 | } | |
2795 | else | |
2796 | { | |
2797 | /* Due to aforementioned implementation issues, the trailing :: token is | |
2798 | * consumed by the path, so it can not be used as a disambiguator. | |
2799 | * NOPE, not true anymore - TODO what are the consequences of this? */ | |
2800 | ||
2801 | const_TokenPtr t = lexer.peek_token (); | |
2802 | switch (t->get_id ()) | |
2803 | { | |
2804 | case ASTERISK: | |
2805 | // glob UseTree type | |
2806 | lexer.skip_token (); | |
2807 | ||
2808 | return std::unique_ptr<AST::UseTreeGlob> ( | |
2809 | new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED, | |
2810 | std::move (path), locus)); | |
2811 | case LEFT_CURLY: { | |
2812 | // nested tree UseTree type | |
2813 | lexer.skip_token (); | |
2814 | ||
2815 | std::vector<std::unique_ptr<AST::UseTree>> use_trees; | |
2816 | ||
2817 | // TODO: think of better control structure | |
2818 | const_TokenPtr t = lexer.peek_token (); | |
2819 | while (t->get_id () != RIGHT_CURLY) | |
2820 | { | |
2821 | std::unique_ptr<AST::UseTree> use_tree = parse_use_tree (); | |
2822 | if (use_tree == nullptr) | |
2823 | { | |
2824 | break; | |
2825 | } | |
2826 | ||
2827 | use_trees.push_back (std::move (use_tree)); | |
2828 | ||
2829 | if (lexer.peek_token ()->get_id () != COMMA) | |
2830 | break; | |
2831 | ||
2832 | lexer.skip_token (); | |
2833 | t = lexer.peek_token (); | |
2834 | } | |
2835 | ||
2836 | // skip end curly delimiter | |
2837 | if (!skip_token (RIGHT_CURLY)) | |
2838 | { | |
2839 | // skip after somewhere? | |
2840 | return nullptr; | |
2841 | } | |
2842 | ||
2843 | return std::unique_ptr<AST::UseTreeList> ( | |
2844 | new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED, | |
2845 | std::move (path), std::move (use_trees), | |
2846 | locus)); | |
2847 | } | |
2848 | case AS: { | |
2849 | // rebind UseTree type | |
2850 | lexer.skip_token (); | |
2851 | ||
2852 | const_TokenPtr t = lexer.peek_token (); | |
2853 | switch (t->get_id ()) | |
2854 | { | |
2855 | case IDENTIFIER: | |
2856 | // skip lexer token | |
2857 | lexer.skip_token (); | |
2858 | ||
2859 | return std::unique_ptr<AST::UseTreeRebind> ( | |
2860 | new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER, | |
2861 | std::move (path), locus, t)); | |
2862 | case UNDERSCORE: | |
2863 | // skip lexer token | |
2864 | lexer.skip_token (); | |
2865 | ||
2866 | return std::unique_ptr<AST::UseTreeRebind> ( | |
2867 | new AST::UseTreeRebind (AST::UseTreeRebind::WILDCARD, | |
2868 | std::move (path), locus, | |
2869 | {Values::Keywords::UNDERSCORE, | |
2870 | t->get_locus ()})); | |
2871 | default: | |
2872 | add_error (Error ( | |
2873 | t->get_locus (), | |
2874 | "unexpected token %qs in use tree with as clause - expected " | |
2875 | "identifier or %<_%>", | |
2876 | t->get_token_description ())); | |
2877 | ||
2878 | skip_after_semicolon (); | |
2879 | return nullptr; | |
2880 | } | |
2881 | } | |
2882 | case SEMICOLON: | |
2883 | // rebind UseTree type without rebinding - path only | |
2884 | ||
2885 | // don't skip semicolon - handled in parse_use_tree | |
2886 | // lexer.skip_token(); | |
2887 | ||
2888 | return std::unique_ptr<AST::UseTreeRebind> ( | |
2889 | new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path), | |
2890 | locus)); | |
2891 | case COMMA: | |
2892 | case RIGHT_CURLY: | |
2893 | // this may occur in recursive calls - assume it is ok and ignore it | |
2894 | return std::unique_ptr<AST::UseTreeRebind> ( | |
2895 | new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path), | |
2896 | locus)); | |
2897 | default: | |
2898 | add_error (Error (t->get_locus (), | |
2899 | "unexpected token %qs in use tree with valid path", | |
2900 | t->get_token_description ())); | |
2901 | ||
2902 | // skip_after_semicolon(); | |
2903 | return nullptr; | |
2904 | } | |
2905 | } | |
2906 | } | |
2907 | ||
2908 | // Parses a function (not a method). | |
2909 | template <typename ManagedTokenSource> | |
2910 | std::unique_ptr<AST::Function> | |
2911 | Parser<ManagedTokenSource>::parse_function (AST::Visibility vis, | |
2912 | AST::AttrVec outer_attrs, | |
2913 | bool is_external) | |
2914 | { | |
2915 | location_t locus = lexer.peek_token ()->get_locus (); | |
2916 | // Get qualifiers for function if they exist | |
2917 | AST::FunctionQualifiers qualifiers = parse_function_qualifiers (); | |
2918 | ||
2919 | skip_token (FN_KW); | |
2920 | ||
2921 | // Save function name token | |
2922 | const_TokenPtr function_name_tok = expect_token (IDENTIFIER); | |
2923 | if (function_name_tok == nullptr) | |
2924 | { | |
2925 | skip_after_next_block (); | |
2926 | return nullptr; | |
2927 | } | |
2928 | Identifier function_name{function_name_tok}; | |
2929 | ||
2930 | // parse generic params - if exist | |
2931 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
2932 | = parse_generic_params_in_angles (); | |
2933 | ||
2934 | if (!skip_token (LEFT_PAREN)) | |
2935 | { | |
2936 | Error error (lexer.peek_token ()->get_locus (), | |
2937 | "function declaration missing opening parentheses before " | |
2938 | "parameter list"); | |
2939 | add_error (std::move (error)); | |
2940 | ||
2941 | skip_after_next_block (); | |
2942 | return nullptr; | |
2943 | } | |
2944 | ||
2945 | auto initial_param = parse_self_param (); | |
2946 | ||
2947 | if (!initial_param.has_value () | |
2948 | && initial_param.error () != ParseSelfError::NOT_SELF) | |
2949 | return nullptr; | |
2950 | ||
2951 | if (initial_param.has_value () && lexer.peek_token ()->get_id () == COMMA) | |
2952 | skip_token (); | |
2953 | ||
2954 | // parse function parameters (only if next token isn't right paren) | |
2955 | std::vector<std::unique_ptr<AST::Param>> function_params; | |
2956 | ||
2957 | if (lexer.peek_token ()->get_id () != RIGHT_PAREN) | |
2958 | function_params | |
2959 | = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; }); | |
2960 | ||
2961 | if (initial_param.has_value ()) | |
2962 | function_params.insert (function_params.begin (), | |
2963 | std::move (*initial_param)); | |
2964 | ||
2965 | if (!skip_token (RIGHT_PAREN)) | |
2966 | { | |
2967 | Error error (lexer.peek_token ()->get_locus (), | |
2968 | "function declaration missing closing parentheses after " | |
2969 | "parameter list"); | |
2970 | add_error (std::move (error)); | |
2971 | ||
2972 | skip_after_next_block (); | |
2973 | return nullptr; | |
2974 | } | |
2975 | ||
2976 | // parse function return type - if exists | |
2977 | std::unique_ptr<AST::Type> return_type = parse_function_return_type (); | |
2978 | ||
2979 | // parse where clause - if exists | |
2980 | AST::WhereClause where_clause = parse_where_clause (); | |
2981 | ||
2982 | tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt; | |
2983 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
2984 | lexer.skip_token (); | |
2985 | else | |
2986 | { | |
2987 | std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr (); | |
2988 | if (block_expr != nullptr) | |
2989 | body = std::move (block_expr); | |
2990 | } | |
2991 | ||
2992 | return std::unique_ptr<AST::Function> ( | |
2993 | new AST::Function (std::move (function_name), std::move (qualifiers), | |
2994 | std::move (generic_params), std::move (function_params), | |
2995 | std::move (return_type), std::move (where_clause), | |
2996 | std::move (body), std::move (vis), | |
2997 | std::move (outer_attrs), locus, false, is_external)); | |
2998 | } | |
2999 | ||
3000 | // Parses function or method qualifiers (i.e. const, unsafe, and extern). | |
3001 | template <typename ManagedTokenSource> | |
3002 | AST::FunctionQualifiers | |
3003 | Parser<ManagedTokenSource>::parse_function_qualifiers () | |
3004 | { | |
3005 | Async async_status = Async::No; | |
3006 | Const const_status = Const::No; | |
3007 | Unsafety unsafe_status = Unsafety::Normal; | |
3008 | bool has_extern = false; | |
3009 | std::string abi; | |
3010 | ||
3011 | const_TokenPtr t; | |
3012 | location_t locus; | |
3013 | // Check in order of const, unsafe, then extern | |
3014 | for (int i = 0; i < 2; i++) | |
3015 | { | |
3016 | t = lexer.peek_token (); | |
3017 | locus = t->get_locus (); | |
3018 | ||
3019 | switch (t->get_id ()) | |
3020 | { | |
3021 | case CONST: | |
3022 | lexer.skip_token (); | |
3023 | const_status = Const::Yes; | |
3024 | break; | |
3025 | case ASYNC: | |
3026 | lexer.skip_token (); | |
3027 | async_status = Async::Yes; | |
3028 | break; | |
3029 | default: | |
3030 | // const status is still none | |
3031 | break; | |
3032 | } | |
3033 | } | |
3034 | ||
3035 | if (lexer.peek_token ()->get_id () == UNSAFE) | |
3036 | { | |
3037 | lexer.skip_token (); | |
3038 | unsafe_status = Unsafety::Unsafe; | |
3039 | } | |
3040 | ||
3041 | if (lexer.peek_token ()->get_id () == EXTERN_KW) | |
3042 | { | |
3043 | lexer.skip_token (); | |
3044 | has_extern = true; | |
3045 | ||
3046 | // detect optional abi name | |
3047 | const_TokenPtr next_tok = lexer.peek_token (); | |
3048 | if (next_tok->get_id () == STRING_LITERAL) | |
3049 | { | |
3050 | lexer.skip_token (); | |
3051 | abi = next_tok->get_str (); | |
3052 | } | |
3053 | } | |
3054 | ||
3055 | return AST::FunctionQualifiers (locus, async_status, const_status, | |
3056 | unsafe_status, has_extern, std::move (abi)); | |
3057 | } | |
3058 | ||
3059 | // Parses generic (lifetime or type) params inside angle brackets (optional). | |
3060 | template <typename ManagedTokenSource> | |
3061 | std::vector<std::unique_ptr<AST::GenericParam>> | |
3062 | Parser<ManagedTokenSource>::parse_generic_params_in_angles () | |
3063 | { | |
3064 | if (lexer.peek_token ()->get_id () != LEFT_ANGLE) | |
3065 | { | |
3066 | // seems to be no generic params, so exit with empty vector | |
3067 | return std::vector<std::unique_ptr<AST::GenericParam>> (); | |
3068 | } | |
3069 | lexer.skip_token (); | |
3070 | ||
3071 | // DEBUG: | |
3072 | rust_debug ("skipped left angle in generic param"); | |
3073 | ||
3074 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
3075 | = parse_generic_params (is_right_angle_tok); | |
3076 | ||
3077 | // DEBUG: | |
3078 | rust_debug ("finished parsing actual generic params (i.e. inside angles)"); | |
3079 | ||
3080 | if (!skip_generics_right_angle ()) | |
3081 | { | |
3082 | // DEBUG | |
3083 | rust_debug ("failed to skip generics right angle - returning empty " | |
3084 | "generic params"); | |
3085 | ||
3086 | return std::vector<std::unique_ptr<AST::GenericParam>> (); | |
3087 | } | |
3088 | ||
3089 | return generic_params; | |
3090 | } | |
3091 | ||
3092 | template <typename ManagedTokenSource> | |
3093 | template <typename EndTokenPred> | |
3094 | std::unique_ptr<AST::GenericParam> | |
3095 | Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) | |
3096 | { | |
3097 | auto outer_attrs = parse_outer_attributes (); | |
3098 | std::unique_ptr<AST::GenericParam> param; | |
3099 | auto token = lexer.peek_token (); | |
3100 | ||
3101 | switch (token->get_id ()) | |
3102 | { | |
3103 | case LIFETIME: { | |
3104 | auto lifetime = parse_lifetime (false); | |
3105 | if (!lifetime) | |
3106 | { | |
3107 | rust_error_at ( | |
3108 | token->get_locus (), | |
3109 | "failed to parse lifetime in generic parameter list"); | |
3110 | return nullptr; | |
3111 | } | |
3112 | ||
3113 | std::vector<AST::Lifetime> lifetime_bounds; | |
3114 | if (lexer.peek_token ()->get_id () == COLON) | |
3115 | { | |
3116 | lexer.skip_token (); | |
3117 | // parse required bounds | |
3118 | lifetime_bounds | |
3119 | = parse_lifetime_bounds ([is_end_token] (TokenId id) { | |
3120 | return is_end_token (id) || id == COMMA; | |
3121 | }); | |
3122 | } | |
3123 | ||
3124 | param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam ( | |
3125 | std::move (lifetime.value ()), std::move (lifetime_bounds), | |
3126 | std::move (outer_attrs), token->get_locus ())); | |
3127 | break; | |
3128 | } | |
3129 | case IDENTIFIER: { | |
3130 | auto type_ident = token->get_str (); | |
3131 | lexer.skip_token (); | |
3132 | ||
3133 | std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds; | |
3134 | if (lexer.peek_token ()->get_id () == COLON) | |
3135 | { | |
3136 | lexer.skip_token (); | |
3137 | ||
3138 | // parse optional type param bounds | |
3139 | type_param_bounds = parse_type_param_bounds (); | |
3140 | } | |
3141 | ||
3142 | std::unique_ptr<AST::Type> type = nullptr; | |
3143 | if (lexer.peek_token ()->get_id () == EQUAL) | |
3144 | { | |
3145 | lexer.skip_token (); | |
3146 | ||
3147 | // parse required type | |
3148 | type = parse_type (); | |
3149 | if (!type) | |
3150 | { | |
3151 | rust_error_at ( | |
3152 | lexer.peek_token ()->get_locus (), | |
3153 | "failed to parse type in type param in generic params"); | |
3154 | return nullptr; | |
3155 | } | |
3156 | } | |
3157 | ||
3158 | param = std::unique_ptr<AST::TypeParam> ( | |
3159 | new AST::TypeParam (std::move (type_ident), token->get_locus (), | |
3160 | std::move (type_param_bounds), std::move (type), | |
3161 | std::move (outer_attrs))); | |
3162 | break; | |
3163 | } | |
3164 | case CONST: { | |
3165 | lexer.skip_token (); | |
3166 | ||
3167 | auto name_token = expect_token (IDENTIFIER); | |
3168 | ||
3169 | if (!name_token || !expect_token (COLON)) | |
3170 | return nullptr; | |
3171 | ||
3172 | auto type = parse_type (); | |
3173 | if (!type) | |
3174 | return nullptr; | |
3175 | ||
3176 | // optional default value | |
3177 | tl::optional<AST::GenericArg> default_expr = tl::nullopt; | |
3178 | if (lexer.peek_token ()->get_id () == EQUAL) | |
3179 | { | |
3180 | lexer.skip_token (); | |
3181 | auto tok = lexer.peek_token (); | |
3182 | default_expr = parse_generic_arg (); | |
3183 | ||
3184 | if (!default_expr) | |
3185 | { | |
3186 | rust_error_at (tok->get_locus (), | |
3187 | "invalid token for start of default value for " | |
3188 | "const generic parameter: expected %<block%>, " | |
3189 | "%<identifier%> or %<literal%>, got %qs", | |
3190 | token_id_to_str (tok->get_id ())); | |
3191 | return nullptr; | |
3192 | } | |
3193 | ||
3194 | // At this point, we *know* that we are parsing a const | |
3195 | // expression | |
3196 | if (default_expr.value ().get_kind () | |
3197 | == AST::GenericArg::Kind::Either) | |
3198 | default_expr = default_expr.value ().disambiguate_to_const (); | |
3199 | } | |
3200 | ||
3201 | param = std::unique_ptr<AST::ConstGenericParam> ( | |
3202 | new AST::ConstGenericParam (name_token->get_str (), std::move (type), | |
3203 | default_expr, std::move (outer_attrs), | |
3204 | token->get_locus ())); | |
3205 | ||
3206 | break; | |
3207 | } | |
3208 | default: | |
3209 | // FIXME: Can we clean this last call with a method call? | |
3210 | rust_error_at (token->get_locus (), | |
3211 | "unexpected token when parsing generic parameters: %qs", | |
3212 | token->as_string ().c_str ()); | |
3213 | return nullptr; | |
3214 | } | |
3215 | ||
3216 | return param; | |
3217 | } | |
3218 | ||
3219 | /* Parse generic (lifetime or type) params NOT INSIDE ANGLE BRACKETS!!! Almost | |
3220 | * always parse_generic_params_in_angles is what is wanted. */ | |
3221 | template <typename ManagedTokenSource> | |
3222 | template <typename EndTokenPred> | |
3223 | std::vector<std::unique_ptr<AST::GenericParam>> | |
3224 | Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token) | |
3225 | { | |
3226 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params; | |
3227 | ||
3228 | /* can't parse lifetime and type params separately due to lookahead issues | |
3229 | * thus, parse them all here */ | |
3230 | ||
3231 | /* HACK: used to retain attribute data if a lifetime param is tentatively | |
3232 | * parsed but it turns out to be type param */ | |
3233 | AST::Attribute parsed_outer_attr = AST::Attribute::create_empty (); | |
3234 | ||
3235 | // Did we parse a generic type param yet | |
3236 | auto type_seen = false; | |
3237 | // Did the user write a lifetime parameter after a type one | |
3238 | auto order_error = false; | |
3239 | ||
3240 | // parse lifetime params | |
3241 | while (!is_end_token (lexer.peek_token ()->get_id ())) | |
3242 | { | |
3243 | auto param = parse_generic_param (is_end_token); | |
3244 | if (param) | |
3245 | { | |
3246 | // TODO: Handle `Const` here as well if necessary | |
3247 | if (param->get_kind () == AST::GenericParam::Kind::Type) | |
3248 | type_seen = true; | |
3249 | else if (param->get_kind () == AST::GenericParam::Kind::Lifetime | |
3250 | && type_seen) | |
3251 | order_error = true; | |
3252 | ||
3253 | generic_params.emplace_back (std::move (param)); | |
3254 | maybe_skip_token (COMMA); | |
3255 | } | |
3256 | else | |
3257 | break; | |
3258 | } | |
3259 | ||
3260 | // FIXME: Add reordering hint | |
3261 | if (order_error) | |
3262 | { | |
3263 | Error error (generic_params.front ()->get_locus (), | |
3264 | "invalid order for generic parameters: lifetime parameters " | |
3265 | "must be declared prior to type and const parameters"); | |
3266 | add_error (std::move (error)); | |
3267 | } | |
3268 | ||
3269 | generic_params.shrink_to_fit (); | |
3270 | return generic_params; | |
3271 | } | |
3272 | ||
3273 | /* Parses lifetime generic parameters (pointers). Will also consume any | |
3274 | * trailing comma. No extra checks for end token. */ | |
3275 | template <typename ManagedTokenSource> | |
3276 | std::vector<std::unique_ptr<AST::LifetimeParam>> | |
3277 | Parser<ManagedTokenSource>::parse_lifetime_params () | |
3278 | { | |
3279 | std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params; | |
3280 | ||
3281 | while (lexer.peek_token ()->get_id () != END_OF_FILE) | |
3282 | { | |
3283 | auto lifetime_param = parse_lifetime_param (); | |
3284 | ||
3285 | if (!lifetime_param) | |
3286 | { | |
3287 | // can't treat as error as only way to get out with trailing comma | |
3288 | break; | |
3289 | } | |
3290 | ||
3291 | lifetime_params.push_back (std::unique_ptr<AST::LifetimeParam> ( | |
3292 | new AST::LifetimeParam (std::move (lifetime_param.value ())))); | |
3293 | ||
3294 | if (lexer.peek_token ()->get_id () != COMMA) | |
3295 | break; | |
3296 | ||
3297 | // skip commas, including trailing commas | |
3298 | lexer.skip_token (); | |
3299 | } | |
3300 | ||
3301 | lifetime_params.shrink_to_fit (); | |
3302 | ||
3303 | return lifetime_params; | |
3304 | } | |
3305 | ||
3306 | /* Parses lifetime generic parameters (pointers). Will also consume any | |
3307 | * trailing comma. Has extra is_end_token predicate checking. */ | |
3308 | template <typename ManagedTokenSource> | |
3309 | template <typename EndTokenPred> | |
3310 | std::vector<std::unique_ptr<AST::LifetimeParam>> | |
3311 | Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token) | |
3312 | { | |
3313 | std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params; | |
3314 | ||
3315 | // if end_token is not specified, it defaults to EOF, so should work fine | |
3316 | while (!is_end_token (lexer.peek_token ()->get_id ())) | |
3317 | { | |
3318 | auto lifetime_param = parse_lifetime_param (); | |
3319 | ||
3320 | if (!lifetime_param) | |
3321 | { | |
3322 | /* TODO: is it worth throwing away all lifetime params just because | |
3323 | * one failed? */ | |
3324 | Error error (lexer.peek_token ()->get_locus (), | |
3325 | "failed to parse lifetime param in lifetime params"); | |
3326 | add_error (std::move (error)); | |
3327 | ||
3328 | return {}; | |
3329 | } | |
3330 | ||
3331 | lifetime_params.push_back (std::unique_ptr<AST::LifetimeParam> ( | |
3332 | new AST::LifetimeParam (std::move (lifetime_param)))); | |
3333 | ||
3334 | if (lexer.peek_token ()->get_id () != COMMA) | |
3335 | break; | |
3336 | ||
3337 | // skip commas, including trailing commas | |
3338 | lexer.skip_token (); | |
3339 | } | |
3340 | ||
3341 | lifetime_params.shrink_to_fit (); | |
3342 | ||
3343 | return lifetime_params; | |
3344 | } | |
3345 | ||
3346 | /* Parses lifetime generic parameters (objects). Will also consume any | |
3347 | * trailing comma. No extra checks for end token. | |
3348 | * TODO: is this best solution? implements most of the same algorithm. */ | |
3349 | template <typename ManagedTokenSource> | |
3350 | std::vector<AST::LifetimeParam> | |
3351 | Parser<ManagedTokenSource>::parse_lifetime_params_objs () | |
3352 | { | |
3353 | std::vector<AST::LifetimeParam> lifetime_params; | |
3354 | ||
3355 | // bad control structure as end token cannot be guaranteed | |
3356 | while (true) | |
3357 | { | |
3358 | auto lifetime_param = parse_lifetime_param (); | |
3359 | ||
3360 | if (!lifetime_param) | |
3361 | { | |
3362 | // not an error as only way to exit if trailing comma | |
3363 | break; | |
3364 | } | |
3365 | ||
3366 | lifetime_params.push_back (std::move (lifetime_param)); | |
3367 | ||
3368 | if (lexer.peek_token ()->get_id () != COMMA) | |
3369 | break; | |
3370 | ||
3371 | // skip commas, including trailing commas | |
3372 | lexer.skip_token (); | |
3373 | } | |
3374 | ||
3375 | lifetime_params.shrink_to_fit (); | |
3376 | ||
3377 | return lifetime_params; | |
3378 | } | |
3379 | ||
3380 | /* Parses lifetime generic parameters (objects). Will also consume any | |
3381 | * trailing comma. Has extra is_end_token predicate checking. | |
3382 | * TODO: is this best solution? implements most of the same algorithm. */ | |
3383 | template <typename ManagedTokenSource> | |
3384 | template <typename EndTokenPred> | |
3385 | std::vector<AST::LifetimeParam> | |
3386 | Parser<ManagedTokenSource>::parse_lifetime_params_objs ( | |
3387 | EndTokenPred is_end_token) | |
3388 | { | |
3389 | std::vector<AST::LifetimeParam> lifetime_params; | |
3390 | ||
3391 | while (!is_end_token (lexer.peek_token ()->get_id ())) | |
3392 | { | |
3393 | auto lifetime_param = parse_lifetime_param (); | |
3394 | ||
3395 | if (!lifetime_param) | |
3396 | { | |
3397 | /* TODO: is it worth throwing away all lifetime params just because | |
3398 | * one failed? */ | |
3399 | Error error (lexer.peek_token ()->get_locus (), | |
3400 | "failed to parse lifetime param in lifetime params"); | |
3401 | add_error (std::move (error)); | |
3402 | ||
3403 | return {}; | |
3404 | } | |
3405 | ||
3406 | lifetime_params.push_back (std::move (lifetime_param.value ())); | |
3407 | ||
3408 | if (lexer.peek_token ()->get_id () != COMMA) | |
3409 | break; | |
3410 | ||
3411 | // skip commas, including trailing commas | |
3412 | lexer.skip_token (); | |
3413 | } | |
3414 | ||
3415 | lifetime_params.shrink_to_fit (); | |
3416 | ||
3417 | return lifetime_params; | |
3418 | } | |
3419 | ||
3420 | /* Parses a sequence of a certain grammar rule in object form (not pointer or | |
3421 | * smart pointer), delimited by commas and ending when 'is_end_token' is | |
3422 | * satisfied (templated). Will also consume any trailing comma. | |
3423 | * FIXME: this cannot be used due to member function pointer problems (i.e. | |
3424 | * parsing_function cannot be specified properly) */ | |
3425 | template <typename ManagedTokenSource> | |
3426 | template <typename ParseFunction, typename EndTokenPred> | |
3427 | auto | |
3428 | Parser<ManagedTokenSource>::parse_non_ptr_sequence ( | |
3429 | ParseFunction parsing_function, EndTokenPred is_end_token, | |
3430 | std::string error_msg) -> std::vector<decltype (parsing_function ())> | |
3431 | { | |
3432 | std::vector<decltype (parsing_function ())> params; | |
3433 | ||
3434 | while (!is_end_token (lexer.peek_token ()->get_id ())) | |
3435 | { | |
3436 | auto param = parsing_function (); | |
3437 | ||
3438 | if (param.is_error ()) | |
3439 | { | |
3440 | // TODO: is it worth throwing away all params just because one | |
3441 | // failed? | |
3442 | Error error (lexer.peek_token ()->get_locus (), | |
3443 | std::move (error_msg)); | |
3444 | add_error (std::move (error)); | |
3445 | ||
3446 | return {}; | |
3447 | } | |
3448 | ||
3449 | params.push_back (std::move (param)); | |
3450 | ||
3451 | if (lexer.peek_token ()->get_id () != COMMA) | |
3452 | break; | |
3453 | ||
3454 | // skip commas, including trailing commas | |
3455 | lexer.skip_token (); | |
3456 | } | |
3457 | ||
3458 | params.shrink_to_fit (); | |
3459 | ||
3460 | return params; | |
3461 | } | |
3462 | ||
3463 | /* Parses a single lifetime generic parameter (not including comma). */ | |
3464 | template <typename ManagedTokenSource> | |
3465 | tl::expected<AST::LifetimeParam, ParseLifetimeParamError> | |
3466 | Parser<ManagedTokenSource>::parse_lifetime_param () | |
3467 | { | |
3468 | // parse outer attributes, which are optional and may not exist | |
3469 | auto outer_attrs = parse_outer_attributes (); | |
3470 | ||
3471 | // save lifetime token - required | |
3472 | const_TokenPtr lifetime_tok = lexer.peek_token (); | |
3473 | if (lifetime_tok->get_id () != LIFETIME) | |
3474 | { | |
3475 | // if lifetime is missing, must not be a lifetime param, so return error | |
3476 | return tl::make_unexpected<ParseLifetimeParamError> ({}); | |
3477 | } | |
3478 | lexer.skip_token (); | |
3479 | AST::Lifetime lifetime (AST::Lifetime::NAMED, lifetime_tok->get_str (), | |
3480 | lifetime_tok->get_locus ()); | |
3481 | ||
3482 | // parse lifetime bounds, if it exists | |
3483 | std::vector<AST::Lifetime> lifetime_bounds; | |
3484 | if (lexer.peek_token ()->get_id () == COLON) | |
3485 | { | |
3486 | // parse lifetime bounds | |
3487 | lifetime_bounds = parse_lifetime_bounds (); | |
3488 | // TODO: have end token passed in? | |
3489 | } | |
3490 | ||
3491 | return AST::LifetimeParam (std::move (lifetime), std::move (lifetime_bounds), | |
3492 | std::move (outer_attrs), | |
3493 | lifetime_tok->get_locus ()); | |
3494 | } | |
3495 | ||
3496 | // Parses type generic parameters. Will also consume any trailing comma. | |
3497 | template <typename ManagedTokenSource> | |
3498 | std::vector<std::unique_ptr<AST::TypeParam>> | |
3499 | Parser<ManagedTokenSource>::parse_type_params () | |
3500 | { | |
3501 | std::vector<std::unique_ptr<AST::TypeParam>> type_params; | |
3502 | ||
3503 | // infinite loop with break on failure as no info on ending token | |
3504 | while (true) | |
3505 | { | |
3506 | std::unique_ptr<AST::TypeParam> type_param = parse_type_param (); | |
3507 | ||
3508 | if (type_param == nullptr) | |
3509 | { | |
3510 | // break if fails to parse | |
3511 | break; | |
3512 | } | |
3513 | ||
3514 | type_params.push_back (std::move (type_param)); | |
3515 | ||
3516 | if (lexer.peek_token ()->get_id () != COMMA) | |
3517 | break; | |
3518 | ||
3519 | // skip commas, including trailing commas | |
3520 | lexer.skip_token (); | |
3521 | } | |
3522 | ||
3523 | type_params.shrink_to_fit (); | |
3524 | return type_params; | |
3525 | } | |
3526 | ||
3527 | // Parses type generic parameters. Will also consume any trailing comma. | |
3528 | template <typename ManagedTokenSource> | |
3529 | template <typename EndTokenPred> | |
3530 | std::vector<std::unique_ptr<AST::TypeParam>> | |
3531 | Parser<ManagedTokenSource>::parse_type_params (EndTokenPred is_end_token) | |
3532 | { | |
3533 | std::vector<std::unique_ptr<AST::TypeParam>> type_params; | |
3534 | ||
3535 | while (!is_end_token (lexer.peek_token ()->get_id ())) | |
3536 | { | |
3537 | std::unique_ptr<AST::TypeParam> type_param = parse_type_param (); | |
3538 | ||
3539 | if (type_param == nullptr) | |
3540 | { | |
3541 | Error error (lexer.peek_token ()->get_locus (), | |
3542 | "failed to parse type param in type params"); | |
3543 | add_error (std::move (error)); | |
3544 | ||
3545 | return {}; | |
3546 | } | |
3547 | ||
3548 | type_params.push_back (std::move (type_param)); | |
3549 | ||
3550 | if (lexer.peek_token ()->get_id () != COMMA) | |
3551 | break; | |
3552 | ||
3553 | // skip commas, including trailing commas | |
3554 | lexer.skip_token (); | |
3555 | } | |
3556 | ||
3557 | type_params.shrink_to_fit (); | |
3558 | return type_params; | |
3559 | /* TODO: this shares most code with parse_lifetime_params - good place to | |
3560 | * use template (i.e. parse_non_ptr_sequence if doable) */ | |
3561 | } | |
3562 | ||
3563 | /* Parses a single type (generic) parameter, not including commas. May change | |
3564 | * to return value. */ | |
3565 | template <typename ManagedTokenSource> | |
3566 | std::unique_ptr<AST::TypeParam> | |
3567 | Parser<ManagedTokenSource>::parse_type_param () | |
3568 | { | |
3569 | // parse outer attributes, which are optional and may not exist | |
3570 | auto outer_attrs = parse_outer_attributes (); | |
3571 | ||
3572 | const_TokenPtr identifier_tok = lexer.peek_token (); | |
3573 | if (identifier_tok->get_id () != IDENTIFIER) | |
3574 | { | |
3575 | // return null as type param can't exist without this required | |
3576 | // identifier | |
3577 | return nullptr; | |
3578 | } | |
3579 | Identifier ident{identifier_tok}; | |
3580 | lexer.skip_token (); | |
3581 | ||
3582 | // parse type param bounds (if they exist) | |
3583 | std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds; | |
3584 | if (lexer.peek_token ()->get_id () == COLON) | |
3585 | { | |
3586 | lexer.skip_token (); | |
3587 | ||
3588 | // parse type param bounds, which may or may not exist | |
3589 | type_param_bounds = parse_type_param_bounds (); | |
3590 | } | |
3591 | ||
3592 | // parse type (if it exists) | |
3593 | std::unique_ptr<AST::Type> type = nullptr; | |
3594 | if (lexer.peek_token ()->get_id () == EQUAL) | |
3595 | { | |
3596 | lexer.skip_token (); | |
3597 | ||
3598 | // parse type (now required) | |
3599 | type = parse_type (); | |
3600 | if (type == nullptr) | |
3601 | { | |
3602 | Error error (lexer.peek_token ()->get_locus (), | |
3603 | "failed to parse type in type param"); | |
3604 | add_error (std::move (error)); | |
3605 | ||
3606 | return nullptr; | |
3607 | } | |
3608 | } | |
3609 | ||
3610 | return std::unique_ptr<AST::TypeParam> ( | |
3611 | new AST::TypeParam (std::move (ident), identifier_tok->get_locus (), | |
3612 | std::move (type_param_bounds), std::move (type), | |
3613 | std::move (outer_attrs))); | |
3614 | } | |
3615 | ||
3616 | /* Parses regular (i.e. non-generic) parameters in functions or methods. Also | |
3617 | * has end token handling. */ | |
3618 | template <typename ManagedTokenSource> | |
3619 | template <typename EndTokenPred> | |
3620 | std::vector<std::unique_ptr<AST::Param>> | |
3621 | Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token) | |
3622 | { | |
3623 | std::vector<std::unique_ptr<AST::Param>> params; | |
3624 | ||
3625 | if (is_end_token (lexer.peek_token ()->get_id ())) | |
3626 | return params; | |
3627 | ||
3628 | auto initial_param = parse_function_param (); | |
3629 | ||
3630 | // Return empty parameter list if no parameter there | |
3631 | if (initial_param == nullptr) | |
3632 | { | |
3633 | // TODO: is this an error? | |
3634 | return params; | |
3635 | } | |
3636 | ||
3637 | params.push_back (std::move (initial_param)); | |
3638 | ||
3639 | // maybe think of a better control structure here - do-while with an initial | |
3640 | // error state? basically, loop through parameter list until can't find any | |
3641 | // more params | |
3642 | const_TokenPtr t = lexer.peek_token (); | |
3643 | while (t->get_id () == COMMA) | |
3644 | { | |
3645 | // skip comma if applies | |
3646 | lexer.skip_token (); | |
3647 | ||
3648 | // TODO: strictly speaking, shouldn't there be no trailing comma? | |
3649 | if (is_end_token (lexer.peek_token ()->get_id ())) | |
3650 | break; | |
3651 | ||
3652 | // now, as right paren would break, function param is required | |
3653 | auto param = parse_function_param (); | |
3654 | if (param == nullptr) | |
3655 | { | |
3656 | Error error (lexer.peek_token ()->get_locus (), | |
3657 | "failed to parse function param (in function params)"); | |
3658 | add_error (std::move (error)); | |
3659 | ||
3660 | // skip somewhere? | |
3661 | return std::vector<std::unique_ptr<AST::Param>> (); | |
3662 | } | |
3663 | ||
3664 | params.push_back (std::move (param)); | |
3665 | ||
3666 | t = lexer.peek_token (); | |
3667 | } | |
3668 | ||
3669 | params.shrink_to_fit (); | |
3670 | return params; | |
3671 | } | |
3672 | ||
3673 | /* Parses a single regular (i.e. non-generic) parameter in a function or | |
3674 | * method, i.e. the "name: type" bit. Also handles it not existing. */ | |
3675 | template <typename ManagedTokenSource> | |
3676 | std::unique_ptr<AST::Param> | |
3677 | Parser<ManagedTokenSource>::parse_function_param () | |
3678 | { | |
3679 | // parse outer attributes if they exist | |
3680 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
3681 | ||
3682 | // TODO: should saved location be at start of outer attributes or pattern? | |
3683 | location_t locus = lexer.peek_token ()->get_locus (); | |
3684 | ||
3685 | if (lexer.peek_token ()->get_id () == ELLIPSIS) // Unnamed variadic | |
3686 | { | |
3687 | lexer.skip_token (); // Skip ellipsis | |
3688 | return std::make_unique<AST::VariadicParam> ( | |
3689 | AST::VariadicParam (std::move (outer_attrs), locus)); | |
3690 | } | |
3691 | ||
3692 | std::unique_ptr<AST::Pattern> param_pattern = parse_pattern (); | |
3693 | ||
3694 | // create error function param if it doesn't exist | |
3695 | if (param_pattern == nullptr) | |
3696 | { | |
3697 | // skip after something | |
3698 | return nullptr; | |
3699 | } | |
3700 | ||
3701 | if (!skip_token (COLON)) | |
3702 | { | |
3703 | // skip after something | |
3704 | return nullptr; | |
3705 | } | |
3706 | ||
3707 | if (lexer.peek_token ()->get_id () == ELLIPSIS) // Named variadic | |
3708 | { | |
3709 | lexer.skip_token (); // Skip ellipsis | |
3710 | return std::make_unique<AST::VariadicParam> ( | |
3711 | AST::VariadicParam (std::move (param_pattern), std::move (outer_attrs), | |
3712 | locus)); | |
3713 | } | |
3714 | else | |
3715 | { | |
3716 | std::unique_ptr<AST::Type> param_type = parse_type (); | |
3717 | if (param_type == nullptr) | |
3718 | { | |
3719 | return nullptr; | |
3720 | } | |
3721 | return std::make_unique<AST::FunctionParam> ( | |
3722 | AST::FunctionParam (std::move (param_pattern), std::move (param_type), | |
3723 | std::move (outer_attrs), locus)); | |
3724 | } | |
3725 | } | |
3726 | ||
3727 | /* Parses a function or method return type syntactical construction. Also | |
3728 | * handles a function return type not existing. */ | |
3729 | template <typename ManagedTokenSource> | |
3730 | std::unique_ptr<AST::Type> | |
3731 | Parser<ManagedTokenSource>::parse_function_return_type () | |
3732 | { | |
3733 | if (lexer.peek_token ()->get_id () != RETURN_TYPE) | |
3734 | return nullptr; | |
3735 | ||
3736 | // skip return type, as it now obviously exists | |
3737 | lexer.skip_token (); | |
3738 | ||
3739 | std::unique_ptr<AST::Type> type = parse_type (); | |
3740 | ||
3741 | return type; | |
3742 | } | |
3743 | ||
3744 | /* Parses a "where clause" (in a function, struct, method, etc.). Also handles | |
3745 | * a where clause not existing, in which it will return | |
3746 | * WhereClause::create_empty(), which can be checked via | |
3747 | * WhereClause::is_empty(). */ | |
3748 | template <typename ManagedTokenSource> | |
3749 | AST::WhereClause | |
3750 | Parser<ManagedTokenSource>::parse_where_clause () | |
3751 | { | |
3752 | const_TokenPtr where_tok = lexer.peek_token (); | |
3753 | if (where_tok->get_id () != WHERE) | |
3754 | { | |
3755 | // where clause doesn't exist, so create empty one | |
3756 | return AST::WhereClause::create_empty (); | |
3757 | } | |
3758 | ||
3759 | lexer.skip_token (); | |
3760 | ||
3761 | /* parse where clause items - this is not a separate rule in the reference | |
3762 | * so won't be here */ | |
3763 | std::vector<std::unique_ptr<AST::WhereClauseItem>> where_clause_items; | |
3764 | ||
3765 | std::vector<AST::LifetimeParam> for_lifetimes; | |
3766 | if (lexer.peek_token ()->get_id () == FOR) | |
3767 | for_lifetimes = parse_for_lifetimes (); | |
3768 | ||
3769 | /* HACK: where clauses end with a right curly or semicolon or equals in all | |
3770 | * uses currently */ | |
3771 | const_TokenPtr t = lexer.peek_token (); | |
3772 | while (t->get_id () != LEFT_CURLY && t->get_id () != SEMICOLON | |
3773 | && t->get_id () != EQUAL) | |
3774 | { | |
3775 | std::unique_ptr<AST::WhereClauseItem> where_clause_item | |
3776 | = parse_where_clause_item (for_lifetimes); | |
3777 | ||
3778 | if (where_clause_item == nullptr) | |
3779 | { | |
3780 | Error error (t->get_locus (), "failed to parse where clause item"); | |
3781 | add_error (std::move (error)); | |
3782 | ||
3783 | return AST::WhereClause::create_empty (); | |
3784 | } | |
3785 | ||
3786 | where_clause_items.push_back (std::move (where_clause_item)); | |
3787 | ||
3788 | // also skip comma if it exists | |
3789 | if (lexer.peek_token ()->get_id () != COMMA) | |
3790 | break; | |
3791 | ||
3792 | lexer.skip_token (); | |
3793 | t = lexer.peek_token (); | |
3794 | } | |
3795 | ||
3796 | where_clause_items.shrink_to_fit (); | |
3797 | return AST::WhereClause (std::move (where_clause_items)); | |
3798 | } | |
3799 | ||
3800 | /* Parses a where clause item (lifetime or type bound). Does not parse any | |
3801 | * commas. */ | |
3802 | template <typename ManagedTokenSource> | |
3803 | std::unique_ptr<AST::WhereClauseItem> | |
3804 | Parser<ManagedTokenSource>::parse_where_clause_item ( | |
3805 | const std::vector<AST::LifetimeParam> &outer_for_lifetimes) | |
3806 | { | |
3807 | // shitty cheat way of determining lifetime or type bound - test for | |
3808 | // lifetime | |
3809 | const_TokenPtr t = lexer.peek_token (); | |
3810 | ||
3811 | if (t->get_id () == LIFETIME) | |
3812 | return parse_lifetime_where_clause_item (); | |
3813 | else | |
3814 | return parse_type_bound_where_clause_item (outer_for_lifetimes); | |
3815 | } | |
3816 | ||
3817 | // Parses a lifetime where clause item. | |
3818 | template <typename ManagedTokenSource> | |
3819 | std::unique_ptr<AST::LifetimeWhereClauseItem> | |
3820 | Parser<ManagedTokenSource>::parse_lifetime_where_clause_item () | |
3821 | { | |
3822 | auto parsed_lifetime = parse_lifetime (false); | |
3823 | if (!parsed_lifetime) | |
3824 | { | |
3825 | // TODO: error here? | |
3826 | return nullptr; | |
3827 | } | |
3828 | auto lifetime = parsed_lifetime.value (); | |
3829 | ||
3830 | if (!skip_token (COLON)) | |
3831 | { | |
3832 | // TODO: skip after somewhere | |
3833 | return nullptr; | |
3834 | } | |
3835 | ||
3836 | std::vector<AST::Lifetime> lifetime_bounds = parse_lifetime_bounds (); | |
3837 | // TODO: have end token passed in? | |
3838 | ||
3839 | location_t locus = lifetime.get_locus (); | |
3840 | ||
3841 | return std::unique_ptr<AST::LifetimeWhereClauseItem> ( | |
3842 | new AST::LifetimeWhereClauseItem (std::move (lifetime), | |
3843 | std::move (lifetime_bounds), locus)); | |
3844 | } | |
3845 | ||
3846 | // Parses a type bound where clause item. | |
3847 | template <typename ManagedTokenSource> | |
3848 | std::unique_ptr<AST::TypeBoundWhereClauseItem> | |
3849 | Parser<ManagedTokenSource>::parse_type_bound_where_clause_item ( | |
3850 | const std::vector<AST::LifetimeParam> &outer_for_lifetimes) | |
3851 | { | |
3852 | std::vector<AST::LifetimeParam> for_lifetimes = outer_for_lifetimes; | |
3853 | ||
3854 | std::unique_ptr<AST::Type> type = parse_type (); | |
3855 | if (type == nullptr) | |
3856 | { | |
3857 | return nullptr; | |
3858 | } | |
3859 | ||
3860 | if (!skip_token (COLON)) | |
3861 | { | |
3862 | // TODO: skip after somewhere | |
3863 | return nullptr; | |
3864 | } | |
3865 | ||
3866 | if (lexer.peek_token ()->get_id () == FOR) | |
3867 | { | |
3868 | auto for_lifetimes_inner = parse_for_lifetimes (); | |
3869 | for_lifetimes.insert (for_lifetimes.end (), for_lifetimes_inner.begin (), | |
3870 | for_lifetimes_inner.end ()); | |
3871 | } | |
3872 | ||
3873 | // parse type param bounds if they exist | |
3874 | std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds | |
3875 | = parse_type_param_bounds (); | |
3876 | ||
3877 | location_t locus = lexer.peek_token ()->get_locus (); | |
3878 | ||
3879 | return std::unique_ptr<AST::TypeBoundWhereClauseItem> ( | |
3880 | new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes), | |
3881 | std::move (type), | |
3882 | std::move (type_param_bounds), locus)); | |
3883 | } | |
3884 | ||
3885 | // Parses a for lifetimes clause, including the for keyword and angle | |
3886 | // brackets. | |
3887 | template <typename ManagedTokenSource> | |
3888 | std::vector<AST::LifetimeParam> | |
3889 | Parser<ManagedTokenSource>::parse_for_lifetimes () | |
3890 | { | |
3891 | std::vector<AST::LifetimeParam> params; | |
3892 | ||
3893 | if (!skip_token (FOR)) | |
3894 | { | |
3895 | // skip after somewhere? | |
3896 | return params; | |
3897 | } | |
3898 | ||
3899 | if (!skip_token (LEFT_ANGLE)) | |
3900 | { | |
3901 | // skip after somewhere? | |
3902 | return params; | |
3903 | } | |
3904 | ||
3905 | /* cannot specify end token due to parsing problems with '>' tokens being | |
3906 | * nested */ | |
3907 | params = parse_lifetime_params_objs (is_right_angle_tok); | |
3908 | ||
3909 | if (!skip_generics_right_angle ()) | |
3910 | { | |
3911 | // DEBUG | |
3912 | rust_debug ("failed to skip generics right angle after (supposedly) " | |
3913 | "finished parsing where clause items"); | |
3914 | // ok, well this gets called. | |
3915 | ||
3916 | // skip after somewhere? | |
3917 | return params; | |
3918 | } | |
3919 | ||
3920 | return params; | |
3921 | } | |
3922 | ||
3923 | // Parses type parameter bounds in where clause or generic arguments. | |
3924 | template <typename ManagedTokenSource> | |
3925 | std::vector<std::unique_ptr<AST::TypeParamBound>> | |
3926 | Parser<ManagedTokenSource>::parse_type_param_bounds () | |
3927 | { | |
3928 | std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds; | |
3929 | ||
3930 | std::unique_ptr<AST::TypeParamBound> initial_bound | |
3931 | = parse_type_param_bound (); | |
3932 | ||
3933 | // quick exit if null | |
3934 | if (initial_bound == nullptr) | |
3935 | { | |
3936 | /* error? type param bounds must have at least one term, but are bounds | |
3937 | * optional? */ | |
3938 | return type_param_bounds; | |
3939 | } | |
3940 | type_param_bounds.push_back (std::move (initial_bound)); | |
3941 | ||
3942 | while (lexer.peek_token ()->get_id () == PLUS) | |
3943 | { | |
3944 | lexer.skip_token (); | |
3945 | ||
3946 | std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound (); | |
3947 | if (bound == nullptr) | |
3948 | { | |
3949 | /* not an error: bound is allowed to be null as trailing plus is | |
3950 | * allowed */ | |
3951 | return type_param_bounds; | |
3952 | } | |
3953 | ||
3954 | type_param_bounds.push_back (std::move (bound)); | |
3955 | } | |
3956 | ||
3957 | type_param_bounds.shrink_to_fit (); | |
3958 | return type_param_bounds; | |
3959 | } | |
3960 | ||
3961 | /* Parses type parameter bounds in where clause or generic arguments, with end | |
3962 | * token handling. */ | |
3963 | template <typename ManagedTokenSource> | |
3964 | template <typename EndTokenPred> | |
3965 | std::vector<std::unique_ptr<AST::TypeParamBound>> | |
3966 | Parser<ManagedTokenSource>::parse_type_param_bounds (EndTokenPred is_end_token) | |
3967 | { | |
3968 | std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds; | |
3969 | ||
3970 | std::unique_ptr<AST::TypeParamBound> initial_bound | |
3971 | = parse_type_param_bound (); | |
3972 | ||
3973 | // quick exit if null | |
3974 | if (initial_bound == nullptr) | |
3975 | { | |
3976 | /* error? type param bounds must have at least one term, but are bounds | |
3977 | * optional? */ | |
3978 | return type_param_bounds; | |
3979 | } | |
3980 | type_param_bounds.push_back (std::move (initial_bound)); | |
3981 | ||
3982 | while (lexer.peek_token ()->get_id () == PLUS) | |
3983 | { | |
3984 | lexer.skip_token (); | |
3985 | ||
3986 | // break if end token character | |
3987 | if (is_end_token (lexer.peek_token ()->get_id ())) | |
3988 | break; | |
3989 | ||
3990 | std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound (); | |
3991 | if (bound == nullptr) | |
3992 | { | |
3993 | // TODO how wise is it to ditch all bounds if only one failed? | |
3994 | Error error (lexer.peek_token ()->get_locus (), | |
3995 | "failed to parse type param bound in type param bounds"); | |
3996 | add_error (std::move (error)); | |
3997 | ||
3998 | return {}; | |
3999 | } | |
4000 | ||
4001 | type_param_bounds.push_back (std::move (bound)); | |
4002 | } | |
4003 | ||
4004 | type_param_bounds.shrink_to_fit (); | |
4005 | return type_param_bounds; | |
4006 | } | |
4007 | ||
4008 | /* Parses a single type parameter bound in a where clause or generic argument. | |
4009 | * Does not parse the '+' between arguments. */ | |
4010 | template <typename ManagedTokenSource> | |
4011 | std::unique_ptr<AST::TypeParamBound> | |
4012 | Parser<ManagedTokenSource>::parse_type_param_bound () | |
4013 | { | |
4014 | // shitty cheat way of determining lifetime or trait bound - test for | |
4015 | // lifetime | |
4016 | const_TokenPtr t = lexer.peek_token (); | |
4017 | switch (t->get_id ()) | |
4018 | { | |
4019 | case LIFETIME: | |
4020 | return std::unique_ptr<AST::Lifetime> ( | |
4021 | new AST::Lifetime (parse_lifetime (false).value ())); | |
4022 | case LEFT_PAREN: | |
4023 | case QUESTION_MARK: | |
4024 | case FOR: | |
4025 | case IDENTIFIER: | |
4026 | case SUPER: | |
4027 | case SELF: | |
4028 | case SELF_ALIAS: | |
4029 | case CRATE: | |
4030 | case DOLLAR_SIGN: | |
4031 | case SCOPE_RESOLUTION: | |
4032 | return parse_trait_bound (); | |
4033 | default: | |
4034 | // don't error - assume this is fine TODO | |
4035 | return nullptr; | |
4036 | } | |
4037 | } | |
4038 | ||
4039 | // Parses a trait bound type param bound. | |
4040 | template <typename ManagedTokenSource> | |
4041 | std::unique_ptr<AST::TraitBound> | |
4042 | Parser<ManagedTokenSource>::parse_trait_bound () | |
4043 | { | |
4044 | bool has_parens = false; | |
4045 | bool has_question_mark = false; | |
4046 | ||
4047 | location_t locus = lexer.peek_token ()->get_locus (); | |
4048 | ||
4049 | /* parse optional `for lifetimes`. */ | |
4050 | std::vector<AST::LifetimeParam> for_lifetimes; | |
4051 | if (lexer.peek_token ()->get_id () == FOR) | |
4052 | for_lifetimes = parse_for_lifetimes (); | |
4053 | ||
4054 | // handle trait bound being in parentheses | |
4055 | if (lexer.peek_token ()->get_id () == LEFT_PAREN) | |
4056 | { | |
4057 | has_parens = true; | |
4058 | lexer.skip_token (); | |
4059 | } | |
4060 | ||
4061 | // handle having question mark (optional) | |
4062 | if (lexer.peek_token ()->get_id () == QUESTION_MARK) | |
4063 | { | |
4064 | has_question_mark = true; | |
4065 | lexer.skip_token (); | |
4066 | } | |
4067 | ||
4068 | // handle TypePath | |
4069 | AST::TypePath type_path = parse_type_path (); | |
4070 | ||
4071 | // handle closing parentheses | |
4072 | if (has_parens) | |
4073 | { | |
4074 | if (!skip_token (RIGHT_PAREN)) | |
4075 | { | |
4076 | return nullptr; | |
4077 | } | |
4078 | } | |
4079 | ||
4080 | return std::unique_ptr<AST::TraitBound> ( | |
4081 | new AST::TraitBound (std::move (type_path), locus, has_parens, | |
4082 | has_question_mark, std::move (for_lifetimes))); | |
4083 | } | |
4084 | ||
4085 | // Parses lifetime bounds. | |
4086 | template <typename ManagedTokenSource> | |
4087 | std::vector<AST::Lifetime> | |
4088 | Parser<ManagedTokenSource>::parse_lifetime_bounds () | |
4089 | { | |
4090 | std::vector<AST::Lifetime> lifetime_bounds; | |
4091 | ||
4092 | while (true) | |
4093 | { | |
4094 | auto lifetime = parse_lifetime (false); | |
4095 | ||
4096 | // quick exit for parsing failure | |
4097 | if (!lifetime) | |
4098 | break; | |
4099 | ||
4100 | lifetime_bounds.push_back (std::move (lifetime.value ())); | |
4101 | ||
4102 | /* plus is maybe not allowed at end - spec defines it weirdly, so | |
4103 | * assuming allowed at end */ | |
4104 | if (lexer.peek_token ()->get_id () != PLUS) | |
4105 | break; | |
4106 | ||
4107 | lexer.skip_token (); | |
4108 | } | |
4109 | ||
4110 | lifetime_bounds.shrink_to_fit (); | |
4111 | return lifetime_bounds; | |
4112 | } | |
4113 | ||
4114 | // Parses lifetime bounds, with added check for ending token. | |
4115 | template <typename ManagedTokenSource> | |
4116 | template <typename EndTokenPred> | |
4117 | std::vector<AST::Lifetime> | |
4118 | Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token) | |
4119 | { | |
4120 | std::vector<AST::Lifetime> lifetime_bounds; | |
4121 | ||
4122 | while (!is_end_token (lexer.peek_token ()->get_id ())) | |
4123 | { | |
4124 | auto lifetime = parse_lifetime (false); | |
4125 | ||
4126 | if (!lifetime) | |
4127 | { | |
4128 | /* TODO: is it worth throwing away all lifetime bound info just | |
4129 | * because one failed? */ | |
4130 | Error error (lexer.peek_token ()->get_locus (), | |
4131 | "failed to parse lifetime in lifetime bounds"); | |
4132 | add_error (std::move (error)); | |
4133 | ||
4134 | return {}; | |
4135 | } | |
4136 | ||
4137 | lifetime_bounds.push_back (std::move (lifetime.value ())); | |
4138 | ||
4139 | /* plus is maybe not allowed at end - spec defines it weirdly, so | |
4140 | * assuming allowed at end */ | |
4141 | if (lexer.peek_token ()->get_id () != PLUS) | |
4142 | break; | |
4143 | ||
4144 | lexer.skip_token (); | |
4145 | } | |
4146 | ||
4147 | lifetime_bounds.shrink_to_fit (); | |
4148 | return lifetime_bounds; | |
4149 | } | |
4150 | ||
4151 | /* Parses a lifetime token (named, 'static, or '_). Also handles lifetime not | |
4152 | * existing. */ | |
4153 | template <typename ManagedTokenSource> | |
4154 | tl::expected<AST::Lifetime, ParseLifetimeError> | |
4155 | Parser<ManagedTokenSource>::parse_lifetime (bool allow_elided) | |
4156 | { | |
4157 | const_TokenPtr lifetime_tok = lexer.peek_token (); | |
4158 | if (lifetime_tok->get_id () != LIFETIME) | |
4159 | { | |
4160 | if (allow_elided) | |
4161 | { | |
4162 | return AST::Lifetime::elided (); | |
4163 | } | |
4164 | else | |
4165 | { | |
4166 | return tl::make_unexpected<ParseLifetimeError> ({}); | |
4167 | } | |
4168 | } | |
4169 | lexer.skip_token (); | |
4170 | ||
4171 | return lifetime_from_token (lifetime_tok); | |
4172 | } | |
4173 | ||
4174 | template <typename ManagedTokenSource> | |
4175 | AST::Lifetime | |
4176 | Parser<ManagedTokenSource>::lifetime_from_token (const_TokenPtr tok) | |
4177 | { | |
4178 | location_t locus = tok->get_locus (); | |
4179 | std::string lifetime_ident = tok->get_str (); | |
4180 | ||
4181 | if (lifetime_ident == "static") | |
4182 | { | |
4183 | return AST::Lifetime (AST::Lifetime::STATIC, "", locus); | |
4184 | } | |
4185 | else if (lifetime_ident == "_") | |
4186 | { | |
4187 | // Explicitly and implicitly elided lifetimes follow the same rules. | |
4188 | return AST::Lifetime (AST::Lifetime::WILDCARD, "", locus); | |
4189 | } | |
4190 | else | |
4191 | { | |
4192 | return AST::Lifetime (AST::Lifetime::NAMED, std::move (lifetime_ident), | |
4193 | locus); | |
4194 | } | |
4195 | } | |
4196 | ||
4197 | template <typename ManagedTokenSource> | |
4198 | std::unique_ptr<AST::ExternalTypeItem> | |
4199 | Parser<ManagedTokenSource>::parse_external_type_item (AST::Visibility vis, | |
4200 | AST::AttrVec outer_attrs) | |
4201 | { | |
4202 | location_t locus = lexer.peek_token ()->get_locus (); | |
4203 | skip_token (TYPE); | |
4204 | ||
4205 | const_TokenPtr alias_name_tok = expect_token (IDENTIFIER); | |
4206 | if (alias_name_tok == nullptr) | |
4207 | { | |
4208 | Error error (lexer.peek_token ()->get_locus (), | |
4209 | "could not parse identifier in external opaque type"); | |
4210 | add_error (std::move (error)); | |
4211 | ||
4212 | skip_after_semicolon (); | |
4213 | return nullptr; | |
4214 | } | |
4215 | ||
4216 | if (!skip_token (SEMICOLON)) | |
4217 | return nullptr; | |
4218 | ||
4219 | return std::unique_ptr<AST::ExternalTypeItem> ( | |
4220 | new AST::ExternalTypeItem (alias_name_tok->get_str (), std::move (vis), | |
4221 | std::move (outer_attrs), std::move (locus))); | |
4222 | } | |
4223 | ||
4224 | // Parses a "type alias" (typedef) item. | |
4225 | template <typename ManagedTokenSource> | |
4226 | std::unique_ptr<AST::TypeAlias> | |
4227 | Parser<ManagedTokenSource>::parse_type_alias (AST::Visibility vis, | |
4228 | AST::AttrVec outer_attrs) | |
4229 | { | |
4230 | location_t locus = lexer.peek_token ()->get_locus (); | |
4231 | skip_token (TYPE); | |
4232 | ||
4233 | // TODO: use this token for identifier when finished that | |
4234 | const_TokenPtr alias_name_tok = expect_token (IDENTIFIER); | |
4235 | if (alias_name_tok == nullptr) | |
4236 | { | |
4237 | Error error (lexer.peek_token ()->get_locus (), | |
4238 | "could not parse identifier in type alias"); | |
4239 | add_error (std::move (error)); | |
4240 | ||
4241 | skip_after_semicolon (); | |
4242 | return nullptr; | |
4243 | } | |
4244 | Identifier alias_name{alias_name_tok}; | |
4245 | ||
4246 | // parse generic params, which may not exist | |
4247 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
4248 | = parse_generic_params_in_angles (); | |
4249 | ||
4250 | // parse where clause, which may not exist | |
4251 | AST::WhereClause where_clause = parse_where_clause (); | |
4252 | ||
4253 | if (!skip_token (EQUAL)) | |
4254 | { | |
4255 | skip_after_semicolon (); | |
4256 | return nullptr; | |
4257 | } | |
4258 | ||
4259 | std::unique_ptr<AST::Type> type_to_alias = parse_type (); | |
4260 | ||
4261 | if (!skip_token (SEMICOLON)) | |
4262 | { | |
4263 | // should be skipping past this, not the next line | |
4264 | return nullptr; | |
4265 | } | |
4266 | ||
4267 | return std::unique_ptr<AST::TypeAlias> ( | |
4268 | new AST::TypeAlias (std::move (alias_name), std::move (generic_params), | |
4269 | std::move (where_clause), std::move (type_to_alias), | |
4270 | std::move (vis), std::move (outer_attrs), locus)); | |
4271 | } | |
4272 | ||
4273 | // Parse a struct item AST node. | |
4274 | template <typename ManagedTokenSource> | |
4275 | std::unique_ptr<AST::Struct> | |
4276 | Parser<ManagedTokenSource>::parse_struct (AST::Visibility vis, | |
4277 | AST::AttrVec outer_attrs) | |
4278 | { | |
4279 | /* TODO: determine best way to parse the proper struct vs tuple struct - | |
4280 | * share most of initial constructs so lookahead might be impossible, and if | |
4281 | * not probably too expensive. Best way is probably unified parsing for the | |
4282 | * initial parts and then pass them in as params to more derived functions. | |
4283 | * Alternatively, just parse everything in this one function - do this if | |
4284 | * function not too long. */ | |
4285 | ||
4286 | /* Proper struct <- 'struct' IDENTIFIER generic_params? where_clause? ( '{' | |
4287 | * struct_fields? '}' | ';' ) */ | |
4288 | /* Tuple struct <- 'struct' IDENTIFIER generic_params? '(' tuple_fields? ')' | |
4289 | * where_clause? ';' */ | |
4290 | location_t locus = lexer.peek_token ()->get_locus (); | |
4291 | skip_token (STRUCT_KW); | |
4292 | ||
4293 | // parse struct name | |
4294 | const_TokenPtr name_tok = expect_token (IDENTIFIER); | |
4295 | if (name_tok == nullptr) | |
4296 | { | |
4297 | Error error (lexer.peek_token ()->get_locus (), | |
4298 | "could not parse struct or tuple struct identifier"); | |
4299 | add_error (std::move (error)); | |
4300 | ||
4301 | // skip after somewhere? | |
4302 | return nullptr; | |
4303 | } | |
4304 | Identifier struct_name{name_tok}; | |
4305 | ||
4306 | // parse generic params, which may or may not exist | |
4307 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
4308 | = parse_generic_params_in_angles (); | |
4309 | ||
4310 | // branch on next token - determines whether proper struct or tuple struct | |
4311 | if (lexer.peek_token ()->get_id () == LEFT_PAREN) | |
4312 | { | |
4313 | // tuple struct | |
4314 | ||
4315 | // skip left parenthesis | |
4316 | lexer.skip_token (); | |
4317 | ||
4318 | // parse tuple fields | |
4319 | std::vector<AST::TupleField> tuple_fields; | |
4320 | // Might be empty tuple for unit tuple struct. | |
4321 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
4322 | tuple_fields = std::vector<AST::TupleField> (); | |
4323 | else | |
4324 | tuple_fields = parse_tuple_fields (); | |
4325 | ||
4326 | // tuple parameters must have closing parenthesis | |
4327 | if (!skip_token (RIGHT_PAREN)) | |
4328 | { | |
4329 | skip_after_semicolon (); | |
4330 | return nullptr; | |
4331 | } | |
4332 | ||
4333 | // parse where clause, which is optional | |
4334 | AST::WhereClause where_clause = parse_where_clause (); | |
4335 | ||
4336 | if (!skip_token (SEMICOLON)) | |
4337 | { | |
4338 | // can't skip after semicolon because it's meant to be here | |
4339 | return nullptr; | |
4340 | } | |
4341 | ||
4342 | return std::unique_ptr<AST::TupleStruct> ( | |
4343 | new AST::TupleStruct (std::move (tuple_fields), std::move (struct_name), | |
4344 | std::move (generic_params), | |
4345 | std::move (where_clause), std::move (vis), | |
4346 | std::move (outer_attrs), locus)); | |
4347 | } | |
4348 | ||
4349 | // assume it is a proper struct being parsed and continue outside of switch | |
4350 | // - label only here to suppress warning | |
4351 | ||
4352 | // parse where clause, which is optional | |
4353 | AST::WhereClause where_clause = parse_where_clause (); | |
4354 | ||
4355 | // branch on next token - determines whether struct is a unit struct | |
4356 | const_TokenPtr t = lexer.peek_token (); | |
4357 | switch (t->get_id ()) | |
4358 | { | |
4359 | case LEFT_CURLY: { | |
4360 | // struct with body | |
4361 | ||
4362 | // skip curly bracket | |
4363 | lexer.skip_token (); | |
4364 | ||
4365 | // parse struct fields, if any | |
4366 | std::vector<AST::StructField> struct_fields | |
4367 | = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; }); | |
4368 | ||
4369 | if (!skip_token (RIGHT_CURLY)) | |
4370 | { | |
4371 | // skip somewhere? | |
4372 | return nullptr; | |
4373 | } | |
4374 | ||
4375 | return std::unique_ptr<AST::StructStruct> (new AST::StructStruct ( | |
4376 | std::move (struct_fields), std::move (struct_name), | |
4377 | std::move (generic_params), std::move (where_clause), false, | |
4378 | std::move (vis), std::move (outer_attrs), locus)); | |
4379 | } | |
4380 | case SEMICOLON: | |
4381 | // unit struct declaration | |
4382 | ||
4383 | lexer.skip_token (); | |
4384 | ||
4385 | return std::unique_ptr<AST::StructStruct> ( | |
4386 | new AST::StructStruct (std::move (struct_name), | |
4387 | std::move (generic_params), | |
4388 | std::move (where_clause), std::move (vis), | |
4389 | std::move (outer_attrs), locus)); | |
4390 | default: | |
4391 | add_error (Error (t->get_locus (), | |
4392 | "unexpected token %qs in struct declaration", | |
4393 | t->get_token_description ())); | |
4394 | ||
4395 | // skip somewhere? | |
4396 | return nullptr; | |
4397 | } | |
4398 | } | |
4399 | ||
4400 | // Parses struct fields in struct declarations. | |
4401 | template <typename ManagedTokenSource> | |
4402 | std::vector<AST::StructField> | |
4403 | Parser<ManagedTokenSource>::parse_struct_fields () | |
4404 | { | |
4405 | std::vector<AST::StructField> fields; | |
4406 | ||
4407 | AST::StructField initial_field = parse_struct_field (); | |
4408 | ||
4409 | // Return empty field list if no field there | |
4410 | if (initial_field.is_error ()) | |
4411 | return fields; | |
4412 | ||
4413 | fields.push_back (std::move (initial_field)); | |
4414 | ||
4415 | while (lexer.peek_token ()->get_id () == COMMA) | |
4416 | { | |
4417 | lexer.skip_token (); | |
4418 | ||
4419 | AST::StructField field = parse_struct_field (); | |
4420 | ||
4421 | if (field.is_error ()) | |
4422 | { | |
4423 | // would occur with trailing comma, so allowed | |
4424 | break; | |
4425 | } | |
4426 | ||
4427 | fields.push_back (std::move (field)); | |
4428 | } | |
4429 | ||
4430 | fields.shrink_to_fit (); | |
4431 | return fields; | |
4432 | // TODO: template if possible (parse_non_ptr_seq) | |
4433 | } | |
4434 | ||
4435 | // Parses struct fields in struct declarations. | |
4436 | template <typename ManagedTokenSource> | |
4437 | template <typename EndTokenPred> | |
4438 | std::vector<AST::StructField> | |
4439 | Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok) | |
4440 | { | |
4441 | std::vector<AST::StructField> fields; | |
4442 | ||
4443 | AST::StructField initial_field = parse_struct_field (); | |
4444 | ||
4445 | // Return empty field list if no field there | |
4446 | if (initial_field.is_error ()) | |
4447 | return fields; | |
4448 | ||
4449 | fields.push_back (std::move (initial_field)); | |
4450 | ||
4451 | while (lexer.peek_token ()->get_id () == COMMA) | |
4452 | { | |
4453 | lexer.skip_token (); | |
4454 | ||
4455 | if (is_end_tok (lexer.peek_token ()->get_id ())) | |
4456 | break; | |
4457 | ||
4458 | AST::StructField field = parse_struct_field (); | |
4459 | if (field.is_error ()) | |
4460 | { | |
4461 | /* TODO: should every field be ditched just because one couldn't be | |
4462 | * parsed? */ | |
4463 | Error error (lexer.peek_token ()->get_locus (), | |
4464 | "failed to parse struct field in struct fields"); | |
4465 | add_error (std::move (error)); | |
4466 | ||
4467 | return {}; | |
4468 | } | |
4469 | ||
4470 | fields.push_back (std::move (field)); | |
4471 | } | |
4472 | ||
4473 | fields.shrink_to_fit (); | |
4474 | return fields; | |
4475 | // TODO: template if possible (parse_non_ptr_seq) | |
4476 | } | |
4477 | ||
4478 | // Parses a single struct field (in a struct definition). Does not parse | |
4479 | // commas. | |
4480 | template <typename ManagedTokenSource> | |
4481 | AST::StructField | |
4482 | Parser<ManagedTokenSource>::parse_struct_field () | |
4483 | { | |
4484 | // parse outer attributes, if they exist | |
4485 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
4486 | ||
4487 | // parse visibility, if it exists | |
4488 | AST::Visibility vis = parse_visibility (); | |
4489 | ||
4490 | location_t locus = lexer.peek_token ()->get_locus (); | |
4491 | ||
4492 | // parse field name | |
4493 | const_TokenPtr field_name_tok = lexer.peek_token (); | |
4494 | if (field_name_tok->get_id () != IDENTIFIER) | |
4495 | { | |
4496 | // if not identifier, assumes there is no struct field and exits - not | |
4497 | // necessarily error | |
4498 | return AST::StructField::create_error (); | |
4499 | } | |
4500 | Identifier field_name{field_name_tok}; | |
4501 | lexer.skip_token (); | |
4502 | ||
4503 | if (!skip_token (COLON)) | |
4504 | { | |
4505 | // skip after somewhere? | |
4506 | return AST::StructField::create_error (); | |
4507 | } | |
4508 | ||
4509 | // parse field type - this is required | |
4510 | std::unique_ptr<AST::Type> field_type = parse_type (); | |
4511 | if (field_type == nullptr) | |
4512 | { | |
4513 | Error error (lexer.peek_token ()->get_locus (), | |
4514 | "could not parse type in struct field definition"); | |
4515 | add_error (std::move (error)); | |
4516 | ||
4517 | // skip after somewhere | |
4518 | return AST::StructField::create_error (); | |
4519 | } | |
4520 | ||
4521 | return AST::StructField (std::move (field_name), std::move (field_type), | |
4522 | std::move (vis), locus, std::move (outer_attrs)); | |
4523 | } | |
4524 | ||
4525 | // Parses tuple fields in tuple/tuple struct declarations. | |
4526 | template <typename ManagedTokenSource> | |
4527 | std::vector<AST::TupleField> | |
4528 | Parser<ManagedTokenSource>::parse_tuple_fields () | |
4529 | { | |
4530 | std::vector<AST::TupleField> fields; | |
4531 | ||
4532 | AST::TupleField initial_field = parse_tuple_field (); | |
4533 | ||
4534 | // Return empty field list if no field there | |
4535 | if (initial_field.is_error ()) | |
4536 | { | |
4537 | return fields; | |
4538 | } | |
4539 | ||
4540 | fields.push_back (std::move (initial_field)); | |
4541 | ||
4542 | // maybe think of a better control structure here - do-while with an initial | |
4543 | // error state? basically, loop through field list until can't find any more | |
4544 | // params HACK: all current syntax uses of tuple fields have them ending | |
4545 | // with a right paren token | |
4546 | const_TokenPtr t = lexer.peek_token (); | |
4547 | while (t->get_id () == COMMA) | |
4548 | { | |
4549 | // skip comma if applies - e.g. trailing comma | |
4550 | lexer.skip_token (); | |
4551 | ||
4552 | // break out due to right paren if it exists | |
4553 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
4554 | { | |
4555 | break; | |
4556 | } | |
4557 | ||
4558 | AST::TupleField field = parse_tuple_field (); | |
4559 | if (field.is_error ()) | |
4560 | { | |
4561 | Error error (lexer.peek_token ()->get_locus (), | |
4562 | "failed to parse tuple field in tuple fields"); | |
4563 | add_error (std::move (error)); | |
4564 | ||
4565 | return std::vector<AST::TupleField> (); | |
4566 | } | |
4567 | ||
4568 | fields.push_back (std::move (field)); | |
4569 | ||
4570 | t = lexer.peek_token (); | |
4571 | } | |
4572 | ||
4573 | fields.shrink_to_fit (); | |
4574 | return fields; | |
4575 | ||
4576 | // TODO: this shares basically all code with function params and struct | |
4577 | // fields | |
4578 | // - templates? | |
4579 | } | |
4580 | ||
4581 | /* Parses a single tuple struct field in a tuple struct definition. Does not | |
4582 | * parse commas. */ | |
4583 | template <typename ManagedTokenSource> | |
4584 | AST::TupleField | |
4585 | Parser<ManagedTokenSource>::parse_tuple_field () | |
4586 | { | |
4587 | // parse outer attributes if they exist | |
4588 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
4589 | ||
4590 | // parse visibility if it exists | |
4591 | AST::Visibility vis = parse_visibility (); | |
4592 | ||
4593 | location_t locus = lexer.peek_token ()->get_locus (); | |
4594 | ||
4595 | // parse type, which is required | |
4596 | std::unique_ptr<AST::Type> field_type = parse_type (); | |
4597 | if (field_type == nullptr) | |
4598 | { | |
4599 | // error if null | |
4600 | Error error (lexer.peek_token ()->get_locus (), | |
4601 | "could not parse type in tuple struct field"); | |
4602 | add_error (std::move (error)); | |
4603 | ||
4604 | // skip after something | |
4605 | return AST::TupleField::create_error (); | |
4606 | } | |
4607 | ||
4608 | return AST::TupleField (std::move (field_type), std::move (vis), locus, | |
4609 | std::move (outer_attrs)); | |
4610 | } | |
4611 | ||
4612 | // Parses a Rust "enum" tagged union item definition. | |
4613 | template <typename ManagedTokenSource> | |
4614 | std::unique_ptr<AST::Enum> | |
4615 | Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis, | |
4616 | AST::AttrVec outer_attrs) | |
4617 | { | |
4618 | location_t locus = lexer.peek_token ()->get_locus (); | |
4619 | skip_token (ENUM_KW); | |
4620 | ||
4621 | // parse enum name | |
4622 | const_TokenPtr enum_name_tok = expect_token (IDENTIFIER); | |
4623 | if (enum_name_tok == nullptr) | |
4624 | return nullptr; | |
4625 | ||
4626 | Identifier enum_name = {enum_name_tok}; | |
4627 | ||
4628 | // parse generic params (of enum container, not enum variants) if they exist | |
4629 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
4630 | = parse_generic_params_in_angles (); | |
4631 | ||
4632 | // parse where clause if it exists | |
4633 | AST::WhereClause where_clause = parse_where_clause (); | |
4634 | ||
4635 | if (!skip_token (LEFT_CURLY)) | |
4636 | { | |
4637 | skip_after_end_block (); | |
4638 | return nullptr; | |
4639 | } | |
4640 | ||
4641 | // parse actual enum variant definitions | |
4642 | std::vector<std::unique_ptr<AST::EnumItem>> enum_items | |
4643 | = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; }); | |
4644 | ||
4645 | if (!skip_token (RIGHT_CURLY)) | |
4646 | { | |
4647 | skip_after_end_block (); | |
4648 | return nullptr; | |
4649 | } | |
4650 | ||
4651 | return std::unique_ptr<AST::Enum> ( | |
4652 | new AST::Enum (std::move (enum_name), std::move (vis), | |
4653 | std::move (generic_params), std::move (where_clause), | |
4654 | std::move (enum_items), std::move (outer_attrs), locus)); | |
4655 | } | |
4656 | ||
4657 | // Parses the enum variants inside an enum definiton. | |
4658 | template <typename ManagedTokenSource> | |
4659 | std::vector<std::unique_ptr<AST::EnumItem>> | |
4660 | Parser<ManagedTokenSource>::parse_enum_items () | |
4661 | { | |
4662 | std::vector<std::unique_ptr<AST::EnumItem>> items; | |
4663 | ||
4664 | std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item (); | |
4665 | ||
4666 | // Return empty item list if no field there | |
4667 | if (initial_item == nullptr) | |
4668 | return items; | |
4669 | ||
4670 | items.push_back (std::move (initial_item)); | |
4671 | ||
4672 | while (lexer.peek_token ()->get_id () == COMMA) | |
4673 | { | |
4674 | lexer.skip_token (); | |
4675 | ||
4676 | std::unique_ptr<AST::EnumItem> item = parse_enum_item (); | |
4677 | if (item == nullptr) | |
4678 | { | |
4679 | // this would occur with a trailing comma, which is allowed | |
4680 | break; | |
4681 | } | |
4682 | ||
4683 | items.push_back (std::move (item)); | |
4684 | } | |
4685 | ||
4686 | items.shrink_to_fit (); | |
4687 | return items; | |
4688 | ||
4689 | /* TODO: use template if doable (parse_non_ptr_sequence) */ | |
4690 | } | |
4691 | ||
4692 | // Parses the enum variants inside an enum definiton. | |
4693 | template <typename ManagedTokenSource> | |
4694 | template <typename EndTokenPred> | |
4695 | std::vector<std::unique_ptr<AST::EnumItem>> | |
4696 | Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok) | |
4697 | { | |
4698 | std::vector<std::unique_ptr<AST::EnumItem>> items; | |
4699 | ||
4700 | std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item (); | |
4701 | ||
4702 | // Return empty item list if no field there | |
4703 | if (initial_item == nullptr) | |
4704 | return items; | |
4705 | ||
4706 | items.push_back (std::move (initial_item)); | |
4707 | ||
4708 | while (lexer.peek_token ()->get_id () == COMMA) | |
4709 | { | |
4710 | lexer.skip_token (); | |
4711 | ||
4712 | if (is_end_tok (lexer.peek_token ()->get_id ())) | |
4713 | break; | |
4714 | ||
4715 | std::unique_ptr<AST::EnumItem> item = parse_enum_item (); | |
4716 | if (item == nullptr) | |
4717 | { | |
4718 | /* TODO should this ignore all successfully parsed enum items just | |
4719 | * because one failed? */ | |
4720 | Error error (lexer.peek_token ()->get_locus (), | |
4721 | "failed to parse enum item in enum items"); | |
4722 | add_error (std::move (error)); | |
4723 | ||
4724 | return {}; | |
4725 | } | |
4726 | ||
4727 | items.push_back (std::move (item)); | |
4728 | } | |
4729 | ||
4730 | items.shrink_to_fit (); | |
4731 | return items; | |
4732 | ||
4733 | /* TODO: use template if doable (parse_non_ptr_sequence) */ | |
4734 | } | |
4735 | ||
4736 | /* Parses a single enum variant item in an enum definition. Does not parse | |
4737 | * commas. */ | |
4738 | template <typename ManagedTokenSource> | |
4739 | std::unique_ptr<AST::EnumItem> | |
4740 | Parser<ManagedTokenSource>::parse_enum_item () | |
4741 | { | |
4742 | // parse outer attributes if they exist | |
4743 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
4744 | ||
4745 | // parse visibility, which may or may not exist | |
4746 | AST::Visibility vis = parse_visibility (); | |
4747 | ||
4748 | // parse name for enum item, which is required | |
4749 | const_TokenPtr item_name_tok = lexer.peek_token (); | |
4750 | if (item_name_tok->get_id () != IDENTIFIER) | |
4751 | { | |
4752 | // this may not be an error but it means there is no enum item here | |
4753 | return nullptr; | |
4754 | } | |
4755 | lexer.skip_token (); | |
4756 | Identifier item_name{item_name_tok}; | |
4757 | ||
4758 | // branch based on next token | |
4759 | const_TokenPtr t = lexer.peek_token (); | |
4760 | switch (t->get_id ()) | |
4761 | { | |
4762 | case LEFT_PAREN: { | |
4763 | // tuple enum item | |
4764 | lexer.skip_token (); | |
4765 | ||
4766 | std::vector<AST::TupleField> tuple_fields; | |
4767 | // Might be empty tuple for unit tuple enum variant. | |
4768 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
4769 | tuple_fields = std::vector<AST::TupleField> (); | |
4770 | else | |
4771 | tuple_fields = parse_tuple_fields (); | |
4772 | ||
4773 | if (!skip_token (RIGHT_PAREN)) | |
4774 | { | |
4775 | // skip after somewhere | |
4776 | return nullptr; | |
4777 | } | |
4778 | ||
4779 | return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple ( | |
4780 | std::move (item_name), std::move (vis), std::move (tuple_fields), | |
4781 | std::move (outer_attrs), item_name_tok->get_locus ())); | |
4782 | } | |
4783 | case LEFT_CURLY: { | |
4784 | // struct enum item | |
4785 | lexer.skip_token (); | |
4786 | ||
4787 | std::vector<AST::StructField> struct_fields | |
4788 | = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; }); | |
4789 | ||
4790 | if (!skip_token (RIGHT_CURLY)) | |
4791 | { | |
4792 | // skip after somewhere | |
4793 | return nullptr; | |
4794 | } | |
4795 | ||
4796 | return std::unique_ptr<AST::EnumItemStruct> (new AST::EnumItemStruct ( | |
4797 | std::move (item_name), std::move (vis), std::move (struct_fields), | |
4798 | std::move (outer_attrs), item_name_tok->get_locus ())); | |
4799 | } | |
4800 | case EQUAL: { | |
4801 | // discriminant enum item | |
4802 | lexer.skip_token (); | |
4803 | ||
4804 | std::unique_ptr<AST::Expr> discriminant_expr = parse_expr (); | |
4805 | ||
4806 | return std::unique_ptr<AST::EnumItemDiscriminant> ( | |
4807 | new AST::EnumItemDiscriminant (std::move (item_name), std::move (vis), | |
4808 | std::move (discriminant_expr), | |
4809 | std::move (outer_attrs), | |
4810 | item_name_tok->get_locus ())); | |
4811 | } | |
4812 | default: | |
4813 | // regular enum with just an identifier | |
4814 | return std::unique_ptr<AST::EnumItem> ( | |
4815 | new AST::EnumItem (std::move (item_name), std::move (vis), | |
4816 | std::move (outer_attrs), | |
4817 | item_name_tok->get_locus ())); | |
4818 | } | |
4819 | } | |
4820 | ||
4821 | // Parses a C-style (and C-compat) untagged union declaration. | |
4822 | template <typename ManagedTokenSource> | |
4823 | std::unique_ptr<AST::Union> | |
4824 | Parser<ManagedTokenSource>::parse_union (AST::Visibility vis, | |
4825 | AST::AttrVec outer_attrs) | |
4826 | { | |
4827 | /* hack - "weak keyword" by finding identifier called "union" (lookahead in | |
4828 | * item switch) */ | |
4829 | const_TokenPtr union_keyword = expect_token (IDENTIFIER); | |
4830 | rust_assert (union_keyword->get_str () == Values::WeakKeywords::UNION); | |
4831 | location_t locus = union_keyword->get_locus (); | |
4832 | ||
4833 | // parse actual union name | |
4834 | const_TokenPtr union_name_tok = expect_token (IDENTIFIER); | |
4835 | if (union_name_tok == nullptr) | |
4836 | { | |
4837 | skip_after_next_block (); | |
4838 | return nullptr; | |
4839 | } | |
4840 | Identifier union_name{union_name_tok}; | |
4841 | ||
4842 | // parse optional generic parameters | |
4843 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
4844 | = parse_generic_params_in_angles (); | |
4845 | ||
4846 | // parse optional where clause | |
4847 | AST::WhereClause where_clause = parse_where_clause (); | |
4848 | ||
4849 | if (!skip_token (LEFT_CURLY)) | |
4850 | { | |
4851 | skip_after_end_block (); | |
4852 | return nullptr; | |
4853 | } | |
4854 | ||
4855 | /* parse union inner items as "struct fields" because hey, syntax reuse. | |
4856 | * Spec said so. */ | |
4857 | std::vector<AST::StructField> union_fields | |
4858 | = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; }); | |
4859 | ||
4860 | if (!skip_token (RIGHT_CURLY)) | |
4861 | { | |
4862 | // skip after somewhere | |
4863 | return nullptr; | |
4864 | } | |
4865 | ||
4866 | return std::unique_ptr<AST::Union> ( | |
4867 | new AST::Union (std::move (union_name), std::move (vis), | |
4868 | std::move (generic_params), std::move (where_clause), | |
4869 | std::move (union_fields), std::move (outer_attrs), locus)); | |
4870 | } | |
4871 | ||
4872 | /* Parses a "constant item" (compile-time constant to maybe "inline" | |
4873 | * throughout the program - like constexpr). */ | |
4874 | template <typename ManagedTokenSource> | |
4875 | std::unique_ptr<AST::ConstantItem> | |
4876 | Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis, | |
4877 | AST::AttrVec outer_attrs) | |
4878 | { | |
4879 | location_t locus = lexer.peek_token ()->get_locus (); | |
4880 | skip_token (CONST); | |
4881 | ||
4882 | /* get constant identifier - this is either a proper identifier or the _ | |
4883 | * wildcard */ | |
4884 | const_TokenPtr ident_tok = lexer.peek_token (); | |
4885 | // make default identifier the underscore wildcard one | |
4886 | std::string ident (Values::Keywords::UNDERSCORE); | |
4887 | switch (ident_tok->get_id ()) | |
4888 | { | |
4889 | case IDENTIFIER: | |
4890 | ident = ident_tok->get_str (); | |
4891 | lexer.skip_token (); | |
4892 | break; | |
4893 | case UNDERSCORE: | |
4894 | // do nothing - identifier is already "_" | |
4895 | lexer.skip_token (); | |
4896 | break; | |
4897 | default: | |
4898 | add_error ( | |
4899 | Error (ident_tok->get_locus (), | |
4900 | "expected item name (identifier or %<_%>) in constant item " | |
4901 | "declaration - found %qs", | |
4902 | ident_tok->get_token_description ())); | |
4903 | ||
4904 | skip_after_semicolon (); | |
4905 | return nullptr; | |
4906 | } | |
4907 | ||
4908 | if (!skip_token (COLON)) | |
4909 | { | |
4910 | skip_after_semicolon (); | |
4911 | return nullptr; | |
4912 | } | |
4913 | ||
4914 | // parse constant type (required) | |
4915 | std::unique_ptr<AST::Type> type = parse_type (); | |
4916 | ||
4917 | // A const with no given expression value | |
4918 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
4919 | { | |
4920 | lexer.skip_token (); | |
4921 | return std::unique_ptr<AST::ConstantItem> ( | |
4922 | new AST::ConstantItem (std::move (ident), std::move (vis), | |
4923 | std::move (type), std::move (outer_attrs), | |
4924 | locus)); | |
4925 | } | |
4926 | ||
4927 | if (!skip_token (EQUAL)) | |
4928 | { | |
4929 | skip_after_semicolon (); | |
4930 | return nullptr; | |
4931 | } | |
4932 | ||
4933 | // parse constant expression (required) | |
4934 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
4935 | ||
4936 | if (!skip_token (SEMICOLON)) | |
4937 | { | |
4938 | // skip somewhere? | |
4939 | return nullptr; | |
4940 | } | |
4941 | ||
4942 | return std::unique_ptr<AST::ConstantItem> ( | |
4943 | new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type), | |
4944 | std::move (expr), std::move (outer_attrs), locus)); | |
4945 | } | |
4946 | ||
4947 | // Parses a "static item" (static storage item, with 'static lifetime). | |
4948 | template <typename ManagedTokenSource> | |
4949 | std::unique_ptr<AST::StaticItem> | |
4950 | Parser<ManagedTokenSource>::parse_static_item (AST::Visibility vis, | |
4951 | AST::AttrVec outer_attrs) | |
4952 | { | |
4953 | location_t locus = lexer.peek_token ()->get_locus (); | |
4954 | skip_token (STATIC_KW); | |
4955 | ||
4956 | // determine whether static item is mutable | |
4957 | bool is_mut = false; | |
4958 | if (lexer.peek_token ()->get_id () == MUT) | |
4959 | { | |
4960 | is_mut = true; | |
4961 | lexer.skip_token (); | |
4962 | } | |
4963 | ||
4964 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
4965 | if (ident_tok == nullptr) | |
4966 | return nullptr; | |
4967 | ||
4968 | Identifier ident{ident_tok}; | |
4969 | ||
4970 | if (!skip_token (COLON)) | |
4971 | { | |
4972 | skip_after_semicolon (); | |
4973 | return nullptr; | |
4974 | } | |
4975 | ||
4976 | // parse static item type (required) | |
4977 | std::unique_ptr<AST::Type> type = parse_type (); | |
4978 | ||
4979 | if (!skip_token (EQUAL)) | |
4980 | { | |
4981 | skip_after_semicolon (); | |
4982 | return nullptr; | |
4983 | } | |
4984 | ||
4985 | // parse static item expression (required) | |
4986 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
4987 | ||
4988 | if (!skip_token (SEMICOLON)) | |
4989 | { | |
4990 | // skip after somewhere | |
4991 | return nullptr; | |
4992 | } | |
4993 | ||
4994 | return std::unique_ptr<AST::StaticItem> ( | |
4995 | new AST::StaticItem (std::move (ident), is_mut, std::move (type), | |
4996 | std::move (expr), std::move (vis), | |
4997 | std::move (outer_attrs), locus)); | |
4998 | } | |
4999 | ||
5000 | // Parses a trait definition item, including unsafe ones. | |
5001 | template <typename ManagedTokenSource> | |
5002 | std::unique_ptr<AST::Trait> | |
5003 | Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis, | |
5004 | AST::AttrVec outer_attrs) | |
5005 | { | |
5006 | location_t locus = lexer.peek_token ()->get_locus (); | |
5007 | bool is_unsafe = false; | |
5008 | bool is_auto_trait = false; | |
5009 | ||
5010 | if (lexer.peek_token ()->get_id () == UNSAFE) | |
5011 | { | |
5012 | is_unsafe = true; | |
5013 | lexer.skip_token (); | |
5014 | } | |
5015 | ||
5016 | if (lexer.peek_token ()->get_id () == AUTO) | |
5017 | { | |
5018 | is_auto_trait = true; | |
5019 | lexer.skip_token (); | |
5020 | } | |
5021 | ||
5022 | skip_token (TRAIT); | |
5023 | ||
5024 | // parse trait name | |
5025 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
5026 | if (ident_tok == nullptr) | |
5027 | return nullptr; | |
5028 | ||
5029 | Identifier ident{ident_tok}; | |
5030 | ||
5031 | // parse generic parameters (if they exist) | |
5032 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
5033 | = parse_generic_params_in_angles (); | |
5034 | ||
5035 | // create placeholder type param bounds in case they don't exist | |
5036 | std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds; | |
5037 | ||
5038 | // parse type param bounds (if they exist) | |
5039 | if (lexer.peek_token ()->get_id () == COLON) | |
5040 | { | |
5041 | lexer.skip_token (); | |
5042 | ||
5043 | type_param_bounds = parse_type_param_bounds ( | |
5044 | [] (TokenId id) { return id == WHERE || id == LEFT_CURLY; }); | |
5045 | // type_param_bounds = parse_type_param_bounds (); | |
5046 | } | |
5047 | ||
5048 | // parse where clause (if it exists) | |
5049 | AST::WhereClause where_clause = parse_where_clause (); | |
5050 | ||
5051 | if (!skip_token (LEFT_CURLY)) | |
5052 | { | |
5053 | skip_after_end_block (); | |
5054 | return nullptr; | |
5055 | } | |
5056 | ||
5057 | // parse inner attrs (if they exist) | |
5058 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
5059 | ||
5060 | // parse trait items | |
5061 | std::vector<std::unique_ptr<AST::AssociatedItem>> trait_items; | |
5062 | ||
5063 | const_TokenPtr t = lexer.peek_token (); | |
5064 | while (t->get_id () != RIGHT_CURLY) | |
5065 | { | |
5066 | std::unique_ptr<AST::AssociatedItem> trait_item = parse_trait_item (); | |
5067 | ||
5068 | if (trait_item == nullptr) | |
5069 | { | |
5070 | Error error (lexer.peek_token ()->get_locus (), | |
5071 | "failed to parse trait item in trait"); | |
5072 | add_error (std::move (error)); | |
5073 | ||
5074 | return nullptr; | |
5075 | } | |
5076 | trait_items.push_back (std::move (trait_item)); | |
5077 | ||
5078 | t = lexer.peek_token (); | |
5079 | } | |
5080 | ||
5081 | if (!skip_token (RIGHT_CURLY)) | |
5082 | { | |
5083 | // skip after something | |
5084 | return nullptr; | |
5085 | } | |
5086 | ||
5087 | trait_items.shrink_to_fit (); | |
5088 | return std::unique_ptr<AST::Trait> ( | |
5089 | new AST::Trait (std::move (ident), is_unsafe, is_auto_trait, | |
5090 | std::move (generic_params), std::move (type_param_bounds), | |
5091 | std::move (where_clause), std::move (trait_items), | |
5092 | std::move (vis), std::move (outer_attrs), | |
5093 | std::move (inner_attrs), locus)); | |
5094 | } | |
5095 | ||
5096 | // Parses a trait item used inside traits (not trait, the Item). | |
5097 | template <typename ManagedTokenSource> | |
5098 | std::unique_ptr<AST::AssociatedItem> | |
5099 | Parser<ManagedTokenSource>::parse_trait_item () | |
5100 | { | |
5101 | // parse outer attributes (if they exist) | |
5102 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
5103 | ||
5104 | AST::Visibility vis = parse_visibility (); | |
5105 | ||
5106 | // lookahead to determine what type of trait item to parse | |
5107 | const_TokenPtr tok = lexer.peek_token (); | |
5108 | switch (tok->get_id ()) | |
5109 | { | |
5110 | case SUPER: | |
5111 | case SELF: | |
5112 | case CRATE: | |
5113 | case DOLLAR_SIGN: | |
5114 | // these seem to be SimplePath tokens, so this is a macro invocation | |
5115 | // semi | |
5116 | return parse_macro_invocation_semi (std::move (outer_attrs)); | |
5117 | case IDENTIFIER: | |
5118 | if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT) | |
5119 | return parse_function (std::move (vis), std::move (outer_attrs)); | |
5120 | else | |
5121 | return parse_macro_invocation_semi (std::move (outer_attrs)); | |
5122 | case TYPE: | |
5123 | return parse_trait_type (std::move (outer_attrs), vis); | |
5124 | case CONST: | |
5125 | // disambiguate with function qualifier | |
5126 | if (lexer.peek_token (1)->get_id () == IDENTIFIER) | |
5127 | { | |
5128 | return parse_trait_const (std::move (outer_attrs)); | |
5129 | } | |
5130 | // else, fallthrough to function | |
5131 | // TODO: find out how to disable gcc "implicit fallthrough" error | |
5132 | gcc_fallthrough (); | |
5133 | case ASYNC: | |
5134 | case UNSAFE: | |
5135 | case EXTERN_KW: | |
5136 | case FN_KW: | |
5137 | return parse_function (std::move (vis), std::move (outer_attrs)); | |
5138 | default: | |
5139 | break; | |
5140 | } | |
5141 | add_error (Error (tok->get_locus (), | |
5142 | "unrecognised token %qs for item in trait", | |
5143 | tok->get_token_description ())); | |
5144 | // skip? | |
5145 | return nullptr; | |
5146 | } | |
5147 | ||
5148 | // Parse a typedef trait item. | |
5149 | template <typename ManagedTokenSource> | |
5150 | std::unique_ptr<AST::TraitItemType> | |
5151 | Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs, | |
5152 | AST::Visibility vis) | |
5153 | { | |
5154 | location_t locus = lexer.peek_token ()->get_locus (); | |
5155 | skip_token (TYPE); | |
5156 | ||
5157 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
5158 | if (ident_tok == nullptr) | |
5159 | return nullptr; | |
5160 | ||
5161 | Identifier ident{ident_tok}; | |
5162 | ||
5163 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; | |
5164 | ||
5165 | // parse optional colon | |
5166 | if (lexer.peek_token ()->get_id () == COLON) | |
5167 | { | |
5168 | lexer.skip_token (); | |
5169 | ||
5170 | // parse optional type param bounds | |
5171 | bounds | |
5172 | = parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; }); | |
5173 | // bounds = parse_type_param_bounds (); | |
5174 | } | |
5175 | ||
5176 | if (!skip_token (SEMICOLON)) | |
5177 | { | |
5178 | // skip? | |
5179 | return nullptr; | |
5180 | } | |
5181 | ||
5182 | return std::unique_ptr<AST::TraitItemType> ( | |
5183 | new AST::TraitItemType (std::move (ident), std::move (bounds), | |
5184 | std::move (outer_attrs), vis, locus)); | |
5185 | } | |
5186 | ||
5187 | // Parses a constant trait item. | |
5188 | template <typename ManagedTokenSource> | |
5189 | std::unique_ptr<AST::TraitItemConst> | |
5190 | Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs) | |
5191 | { | |
5192 | location_t locus = lexer.peek_token ()->get_locus (); | |
5193 | skip_token (CONST); | |
5194 | ||
5195 | // parse constant item name | |
5196 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
5197 | if (ident_tok == nullptr) | |
5198 | return nullptr; | |
5199 | ||
5200 | Identifier ident{ident_tok}; | |
5201 | ||
5202 | if (!skip_token (COLON)) | |
5203 | { | |
5204 | skip_after_semicolon (); | |
5205 | return nullptr; | |
5206 | } | |
5207 | ||
5208 | // parse constant trait item type | |
5209 | std::unique_ptr<AST::Type> type = parse_type (); | |
5210 | ||
5211 | // parse constant trait body expression, if it exists | |
5212 | std::unique_ptr<AST::Expr> const_body = nullptr; | |
5213 | if (lexer.peek_token ()->get_id () == EQUAL) | |
5214 | { | |
5215 | lexer.skip_token (); | |
5216 | ||
5217 | // expression must exist, so parse it | |
5218 | const_body = parse_expr (); | |
5219 | } | |
5220 | ||
5221 | if (!skip_token (SEMICOLON)) | |
5222 | { | |
5223 | // skip after something? | |
5224 | return nullptr; | |
5225 | } | |
5226 | ||
5227 | return std::unique_ptr<AST::TraitItemConst> ( | |
5228 | new AST::TraitItemConst (std::move (ident), std::move (type), | |
5229 | std::move (const_body), std::move (outer_attrs), | |
5230 | locus)); | |
5231 | } | |
5232 | ||
5233 | /* Parses a struct "impl" item (both inherent impl and trait impl can be | |
5234 | * parsed here), */ | |
5235 | template <typename ManagedTokenSource> | |
5236 | std::unique_ptr<AST::Impl> | |
5237 | Parser<ManagedTokenSource>::parse_impl (AST::Visibility vis, | |
5238 | AST::AttrVec outer_attrs) | |
5239 | { | |
5240 | /* Note that only trait impls are allowed to be unsafe. So if unsafe, it | |
5241 | * must be a trait impl. However, this isn't enough for full disambiguation, | |
5242 | * so don't branch here. */ | |
5243 | location_t locus = lexer.peek_token ()->get_locus (); | |
5244 | bool is_unsafe = false; | |
5245 | if (lexer.peek_token ()->get_id () == UNSAFE) | |
5246 | { | |
5247 | lexer.skip_token (); | |
5248 | is_unsafe = true; | |
5249 | } | |
5250 | ||
5251 | if (!skip_token (IMPL)) | |
5252 | { | |
5253 | skip_after_next_block (); | |
5254 | return nullptr; | |
5255 | } | |
5256 | ||
5257 | // parse generic params (shared by trait and inherent impls) | |
5258 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
5259 | = parse_generic_params_in_angles (); | |
5260 | ||
5261 | // Again, trait impl-only feature, but optional one, so can be used for | |
5262 | // branching yet. | |
5263 | bool has_exclam = false; | |
5264 | if (lexer.peek_token ()->get_id () == EXCLAM) | |
5265 | { | |
5266 | lexer.skip_token (); | |
5267 | has_exclam = true; | |
5268 | } | |
5269 | ||
5270 | /* FIXME: code that doesn't look shit for TypePath. Also, make sure this | |
5271 | * doesn't parse too much and not work. */ | |
5272 | AST::TypePath type_path = parse_type_path (); | |
5273 | if (type_path.is_error () || lexer.peek_token ()->get_id () != FOR) | |
5274 | { | |
5275 | /* cannot parse type path (or not for token next, at least), so must be | |
5276 | * inherent impl */ | |
5277 | ||
5278 | // hacky conversion of TypePath stack object to Type pointer | |
5279 | std::unique_ptr<AST::Type> type = nullptr; | |
5280 | if (!type_path.is_error ()) | |
5281 | type = std::unique_ptr<AST::TypePath> ( | |
5282 | new AST::TypePath (std::move (type_path))); | |
5283 | else | |
5284 | type = parse_type (); | |
5285 | ||
5286 | // Type is required, so error if null | |
5287 | if (type == nullptr) | |
5288 | { | |
5289 | Error error (lexer.peek_token ()->get_locus (), | |
5290 | "could not parse type in inherent impl"); | |
5291 | add_error (std::move (error)); | |
5292 | ||
5293 | skip_after_next_block (); | |
5294 | return nullptr; | |
5295 | } | |
5296 | ||
5297 | // parse optional where clause | |
5298 | AST::WhereClause where_clause = parse_where_clause (); | |
5299 | ||
5300 | if (!skip_token (LEFT_CURLY)) | |
5301 | { | |
5302 | // TODO: does this still skip properly? | |
5303 | skip_after_end_block (); | |
5304 | return nullptr; | |
5305 | } | |
5306 | ||
5307 | // parse inner attributes (optional) | |
5308 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
5309 | ||
5310 | // parse inherent impl items | |
5311 | std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items; | |
5312 | ||
5313 | const_TokenPtr t = lexer.peek_token (); | |
5314 | while (t->get_id () != RIGHT_CURLY) | |
5315 | { | |
5316 | std::unique_ptr<AST::AssociatedItem> impl_item | |
5317 | = parse_inherent_impl_item (); | |
5318 | ||
5319 | if (impl_item == nullptr) | |
5320 | { | |
5321 | Error error ( | |
5322 | lexer.peek_token ()->get_locus (), | |
5323 | "failed to parse inherent impl item in inherent impl"); | |
5324 | add_error (std::move (error)); | |
5325 | ||
5326 | return nullptr; | |
5327 | } | |
5328 | ||
5329 | impl_items.push_back (std::move (impl_item)); | |
5330 | ||
5331 | t = lexer.peek_token (); | |
5332 | } | |
5333 | ||
5334 | if (!skip_token (RIGHT_CURLY)) | |
5335 | { | |
5336 | // skip somewhere | |
5337 | return nullptr; | |
5338 | } | |
5339 | ||
5340 | // DEBUG | |
5341 | rust_debug ("successfully parsed inherent impl"); | |
5342 | ||
5343 | impl_items.shrink_to_fit (); | |
5344 | ||
5345 | return std::unique_ptr<AST::InherentImpl> (new AST::InherentImpl ( | |
5346 | std::move (impl_items), std::move (generic_params), std::move (type), | |
5347 | std::move (where_clause), std::move (vis), std::move (inner_attrs), | |
5348 | std::move (outer_attrs), locus)); | |
5349 | } | |
5350 | else | |
5351 | { | |
5352 | // type path must both be valid and next token is for, so trait impl | |
5353 | if (!skip_token (FOR)) | |
5354 | { | |
5355 | skip_after_next_block (); | |
5356 | return nullptr; | |
5357 | } | |
5358 | ||
5359 | // parse type | |
5360 | std::unique_ptr<AST::Type> type = parse_type (); | |
5361 | // ensure type is included as it is required | |
5362 | if (type == nullptr) | |
5363 | { | |
5364 | Error error (lexer.peek_token ()->get_locus (), | |
5365 | "could not parse type in trait impl"); | |
5366 | add_error (std::move (error)); | |
5367 | ||
5368 | skip_after_next_block (); | |
5369 | return nullptr; | |
5370 | } | |
5371 | ||
5372 | // parse optional where clause | |
5373 | AST::WhereClause where_clause = parse_where_clause (); | |
5374 | ||
5375 | if (!skip_token (LEFT_CURLY)) | |
5376 | { | |
5377 | // TODO: does this still skip properly? | |
5378 | skip_after_end_block (); | |
5379 | return nullptr; | |
5380 | } | |
5381 | ||
5382 | // parse inner attributes (optional) | |
5383 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
5384 | ||
5385 | // parse trait impl items | |
5386 | std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items; | |
5387 | ||
5388 | const_TokenPtr t = lexer.peek_token (); | |
5389 | while (t->get_id () != RIGHT_CURLY) | |
5390 | { | |
5391 | std::unique_ptr<AST::AssociatedItem> impl_item | |
5392 | = parse_trait_impl_item (); | |
5393 | ||
5394 | if (impl_item == nullptr) | |
5395 | { | |
5396 | Error error (lexer.peek_token ()->get_locus (), | |
5397 | "failed to parse trait impl item in trait impl"); | |
5398 | add_error (std::move (error)); | |
5399 | ||
5400 | return nullptr; | |
5401 | } | |
5402 | ||
5403 | impl_items.push_back (std::move (impl_item)); | |
5404 | ||
5405 | t = lexer.peek_token (); | |
5406 | ||
5407 | // DEBUG | |
5408 | rust_debug ("successfully parsed a trait impl item"); | |
5409 | } | |
5410 | // DEBUG | |
5411 | rust_debug ("successfully finished trait impl items"); | |
5412 | ||
5413 | if (!skip_token (RIGHT_CURLY)) | |
5414 | { | |
5415 | // skip somewhere | |
5416 | return nullptr; | |
5417 | } | |
5418 | ||
5419 | // DEBUG | |
5420 | rust_debug ("successfully parsed trait impl"); | |
5421 | ||
5422 | impl_items.shrink_to_fit (); | |
5423 | ||
5424 | return std::unique_ptr<AST::TraitImpl> ( | |
5425 | new AST::TraitImpl (std::move (type_path), is_unsafe, has_exclam, | |
5426 | std::move (impl_items), std::move (generic_params), | |
5427 | std::move (type), std::move (where_clause), | |
5428 | std::move (vis), std::move (inner_attrs), | |
5429 | std::move (outer_attrs), locus)); | |
5430 | } | |
5431 | } | |
5432 | ||
5433 | // Parses a single inherent impl item (item inside an inherent impl block). | |
5434 | template <typename ManagedTokenSource> | |
5435 | std::unique_ptr<AST::AssociatedItem> | |
5436 | Parser<ManagedTokenSource>::parse_inherent_impl_item () | |
5437 | { | |
5438 | // parse outer attributes (if they exist) | |
5439 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
5440 | ||
5441 | // TODO: cleanup - currently an unreadable mess | |
5442 | ||
5443 | // branch on next token: | |
5444 | const_TokenPtr t = lexer.peek_token (); | |
5445 | switch (t->get_id ()) | |
5446 | { | |
5447 | case IDENTIFIER: | |
5448 | // FIXME: Arthur: Do we need to some lookahead here? | |
5449 | return parse_macro_invocation_semi (outer_attrs); | |
5450 | case SUPER: | |
5451 | case SELF: | |
5452 | case CRATE: | |
5453 | case PUB: { | |
5454 | // visibility, so not a macro invocation semi - must be constant, | |
5455 | // function, or method | |
5456 | AST::Visibility vis = parse_visibility (); | |
5457 | ||
5458 | // TODO: is a recursive call to parse_inherent_impl_item better? | |
5459 | switch (lexer.peek_token ()->get_id ()) | |
5460 | { | |
5461 | case EXTERN_KW: | |
5462 | case UNSAFE: | |
5463 | case FN_KW: | |
5464 | // function or method | |
5465 | return parse_inherent_impl_function_or_method (std::move (vis), | |
5466 | std::move ( | |
5467 | outer_attrs)); | |
5468 | case CONST: | |
5469 | // lookahead to resolve production - could be function/method or | |
5470 | // const item | |
5471 | t = lexer.peek_token (1); | |
5472 | ||
5473 | switch (t->get_id ()) | |
5474 | { | |
5475 | case IDENTIFIER: | |
5476 | case UNDERSCORE: | |
5477 | return parse_const_item (std::move (vis), | |
5478 | std::move (outer_attrs)); | |
5479 | case UNSAFE: | |
5480 | case EXTERN_KW: | |
5481 | case FN_KW: | |
5482 | return parse_inherent_impl_function_or_method (std::move (vis), | |
5483 | std::move ( | |
5484 | outer_attrs)); | |
5485 | default: | |
5486 | add_error (Error (t->get_locus (), | |
5487 | "unexpected token %qs in some sort of const " | |
5488 | "item in inherent impl", | |
5489 | t->get_token_description ())); | |
5490 | ||
5491 | lexer.skip_token (1); // TODO: is this right thing to do? | |
5492 | return nullptr; | |
5493 | } | |
5494 | default: | |
5495 | add_error ( | |
5496 | Error (t->get_locus (), | |
5497 | "unrecognised token %qs for item in inherent impl", | |
5498 | t->get_token_description ())); | |
5499 | // skip? | |
5500 | return nullptr; | |
5501 | } | |
5502 | } | |
5503 | case ASYNC: | |
5504 | case EXTERN_KW: | |
5505 | case UNSAFE: | |
5506 | case FN_KW: | |
5507 | // function or method | |
5508 | return parse_inherent_impl_function_or_method ( | |
5509 | AST::Visibility::create_private (), std::move (outer_attrs)); | |
5510 | case CONST: | |
5511 | /* lookahead to resolve production - could be function/method or const | |
5512 | * item */ | |
5513 | t = lexer.peek_token (1); | |
5514 | ||
5515 | switch (t->get_id ()) | |
5516 | { | |
5517 | case IDENTIFIER: | |
5518 | case UNDERSCORE: | |
5519 | return parse_const_item (AST::Visibility::create_private (), | |
5520 | std::move (outer_attrs)); | |
5521 | case UNSAFE: | |
5522 | case EXTERN_KW: | |
5523 | case FN_KW: | |
5524 | return parse_inherent_impl_function_or_method ( | |
5525 | AST::Visibility::create_private (), std::move (outer_attrs)); | |
5526 | default: | |
5527 | add_error (Error (t->get_locus (), | |
5528 | "unexpected token %qs in some sort of const item " | |
5529 | "in inherent impl", | |
5530 | t->get_token_description ())); | |
5531 | ||
5532 | lexer.skip_token (1); // TODO: is this right thing to do? | |
5533 | return nullptr; | |
5534 | } | |
5535 | rust_unreachable (); | |
5536 | default: | |
5537 | add_error (Error (t->get_locus (), | |
5538 | "unrecognised token %qs for item in inherent impl", | |
5539 | t->get_token_description ())); | |
5540 | ||
5541 | // skip? | |
5542 | return nullptr; | |
5543 | } | |
5544 | } | |
5545 | ||
5546 | /* For internal use only by parse_inherent_impl_item() - splits giant method | |
5547 | * into smaller ones and prevents duplication of logic. Strictly, this parses | |
5548 | * a function or method item inside an inherent impl item block. */ | |
5549 | // TODO: make this a templated function with "return type" as type param - | |
5550 | // InherentImplItem is this specialisation of the template while TraitImplItem | |
5551 | // will be the other. | |
5552 | template <typename ManagedTokenSource> | |
5553 | std::unique_ptr<AST::AssociatedItem> | |
5554 | Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method ( | |
5555 | AST::Visibility vis, AST::AttrVec outer_attrs) | |
5556 | { | |
5557 | location_t locus = lexer.peek_token ()->get_locus (); | |
5558 | // parse function or method qualifiers | |
5559 | AST::FunctionQualifiers qualifiers = parse_function_qualifiers (); | |
5560 | ||
5561 | skip_token (FN_KW); | |
5562 | ||
5563 | // parse function or method name | |
5564 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
5565 | if (ident_tok == nullptr) | |
5566 | return nullptr; | |
5567 | ||
5568 | Identifier ident{ident_tok}; | |
5569 | ||
5570 | // parse generic params | |
5571 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
5572 | = parse_generic_params_in_angles (); | |
5573 | ||
5574 | if (!skip_token (LEFT_PAREN)) | |
5575 | { | |
5576 | // skip after somewhere? | |
5577 | return nullptr; | |
5578 | } | |
5579 | ||
5580 | // now for function vs method disambiguation - method has opening "self" | |
5581 | // param | |
5582 | auto initial_param = parse_self_param (); | |
5583 | ||
5584 | if (!initial_param.has_value () && initial_param.error () != NOT_SELF) | |
5585 | return nullptr; | |
5586 | ||
5587 | /* FIXME: ensure that self param doesn't accidently consume tokens for a | |
5588 | * function one idea is to lookahead up to 4 tokens to see whether self is | |
5589 | * one of them */ | |
5590 | bool is_method = false; | |
5591 | if (initial_param.has_value ()) | |
5592 | { | |
5593 | if ((*initial_param)->is_self ()) | |
5594 | is_method = true; | |
5595 | ||
5596 | /* skip comma so function and method regular params can be parsed in | |
5597 | * same way */ | |
5598 | if (lexer.peek_token ()->get_id () == COMMA) | |
5599 | lexer.skip_token (); | |
5600 | } | |
5601 | ||
5602 | // parse trait function params | |
5603 | std::vector<std::unique_ptr<AST::Param>> function_params | |
5604 | = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; }); | |
5605 | ||
5606 | if (initial_param.has_value ()) | |
5607 | function_params.insert (function_params.begin (), | |
5608 | std::move (*initial_param)); | |
5609 | ||
5610 | if (!skip_token (RIGHT_PAREN)) | |
5611 | { | |
5612 | skip_after_end_block (); | |
5613 | return nullptr; | |
5614 | } | |
5615 | ||
5616 | // parse return type (optional) | |
5617 | std::unique_ptr<AST::Type> return_type = parse_function_return_type (); | |
5618 | ||
5619 | // parse where clause (optional) | |
5620 | AST::WhereClause where_clause = parse_where_clause (); | |
5621 | ||
5622 | tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt; | |
5623 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
5624 | lexer.skip_token (); | |
5625 | else | |
5626 | { | |
5627 | auto result = parse_block_expr (); | |
5628 | ||
5629 | if (result == nullptr) | |
5630 | { | |
5631 | Error error ( | |
5632 | lexer.peek_token ()->get_locus (), | |
5633 | "could not parse definition in inherent impl %s definition", | |
5634 | is_method ? "method" : "function"); | |
5635 | add_error (std::move (error)); | |
5636 | ||
5637 | skip_after_end_block (); | |
5638 | return nullptr; | |
5639 | } | |
5640 | body = std::move (result); | |
5641 | } | |
5642 | ||
5643 | return std::unique_ptr<AST::Function> ( | |
5644 | new AST::Function (std::move (ident), std::move (qualifiers), | |
5645 | std::move (generic_params), std::move (function_params), | |
5646 | std::move (return_type), std::move (where_clause), | |
5647 | std::move (body), std::move (vis), | |
5648 | std::move (outer_attrs), locus)); | |
5649 | } | |
5650 | ||
5651 | // Parses a single trait impl item (item inside a trait impl block). | |
5652 | template <typename ManagedTokenSource> | |
5653 | std::unique_ptr<AST::AssociatedItem> | |
5654 | Parser<ManagedTokenSource>::parse_trait_impl_item () | |
5655 | { | |
5656 | // parse outer attributes (if they exist) | |
5657 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
5658 | ||
5659 | auto visibility = AST::Visibility::create_private (); | |
5660 | if (lexer.peek_token ()->get_id () == PUB) | |
5661 | visibility = parse_visibility (); | |
5662 | ||
5663 | // branch on next token: | |
5664 | const_TokenPtr t = lexer.peek_token (); | |
5665 | switch (t->get_id ()) | |
5666 | { | |
5667 | case SUPER: | |
5668 | case SELF: | |
5669 | case CRATE: | |
5670 | case DOLLAR_SIGN: | |
5671 | // these seem to be SimplePath tokens, so this is a macro invocation | |
5672 | // semi | |
5673 | return parse_macro_invocation_semi (std::move (outer_attrs)); | |
5674 | case IDENTIFIER: | |
5675 | if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT) | |
5676 | return parse_trait_impl_function_or_method (visibility, | |
5677 | std::move (outer_attrs)); | |
5678 | else | |
5679 | return parse_macro_invocation_semi (std::move (outer_attrs)); | |
5680 | case TYPE: | |
5681 | return parse_type_alias (visibility, std::move (outer_attrs)); | |
5682 | case EXTERN_KW: | |
5683 | case UNSAFE: | |
5684 | case FN_KW: | |
5685 | // function or method | |
5686 | return parse_trait_impl_function_or_method (visibility, | |
5687 | std::move (outer_attrs)); | |
5688 | case ASYNC: | |
5689 | return parse_async_item (visibility, std::move (outer_attrs)); | |
5690 | case CONST: | |
5691 | // lookahead to resolve production - could be function/method or const | |
5692 | // item | |
5693 | t = lexer.peek_token (1); | |
5694 | ||
5695 | switch (t->get_id ()) | |
5696 | { | |
5697 | case IDENTIFIER: | |
5698 | case UNDERSCORE: | |
5699 | return parse_const_item (visibility, std::move (outer_attrs)); | |
5700 | case UNSAFE: | |
5701 | case EXTERN_KW: | |
5702 | case FN_KW: | |
5703 | return parse_trait_impl_function_or_method (visibility, | |
5704 | std::move (outer_attrs)); | |
5705 | default: | |
5706 | add_error (Error ( | |
5707 | t->get_locus (), | |
5708 | "unexpected token %qs in some sort of const item in trait impl", | |
5709 | t->get_token_description ())); | |
5710 | ||
5711 | lexer.skip_token (1); // TODO: is this right thing to do? | |
5712 | return nullptr; | |
5713 | } | |
5714 | rust_unreachable (); | |
5715 | default: | |
5716 | break; | |
5717 | } | |
5718 | add_error (Error (t->get_locus (), | |
5719 | "unrecognised token %qs for item in trait impl", | |
5720 | t->get_token_description ())); | |
5721 | ||
5722 | // skip? | |
5723 | return nullptr; | |
5724 | } | |
5725 | ||
5726 | /* For internal use only by parse_trait_impl_item() - splits giant method into | |
5727 | * smaller ones and prevents duplication of logic. Strictly, this parses a | |
5728 | * function or method item inside a trait impl item block. */ | |
5729 | template <typename ManagedTokenSource> | |
5730 | std::unique_ptr<AST::AssociatedItem> | |
5731 | Parser<ManagedTokenSource>::parse_trait_impl_function_or_method ( | |
5732 | AST::Visibility vis, AST::AttrVec outer_attrs) | |
5733 | { | |
5734 | // this shares virtually all logic with | |
5735 | // parse_inherent_impl_function_or_method | |
5736 | // - template? | |
5737 | location_t locus = lexer.peek_token ()->get_locus (); | |
5738 | ||
5739 | auto is_default = false; | |
5740 | auto t = lexer.peek_token (); | |
5741 | if (t->get_id () == IDENTIFIER | |
5742 | && t->get_str () == Values::WeakKeywords::DEFAULT) | |
5743 | { | |
5744 | is_default = true; | |
5745 | lexer.skip_token (); | |
5746 | } | |
5747 | ||
5748 | // parse function or method qualifiers | |
5749 | AST::FunctionQualifiers qualifiers = parse_function_qualifiers (); | |
5750 | ||
5751 | skip_token (FN_KW); | |
5752 | ||
5753 | // parse function or method name | |
5754 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
5755 | if (ident_tok == nullptr) | |
5756 | { | |
5757 | return nullptr; | |
5758 | } | |
5759 | Identifier ident{ident_tok}; | |
5760 | ||
5761 | // DEBUG: | |
5762 | rust_debug ( | |
5763 | "about to start parsing generic params in trait impl function or method"); | |
5764 | ||
5765 | // parse generic params | |
5766 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
5767 | = parse_generic_params_in_angles (); | |
5768 | ||
5769 | // DEBUG: | |
5770 | rust_debug ( | |
5771 | "finished parsing generic params in trait impl function or method"); | |
5772 | ||
5773 | if (!skip_token (LEFT_PAREN)) | |
5774 | { | |
5775 | // skip after somewhere? | |
5776 | return nullptr; | |
5777 | } | |
5778 | ||
5779 | // now for function vs method disambiguation - method has opening "self" | |
5780 | // param | |
5781 | auto initial_param = parse_self_param (); | |
5782 | ||
5783 | if (!initial_param.has_value () && initial_param.error () != NOT_SELF) | |
5784 | return nullptr; | |
5785 | ||
5786 | // FIXME: ensure that self param doesn't accidently consume tokens for a | |
5787 | // function | |
5788 | bool is_method = false; | |
5789 | if (initial_param.has_value ()) | |
5790 | { | |
5791 | if ((*initial_param)->is_self ()) | |
5792 | is_method = true; | |
5793 | ||
5794 | // skip comma so function and method regular params can be parsed in | |
5795 | // same way | |
5796 | if (lexer.peek_token ()->get_id () == COMMA) | |
5797 | { | |
5798 | lexer.skip_token (); | |
5799 | } | |
5800 | ||
5801 | // DEBUG | |
5802 | rust_debug ("successfully parsed self param in method trait impl item"); | |
5803 | } | |
5804 | ||
5805 | // DEBUG | |
5806 | rust_debug ( | |
5807 | "started to parse function params in function or method trait impl item"); | |
5808 | ||
5809 | // parse trait function params (only if next token isn't right paren) | |
5810 | std::vector<std::unique_ptr<AST::Param>> function_params; | |
5811 | if (lexer.peek_token ()->get_id () != RIGHT_PAREN) | |
5812 | { | |
5813 | function_params | |
5814 | = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; }); | |
5815 | ||
5816 | if (function_params.empty ()) | |
5817 | { | |
5818 | Error error ( | |
5819 | lexer.peek_token ()->get_locus (), | |
5820 | "failed to parse function params in trait impl %s definition", | |
5821 | is_method ? "method" : "function"); | |
5822 | add_error (std::move (error)); | |
5823 | ||
5824 | skip_after_next_block (); | |
5825 | return nullptr; | |
5826 | } | |
5827 | } | |
5828 | ||
5829 | if (initial_param.has_value ()) | |
5830 | function_params.insert (function_params.begin (), | |
5831 | std::move (*initial_param)); | |
5832 | ||
5833 | // DEBUG | |
5834 | rust_debug ("successfully parsed function params in function or method " | |
5835 | "trait impl item"); | |
5836 | ||
5837 | if (!skip_token (RIGHT_PAREN)) | |
5838 | { | |
5839 | skip_after_next_block (); | |
5840 | return nullptr; | |
5841 | } | |
5842 | ||
5843 | // parse return type (optional) | |
5844 | std::unique_ptr<AST::Type> return_type = parse_function_return_type (); | |
5845 | ||
5846 | // DEBUG | |
5847 | rust_debug ( | |
5848 | "successfully parsed return type in function or method trait impl item"); | |
5849 | ||
5850 | // parse where clause (optional) | |
5851 | AST::WhereClause where_clause = parse_where_clause (); | |
5852 | ||
5853 | // DEBUG | |
5854 | rust_debug ( | |
5855 | "successfully parsed where clause in function or method trait impl item"); | |
5856 | ||
5857 | // parse function definition (in block) - semicolon not allowed | |
5858 | tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt; | |
5859 | ||
5860 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
5861 | lexer.skip_token (); | |
5862 | else | |
5863 | { | |
5864 | auto result = parse_block_expr (); | |
5865 | if (result == nullptr) | |
5866 | { | |
5867 | Error error (lexer.peek_token ()->get_locus (), | |
5868 | "could not parse definition in trait impl %s definition", | |
5869 | is_method ? "method" : "function"); | |
5870 | add_error (std::move (error)); | |
5871 | ||
5872 | skip_after_end_block (); | |
5873 | return nullptr; | |
5874 | } | |
5875 | body = std::move (result); | |
5876 | } | |
5877 | ||
5878 | return std::unique_ptr<AST::Function> ( | |
5879 | new AST::Function (std::move (ident), std::move (qualifiers), | |
5880 | std::move (generic_params), std::move (function_params), | |
5881 | std::move (return_type), std::move (where_clause), | |
5882 | std::move (body), std::move (vis), | |
5883 | std::move (outer_attrs), locus, is_default)); | |
5884 | } | |
5885 | ||
5886 | // Parses an extern block of declarations. | |
5887 | template <typename ManagedTokenSource> | |
5888 | std::unique_ptr<AST::ExternBlock> | |
5889 | Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis, | |
5890 | AST::AttrVec outer_attrs) | |
5891 | { | |
5892 | location_t locus = lexer.peek_token ()->get_locus (); | |
5893 | skip_token (EXTERN_KW); | |
5894 | ||
5895 | // detect optional abi name | |
5896 | std::string abi; | |
5897 | const_TokenPtr next_tok = lexer.peek_token (); | |
5898 | if (next_tok->get_id () == STRING_LITERAL) | |
5899 | { | |
5900 | lexer.skip_token (); | |
5901 | abi = next_tok->get_str (); | |
5902 | } | |
5903 | ||
5904 | if (!skip_token (LEFT_CURLY)) | |
5905 | { | |
5906 | skip_after_end_block (); | |
5907 | return nullptr; | |
5908 | } | |
5909 | ||
5910 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
5911 | ||
5912 | // parse declarations inside extern block | |
5913 | std::vector<std::unique_ptr<AST::ExternalItem>> extern_items; | |
5914 | ||
5915 | const_TokenPtr t = lexer.peek_token (); | |
5916 | while (t->get_id () != RIGHT_CURLY) | |
5917 | { | |
5918 | std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item (); | |
5919 | ||
5920 | if (extern_item == nullptr) | |
5921 | { | |
5922 | Error error (t->get_locus (), | |
5923 | "failed to parse external item despite not reaching " | |
5924 | "end of extern block"); | |
5925 | add_error (std::move (error)); | |
5926 | ||
5927 | return nullptr; | |
5928 | } | |
5929 | ||
5930 | extern_items.push_back (std::move (extern_item)); | |
5931 | ||
5932 | t = lexer.peek_token (); | |
5933 | } | |
5934 | ||
5935 | if (!skip_token (RIGHT_CURLY)) | |
5936 | { | |
5937 | // skip somewhere | |
5938 | return nullptr; | |
5939 | } | |
5940 | ||
5941 | extern_items.shrink_to_fit (); | |
5942 | ||
5943 | return std::unique_ptr<AST::ExternBlock> ( | |
5944 | new AST::ExternBlock (std::move (abi), std::move (extern_items), | |
5945 | std::move (vis), std::move (inner_attrs), | |
5946 | std::move (outer_attrs), locus)); | |
5947 | } | |
5948 | ||
5949 | // Parses a single extern block item (static or function declaration). | |
5950 | template <typename ManagedTokenSource> | |
5951 | std::unique_ptr<AST::ExternalItem> | |
5952 | Parser<ManagedTokenSource>::parse_external_item () | |
5953 | { | |
5954 | // parse optional outer attributes | |
5955 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
5956 | ||
5957 | location_t locus = lexer.peek_token ()->get_locus (); | |
5958 | ||
5959 | // parse optional visibility | |
5960 | AST::Visibility vis = parse_visibility (); | |
5961 | ||
5962 | const_TokenPtr t = lexer.peek_token (); | |
5963 | switch (t->get_id ()) | |
5964 | { | |
5965 | case IDENTIFIER: | |
5966 | return parse_macro_invocation_semi (outer_attrs); | |
5967 | case STATIC_KW: { | |
5968 | // parse extern static item | |
5969 | lexer.skip_token (); | |
5970 | ||
5971 | // parse mut (optional) | |
5972 | bool has_mut = false; | |
5973 | if (lexer.peek_token ()->get_id () == MUT) | |
5974 | { | |
5975 | lexer.skip_token (); | |
5976 | has_mut = true; | |
5977 | } | |
5978 | ||
5979 | // parse identifier | |
5980 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
5981 | if (ident_tok == nullptr) | |
5982 | { | |
5983 | skip_after_semicolon (); | |
5984 | return nullptr; | |
5985 | } | |
5986 | Identifier ident{ident_tok}; | |
5987 | ||
5988 | if (!skip_token (COLON)) | |
5989 | { | |
5990 | skip_after_semicolon (); | |
5991 | return nullptr; | |
5992 | } | |
5993 | ||
5994 | // parse type (required) | |
5995 | std::unique_ptr<AST::Type> type = parse_type (); | |
5996 | if (type == nullptr) | |
5997 | { | |
5998 | Error error (lexer.peek_token ()->get_locus (), | |
5999 | "failed to parse type in external static item"); | |
6000 | add_error (std::move (error)); | |
6001 | ||
6002 | skip_after_semicolon (); | |
6003 | return nullptr; | |
6004 | } | |
6005 | ||
6006 | if (!skip_token (SEMICOLON)) | |
6007 | { | |
6008 | // skip after somewhere? | |
6009 | return nullptr; | |
6010 | } | |
6011 | ||
6012 | return std::unique_ptr<AST::ExternalStaticItem> ( | |
6013 | new AST::ExternalStaticItem (std::move (ident), std::move (type), | |
6014 | has_mut, std::move (vis), | |
6015 | std::move (outer_attrs), locus)); | |
6016 | } | |
6017 | case FN_KW: | |
6018 | return parse_function (std::move (vis), std::move (outer_attrs), true); | |
6019 | ||
6020 | case TYPE: | |
6021 | return parse_external_type_item (std::move (vis), | |
6022 | std::move (outer_attrs)); | |
6023 | default: | |
6024 | // error | |
6025 | add_error ( | |
6026 | Error (t->get_locus (), | |
6027 | "unrecognised token %qs in extern block item declaration", | |
6028 | t->get_token_description ())); | |
6029 | ||
6030 | skip_after_semicolon (); | |
6031 | return nullptr; | |
6032 | } | |
6033 | } | |
6034 | ||
6035 | // Parses a statement (will further disambiguate any statement). | |
6036 | template <typename ManagedTokenSource> | |
6037 | std::unique_ptr<AST::Stmt> | |
6038 | Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions) | |
6039 | { | |
6040 | // quick exit for empty statement | |
6041 | // FIXME: Can we have empty statements without semicolons? Just nothing? | |
6042 | const_TokenPtr t = lexer.peek_token (); | |
6043 | if (t->get_id () == SEMICOLON) | |
6044 | { | |
6045 | lexer.skip_token (); | |
6046 | return std::unique_ptr<AST::EmptyStmt> ( | |
6047 | new AST::EmptyStmt (t->get_locus ())); | |
6048 | } | |
6049 | ||
6050 | // parse outer attributes | |
6051 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
6052 | ||
6053 | // parsing this will be annoying because of the many different possibilities | |
6054 | /* best may be just to copy paste in parse_item switch, and failing that try | |
6055 | * to parse outer attributes, and then pass them in to either a let | |
6056 | * statement or (fallback) expression statement. */ | |
6057 | // FIXME: think of a way to do this without such a large switch? | |
6058 | t = lexer.peek_token (); | |
6059 | switch (t->get_id ()) | |
6060 | { | |
6061 | case LET: | |
6062 | // let statement | |
6063 | return parse_let_stmt (std::move (outer_attrs), restrictions); | |
6064 | case PUB: | |
6065 | case MOD: | |
6066 | case EXTERN_KW: | |
6067 | case USE: | |
6068 | case FN_KW: | |
6069 | case TYPE: | |
6070 | case STRUCT_KW: | |
6071 | case ENUM_KW: | |
6072 | case CONST: | |
6073 | case STATIC_KW: | |
6074 | case AUTO: | |
6075 | case TRAIT: | |
6076 | case IMPL: | |
6077 | case MACRO: | |
6078 | /* TODO: implement union keyword but not really because of | |
6079 | * context-dependence crappy hack way to parse a union written below to | |
6080 | * separate it from the good code. */ | |
6081 | // case UNION: | |
6082 | case UNSAFE: // maybe - unsafe traits are a thing | |
6083 | /* if any of these (should be all possible VisItem prefixes), parse a | |
6084 | * VisItem can't parse item because would require reparsing outer | |
6085 | * attributes */ | |
6086 | // may also be unsafe block | |
6087 | if (lexer.peek_token (1)->get_id () == LEFT_CURLY) | |
6088 | { | |
6089 | return parse_expr_stmt (std::move (outer_attrs), restrictions); | |
6090 | } | |
6091 | else | |
6092 | { | |
6093 | return parse_vis_item (std::move (outer_attrs)); | |
6094 | } | |
6095 | break; | |
6096 | // crappy hack to do union "keyword" | |
6097 | case IDENTIFIER: | |
6098 | if (t->get_str () == Values::WeakKeywords::UNION | |
6099 | && lexer.peek_token (1)->get_id () == IDENTIFIER) | |
6100 | { | |
6101 | return parse_vis_item (std::move (outer_attrs)); | |
6102 | // or should this go straight to parsing union? | |
6103 | } | |
6104 | else if (is_macro_rules_def (t)) | |
6105 | { | |
6106 | // macro_rules! macro item | |
6107 | return parse_macro_rules_def (std::move (outer_attrs)); | |
6108 | } | |
6109 | gcc_fallthrough (); | |
6110 | // TODO: find out how to disable gcc "implicit fallthrough" warning | |
6111 | default: | |
6112 | // fallback: expression statement | |
6113 | return parse_expr_stmt (std::move (outer_attrs), restrictions); | |
6114 | break; | |
6115 | } | |
6116 | } | |
6117 | ||
6118 | // Parses a let statement. | |
6119 | template <typename ManagedTokenSource> | |
6120 | std::unique_ptr<AST::LetStmt> | |
6121 | Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs, | |
6122 | ParseRestrictions restrictions) | |
6123 | { | |
6124 | location_t locus = lexer.peek_token ()->get_locus (); | |
6125 | skip_token (LET); | |
6126 | ||
6127 | // parse pattern (required) | |
6128 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
6129 | if (pattern == nullptr) | |
6130 | { | |
6131 | Error error (lexer.peek_token ()->get_locus (), | |
6132 | "failed to parse pattern in let statement"); | |
6133 | add_error (std::move (error)); | |
6134 | ||
6135 | skip_after_semicolon (); | |
6136 | return nullptr; | |
6137 | } | |
6138 | ||
6139 | // parse type declaration (optional) | |
6140 | std::unique_ptr<AST::Type> type = nullptr; | |
6141 | if (lexer.peek_token ()->get_id () == COLON) | |
6142 | { | |
6143 | // must have a type declaration | |
6144 | lexer.skip_token (); | |
6145 | ||
6146 | type = parse_type (); | |
6147 | if (type == nullptr) | |
6148 | { | |
6149 | Error error (lexer.peek_token ()->get_locus (), | |
6150 | "failed to parse type in let statement"); | |
6151 | add_error (std::move (error)); | |
6152 | ||
6153 | skip_after_semicolon (); | |
6154 | return nullptr; | |
6155 | } | |
6156 | } | |
6157 | ||
6158 | // parse expression to set variable to (optional) | |
6159 | std::unique_ptr<AST::Expr> expr = nullptr; | |
6160 | if (lexer.peek_token ()->get_id () == EQUAL) | |
6161 | { | |
6162 | // must have an expression | |
6163 | lexer.skip_token (); | |
6164 | ||
6165 | expr = parse_expr (); | |
6166 | if (expr == nullptr) | |
6167 | { | |
6168 | Error error (lexer.peek_token ()->get_locus (), | |
6169 | "failed to parse expression in let statement"); | |
6170 | add_error (std::move (error)); | |
6171 | ||
6172 | skip_after_semicolon (); | |
6173 | return nullptr; | |
6174 | } | |
6175 | } | |
6176 | ||
6177 | tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt; | |
6178 | if (maybe_skip_token (ELSE)) | |
6179 | else_expr = parse_block_expr (); | |
6180 | ||
6181 | if (restrictions.consume_semi) | |
6182 | { | |
6183 | // `stmt` macro variables are parsed without a semicolon, but should be | |
6184 | // parsed as a full statement when interpolated. This should be handled | |
6185 | // by having the interpolated statement be distinguishable from normal | |
6186 | // tokens, e.g. by NT tokens. | |
6187 | if (restrictions.allow_close_after_expr_stmt) | |
6188 | maybe_skip_token (SEMICOLON); | |
6189 | else if (!skip_token (SEMICOLON)) | |
6190 | return nullptr; | |
6191 | } | |
6192 | ||
6193 | return std::unique_ptr<AST::LetStmt> ( | |
6194 | new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type), | |
6195 | std::move (else_expr), std::move (outer_attrs), locus)); | |
6196 | } | |
6197 | ||
6198 | // Parses a type path. | |
6199 | template <typename ManagedTokenSource> | |
6200 | AST::TypePath | |
6201 | Parser<ManagedTokenSource>::parse_type_path () | |
6202 | { | |
6203 | bool has_opening_scope_resolution = false; | |
6204 | location_t locus = lexer.peek_token ()->get_locus (); | |
6205 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION) | |
6206 | { | |
6207 | has_opening_scope_resolution = true; | |
6208 | lexer.skip_token (); | |
6209 | } | |
6210 | ||
6211 | // create segment vector | |
6212 | std::vector<std::unique_ptr<AST::TypePathSegment>> segments; | |
6213 | ||
6214 | // parse required initial segment | |
6215 | std::unique_ptr<AST::TypePathSegment> initial_segment | |
6216 | = parse_type_path_segment (); | |
6217 | if (initial_segment == nullptr) | |
6218 | { | |
6219 | // skip after somewhere? | |
6220 | // don't necessarily throw error but yeah | |
6221 | return AST::TypePath::create_error (); | |
6222 | } | |
6223 | segments.push_back (std::move (initial_segment)); | |
6224 | ||
6225 | // parse optional segments (as long as scope resolution operator exists) | |
6226 | const_TokenPtr t = lexer.peek_token (); | |
6227 | while (t->get_id () == SCOPE_RESOLUTION) | |
6228 | { | |
6229 | // skip scope resolution operator | |
6230 | lexer.skip_token (); | |
6231 | ||
6232 | // parse the actual segment - it is an error if it doesn't exist now | |
6233 | std::unique_ptr<AST::TypePathSegment> segment | |
6234 | = parse_type_path_segment (); | |
6235 | if (segment == nullptr) | |
6236 | { | |
6237 | // skip after somewhere? | |
6238 | Error error (t->get_locus (), "could not parse type path segment"); | |
6239 | add_error (std::move (error)); | |
6240 | ||
6241 | return AST::TypePath::create_error (); | |
6242 | } | |
6243 | ||
6244 | segments.push_back (std::move (segment)); | |
6245 | ||
6246 | t = lexer.peek_token (); | |
6247 | } | |
6248 | ||
6249 | segments.shrink_to_fit (); | |
6250 | ||
6251 | return AST::TypePath (std::move (segments), locus, | |
6252 | has_opening_scope_resolution); | |
6253 | } | |
6254 | ||
6255 | template <typename ManagedTokenSource> | |
6256 | tl::optional<AST::GenericArg> | |
6257 | Parser<ManagedTokenSource>::parse_generic_arg () | |
6258 | { | |
6259 | auto tok = lexer.peek_token (); | |
6260 | std::unique_ptr<AST::Expr> expr = nullptr; | |
6261 | ||
6262 | switch (tok->get_id ()) | |
6263 | { | |
6264 | case IDENTIFIER: { | |
6265 | // This is a bit of a weird situation: With an identifier token, we | |
6266 | // could either have a valid type or a macro (FIXME: anything else?). So | |
6267 | // we need one bit of lookahead to differentiate if this is really | |
6268 | auto next_tok = lexer.peek_token (1); | |
6269 | if (next_tok->get_id () == LEFT_ANGLE | |
6270 | || next_tok->get_id () == SCOPE_RESOLUTION | |
6271 | || next_tok->get_id () == EXCLAM) | |
6272 | { | |
6273 | auto type = parse_type (); | |
6274 | if (type) | |
6275 | return AST::GenericArg::create_type (std::move (type)); | |
6276 | else | |
6277 | return tl::nullopt; | |
6278 | } | |
6279 | else if (next_tok->get_id () == COLON) | |
6280 | { | |
6281 | lexer.skip_token (); // skip ident | |
6282 | lexer.skip_token (); // skip colon | |
6283 | ||
6284 | auto tok = lexer.peek_token (); | |
6285 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds | |
6286 | = parse_type_param_bounds (); | |
6287 | ||
6288 | auto type = std::unique_ptr<AST::TraitObjectType> ( | |
6289 | new AST::TraitObjectType (std::move (bounds), tok->get_locus (), | |
6290 | false)); | |
6291 | if (type) | |
6292 | return AST::GenericArg::create_type (std::move (type)); | |
6293 | else | |
6294 | return tl::nullopt; | |
6295 | } | |
6296 | lexer.skip_token (); | |
6297 | return AST::GenericArg::create_ambiguous (tok->get_str (), | |
6298 | tok->get_locus ()); | |
6299 | } | |
6300 | case LEFT_CURLY: | |
6301 | expr = parse_block_expr (); | |
6302 | break; | |
6303 | case MINUS: | |
6304 | case STRING_LITERAL: | |
6305 | case CHAR_LITERAL: | |
6306 | case INT_LITERAL: | |
6307 | case FLOAT_LITERAL: | |
6308 | case TRUE_LITERAL: | |
6309 | case FALSE_LITERAL: | |
6310 | expr = parse_literal_expr (); | |
6311 | break; | |
6312 | // FIXME: Because of this, error reporting is garbage for const generic | |
6313 | // parameter's default values | |
6314 | default: { | |
6315 | auto type = parse_type (); | |
6316 | // FIXME: Find a better way to do this? | |
6317 | if (type) | |
6318 | return AST::GenericArg::create_type (std::move (type)); | |
6319 | else | |
6320 | return tl::nullopt; | |
6321 | } | |
6322 | } | |
6323 | ||
6324 | if (!expr) | |
6325 | return tl::nullopt; | |
6326 | ||
6327 | return AST::GenericArg::create_const (std::move (expr)); | |
6328 | } | |
6329 | ||
6330 | // Parses the generic arguments in each path segment. | |
6331 | template <typename ManagedTokenSource> | |
6332 | AST::GenericArgs | |
6333 | Parser<ManagedTokenSource>::parse_path_generic_args () | |
6334 | { | |
6335 | if (lexer.peek_token ()->get_id () == LEFT_SHIFT) | |
6336 | lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE); | |
6337 | ||
6338 | if (!skip_token (LEFT_ANGLE)) | |
6339 | { | |
6340 | // skip after somewhere? | |
6341 | return AST::GenericArgs::create_empty (); | |
6342 | } | |
6343 | ||
6344 | // We need to parse all lifetimes, then parse types and const generics in | |
6345 | // any order. | |
6346 | ||
6347 | // try to parse lifetimes first | |
6348 | std::vector<AST::Lifetime> lifetime_args; | |
6349 | ||
6350 | const_TokenPtr t = lexer.peek_token (); | |
6351 | location_t locus = t->get_locus (); | |
6352 | while (!is_right_angle_tok (t->get_id ())) | |
6353 | { | |
6354 | auto lifetime = parse_lifetime (false); | |
6355 | if (!lifetime) | |
6356 | { | |
6357 | // not necessarily an error | |
6358 | break; | |
6359 | } | |
6360 | ||
6361 | lifetime_args.push_back (std::move (lifetime.value ())); | |
6362 | ||
6363 | // if next token isn't comma, then it must be end of list | |
6364 | if (lexer.peek_token ()->get_id () != COMMA) | |
6365 | { | |
6366 | break; | |
6367 | } | |
6368 | // skip comma | |
6369 | lexer.skip_token (); | |
6370 | ||
6371 | t = lexer.peek_token (); | |
6372 | } | |
6373 | ||
6374 | // try to parse types and const generics second | |
6375 | std::vector<AST::GenericArg> generic_args; | |
6376 | ||
6377 | // TODO: think of better control structure | |
6378 | t = lexer.peek_token (); | |
6379 | while (!is_right_angle_tok (t->get_id ())) | |
6380 | { | |
6381 | // FIXME: Is it fine to break if there is one binding? Can't there be | |
6382 | // bindings in between types? | |
6383 | ||
6384 | // ensure not binding being parsed as type accidently | |
6385 | if (t->get_id () == IDENTIFIER | |
6386 | && lexer.peek_token (1)->get_id () == EQUAL) | |
6387 | break; | |
6388 | ||
6389 | auto arg = parse_generic_arg (); | |
6390 | if (arg) | |
6391 | { | |
6392 | generic_args.emplace_back (std::move (arg.value ())); | |
6393 | } | |
6394 | ||
6395 | // FIXME: Do we need to break if we encounter an error? | |
6396 | ||
6397 | // if next token isn't comma, then it must be end of list | |
6398 | if (lexer.peek_token ()->get_id () != COMMA) | |
6399 | break; | |
6400 | ||
6401 | // skip comma | |
6402 | lexer.skip_token (); | |
6403 | t = lexer.peek_token (); | |
6404 | } | |
6405 | ||
6406 | // try to parse bindings third | |
6407 | std::vector<AST::GenericArgsBinding> binding_args; | |
6408 | ||
6409 | // TODO: think of better control structure | |
6410 | t = lexer.peek_token (); | |
6411 | while (!is_right_angle_tok (t->get_id ())) | |
6412 | { | |
6413 | AST::GenericArgsBinding binding = parse_generic_args_binding (); | |
6414 | if (binding.is_error ()) | |
6415 | { | |
6416 | // not necessarily an error | |
6417 | break; | |
6418 | } | |
6419 | ||
6420 | binding_args.push_back (std::move (binding)); | |
6421 | ||
6422 | // if next token isn't comma, then it must be end of list | |
6423 | if (lexer.peek_token ()->get_id () != COMMA) | |
6424 | { | |
6425 | break; | |
6426 | } | |
6427 | // skip comma | |
6428 | lexer.skip_token (); | |
6429 | ||
6430 | t = lexer.peek_token (); | |
6431 | } | |
6432 | ||
6433 | // skip any trailing commas | |
6434 | if (lexer.peek_token ()->get_id () == COMMA) | |
6435 | lexer.skip_token (); | |
6436 | ||
6437 | if (!skip_generics_right_angle ()) | |
6438 | return AST::GenericArgs::create_empty (); | |
6439 | ||
6440 | lifetime_args.shrink_to_fit (); | |
6441 | generic_args.shrink_to_fit (); | |
6442 | binding_args.shrink_to_fit (); | |
6443 | ||
6444 | return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args), | |
6445 | std::move (binding_args), locus); | |
6446 | } | |
6447 | ||
6448 | // Parses a binding in a generic args path segment. | |
6449 | template <typename ManagedTokenSource> | |
6450 | AST::GenericArgsBinding | |
6451 | Parser<ManagedTokenSource>::parse_generic_args_binding () | |
6452 | { | |
6453 | const_TokenPtr ident_tok = lexer.peek_token (); | |
6454 | if (ident_tok->get_id () != IDENTIFIER) | |
6455 | { | |
6456 | // allow non error-inducing use | |
6457 | // skip somewhere? | |
6458 | return AST::GenericArgsBinding::create_error (); | |
6459 | } | |
6460 | lexer.skip_token (); | |
6461 | Identifier ident{ident_tok}; | |
6462 | ||
6463 | if (!skip_token (EQUAL)) | |
6464 | { | |
6465 | // skip after somewhere? | |
6466 | return AST::GenericArgsBinding::create_error (); | |
6467 | } | |
6468 | ||
6469 | // parse type (required) | |
6470 | std::unique_ptr<AST::Type> type = parse_type (); | |
6471 | if (type == nullptr) | |
6472 | { | |
6473 | // skip somewhere? | |
6474 | return AST::GenericArgsBinding::create_error (); | |
6475 | } | |
6476 | ||
6477 | return AST::GenericArgsBinding (std::move (ident), std::move (type), | |
6478 | ident_tok->get_locus ()); | |
6479 | } | |
6480 | ||
6481 | /* Parses a single type path segment (not including opening scope resolution, | |
6482 | * but includes any internal ones). Includes generic args or type path | |
6483 | * functions too. */ | |
6484 | template <typename ManagedTokenSource> | |
6485 | std::unique_ptr<AST::TypePathSegment> | |
6486 | Parser<ManagedTokenSource>::parse_type_path_segment () | |
6487 | { | |
6488 | location_t locus = lexer.peek_token ()->get_locus (); | |
6489 | // parse ident segment part | |
6490 | AST::PathIdentSegment ident_segment = parse_path_ident_segment (); | |
6491 | if (ident_segment.is_error ()) | |
6492 | { | |
6493 | // not necessarily an error | |
6494 | return nullptr; | |
6495 | } | |
6496 | ||
6497 | /* lookahead to determine if variants exist - only consume scope resolution | |
6498 | * then */ | |
6499 | bool has_separating_scope_resolution = false; | |
6500 | const_TokenPtr next = lexer.peek_token (1); | |
6501 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION | |
6502 | && (next->get_id () == LEFT_ANGLE || next->get_id () == LEFT_PAREN)) | |
6503 | { | |
6504 | has_separating_scope_resolution = true; | |
6505 | lexer.skip_token (); | |
6506 | } | |
6507 | ||
6508 | // branch into variants on next token | |
6509 | const_TokenPtr t = lexer.peek_token (); | |
6510 | switch (t->get_id ()) | |
6511 | { | |
6512 | case LEFT_SHIFT: | |
6513 | case LEFT_ANGLE: { | |
6514 | // parse generic args | |
6515 | AST::GenericArgs generic_args = parse_path_generic_args (); | |
6516 | ||
6517 | return std::unique_ptr<AST::TypePathSegmentGeneric> ( | |
6518 | new AST::TypePathSegmentGeneric (std::move (ident_segment), | |
6519 | has_separating_scope_resolution, | |
6520 | std::move (generic_args), locus)); | |
6521 | } | |
6522 | case LEFT_PAREN: { | |
6523 | // parse type path function | |
6524 | AST::TypePathFunction type_path_function | |
6525 | = parse_type_path_function (locus); | |
6526 | ||
6527 | if (type_path_function.is_error ()) | |
6528 | { | |
6529 | // skip after somewhere? | |
6530 | return nullptr; | |
6531 | } | |
6532 | ||
6533 | return std::unique_ptr<AST::TypePathSegmentFunction> ( | |
6534 | new AST::TypePathSegmentFunction (std::move (ident_segment), | |
6535 | has_separating_scope_resolution, | |
6536 | std::move (type_path_function), | |
6537 | locus)); | |
6538 | } | |
6539 | default: | |
6540 | // neither of them | |
6541 | return std::unique_ptr<AST::TypePathSegment> ( | |
6542 | new AST::TypePathSegment (std::move (ident_segment), | |
6543 | has_separating_scope_resolution, locus)); | |
6544 | } | |
6545 | rust_unreachable (); | |
6546 | } | |
6547 | ||
6548 | // Parses a function call representation inside a type path. | |
6549 | template <typename ManagedTokenSource> | |
6550 | AST::TypePathFunction | |
6551 | Parser<ManagedTokenSource>::parse_type_path_function (location_t id_location) | |
6552 | { | |
6553 | if (!skip_token (LEFT_PAREN)) | |
6554 | { | |
6555 | // skip somewhere? | |
6556 | return AST::TypePathFunction::create_error (); | |
6557 | } | |
6558 | ||
6559 | // parse function inputs | |
6560 | std::vector<std::unique_ptr<AST::Type>> inputs; | |
6561 | ||
6562 | while (lexer.peek_token ()->get_id () != RIGHT_PAREN) | |
6563 | { | |
6564 | std::unique_ptr<AST::Type> type = parse_type (); | |
6565 | if (type == nullptr) | |
6566 | { | |
6567 | /* this is an error as there should've been a ')' there if there | |
6568 | * wasn't a type */ | |
6569 | Error error ( | |
6570 | lexer.peek_token ()->get_locus (), | |
6571 | "failed to parse type in parameters of type path function"); | |
6572 | add_error (std::move (error)); | |
6573 | ||
6574 | // skip somewhere? | |
6575 | return AST::TypePathFunction::create_error (); | |
6576 | } | |
6577 | ||
6578 | inputs.push_back (std::move (type)); | |
6579 | ||
6580 | // skip commas, including trailing commas | |
6581 | if (lexer.peek_token ()->get_id () != COMMA) | |
6582 | break; | |
6583 | ||
6584 | lexer.skip_token (); | |
6585 | } | |
6586 | ||
6587 | if (!skip_token (RIGHT_PAREN)) | |
6588 | { | |
6589 | // skip somewhere? | |
6590 | return AST::TypePathFunction::create_error (); | |
6591 | } | |
6592 | ||
6593 | // parse optional return type | |
6594 | std::unique_ptr<AST::Type> return_type = parse_function_return_type (); | |
6595 | ||
6596 | inputs.shrink_to_fit (); | |
6597 | return AST::TypePathFunction (std::move (inputs), id_location, | |
6598 | std::move (return_type)); | |
6599 | } | |
6600 | ||
6601 | // Parses a path inside an expression that allows generic arguments. | |
6602 | template <typename ManagedTokenSource> | |
6603 | AST::PathInExpression | |
6604 | Parser<ManagedTokenSource>::parse_path_in_expression () | |
6605 | { | |
6606 | location_t locus = UNKNOWN_LOCATION; | |
6607 | bool has_opening_scope_resolution = false; | |
6608 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION) | |
6609 | { | |
6610 | has_opening_scope_resolution = true; | |
6611 | ||
6612 | locus = lexer.peek_token ()->get_locus (); | |
6613 | ||
6614 | lexer.skip_token (); | |
6615 | } | |
6616 | ||
6617 | // create segment vector | |
6618 | std::vector<AST::PathExprSegment> segments; | |
6619 | ||
6620 | if (locus == UNKNOWN_LOCATION) | |
6621 | { | |
6622 | locus = lexer.peek_token ()->get_locus (); | |
6623 | } | |
6624 | ||
6625 | // parse required initial segment | |
6626 | AST::PathExprSegment initial_segment = parse_path_expr_segment (); | |
6627 | if (initial_segment.is_error ()) | |
6628 | { | |
6629 | // skip after somewhere? | |
6630 | // don't necessarily throw error but yeah | |
6631 | return AST::PathInExpression::create_error (); | |
6632 | } | |
6633 | segments.push_back (std::move (initial_segment)); | |
6634 | ||
6635 | // parse optional segments (as long as scope resolution operator exists) | |
6636 | const_TokenPtr t = lexer.peek_token (); | |
6637 | while (t->get_id () == SCOPE_RESOLUTION) | |
6638 | { | |
6639 | // skip scope resolution operator | |
6640 | lexer.skip_token (); | |
6641 | ||
6642 | // parse the actual segment - it is an error if it doesn't exist now | |
6643 | AST::PathExprSegment segment = parse_path_expr_segment (); | |
6644 | if (segment.is_error ()) | |
6645 | { | |
6646 | // skip after somewhere? | |
6647 | Error error (t->get_locus (), | |
6648 | "could not parse path expression segment"); | |
6649 | add_error (std::move (error)); | |
6650 | ||
6651 | return AST::PathInExpression::create_error (); | |
6652 | } | |
6653 | ||
6654 | segments.push_back (std::move (segment)); | |
6655 | ||
6656 | t = lexer.peek_token (); | |
6657 | } | |
6658 | ||
6659 | segments.shrink_to_fit (); | |
6660 | ||
6661 | return AST::PathInExpression (std::move (segments), {}, locus, | |
6662 | has_opening_scope_resolution); | |
6663 | } | |
6664 | ||
6665 | /* Parses a single path in expression path segment (including generic | |
6666 | * arguments). */ | |
6667 | template <typename ManagedTokenSource> | |
6668 | AST::PathExprSegment | |
6669 | Parser<ManagedTokenSource>::parse_path_expr_segment () | |
6670 | { | |
6671 | location_t locus = lexer.peek_token ()->get_locus (); | |
6672 | // parse ident segment | |
6673 | AST::PathIdentSegment ident = parse_path_ident_segment (); | |
6674 | if (ident.is_error ()) | |
6675 | { | |
6676 | // not necessarily an error? | |
6677 | return AST::PathExprSegment::create_error (); | |
6678 | } | |
6679 | ||
6680 | // parse generic args (and turbofish), if they exist | |
6681 | /* use lookahead to determine if they actually exist (don't want to | |
6682 | * accidently parse over next ident segment) */ | |
6683 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION | |
6684 | && (lexer.peek_token (1)->get_id () == LEFT_ANGLE | |
6685 | || lexer.peek_token (1)->get_id () == LEFT_SHIFT)) | |
6686 | { | |
6687 | // skip scope resolution | |
6688 | lexer.skip_token (); | |
6689 | ||
6690 | // Let parse_path_generic_args split "<<" tokens | |
6691 | AST::GenericArgs generic_args = parse_path_generic_args (); | |
6692 | ||
6693 | return AST::PathExprSegment (std::move (ident), locus, | |
6694 | std::move (generic_args)); | |
6695 | } | |
6696 | ||
6697 | // return a generic parameter-less expr segment if not found | |
6698 | return AST::PathExprSegment (std::move (ident), locus); | |
6699 | } | |
6700 | ||
6701 | /* Parses a fully qualified path in expression (i.e. a pattern). FIXME does | |
6702 | * not parse outer attrs. */ | |
6703 | template <typename ManagedTokenSource> | |
6704 | AST::QualifiedPathInExpression | |
6705 | Parser<ManagedTokenSource>::parse_qualified_path_in_expression ( | |
6706 | location_t pratt_parsed_loc) | |
6707 | { | |
6708 | /* Note: the Rust grammar is defined in such a way that it is impossible to | |
6709 | * determine whether a prospective qualified path is a | |
6710 | * QualifiedPathInExpression or QualifiedPathInType in all cases by the | |
6711 | * rules themselves (the only possible difference is a TypePathSegment with | |
6712 | * function, and lookahead to find this is too difficult). However, as this | |
6713 | * is a pattern and QualifiedPathInType is a type, I believe it that their | |
6714 | * construction will not be confused (due to rules regarding patterns vs | |
6715 | * types). | |
6716 | * As such, this function will not attempt to minimise errors created by | |
6717 | * their confusion. */ | |
6718 | ||
6719 | // parse the qualified path type (required) | |
6720 | AST::QualifiedPathType qual_path_type | |
6721 | = parse_qualified_path_type (pratt_parsed_loc); | |
6722 | if (qual_path_type.is_error ()) | |
6723 | { | |
6724 | // TODO: should this create a parse error? | |
6725 | return AST::QualifiedPathInExpression::create_error (); | |
6726 | } | |
6727 | location_t locus = qual_path_type.get_locus (); | |
6728 | ||
6729 | // parse path segments | |
6730 | std::vector<AST::PathExprSegment> segments; | |
6731 | ||
6732 | // parse initial required segment | |
6733 | if (!expect_token (SCOPE_RESOLUTION)) | |
6734 | { | |
6735 | // skip after somewhere? | |
6736 | ||
6737 | return AST::QualifiedPathInExpression::create_error (); | |
6738 | } | |
6739 | AST::PathExprSegment initial_segment = parse_path_expr_segment (); | |
6740 | if (initial_segment.is_error ()) | |
6741 | { | |
6742 | // skip after somewhere? | |
6743 | Error error (lexer.peek_token ()->get_locus (), | |
6744 | "required initial path expression segment in " | |
6745 | "qualified path in expression could not be parsed"); | |
6746 | add_error (std::move (error)); | |
6747 | ||
6748 | return AST::QualifiedPathInExpression::create_error (); | |
6749 | } | |
6750 | segments.push_back (std::move (initial_segment)); | |
6751 | ||
6752 | // parse optional segments (as long as scope resolution operator exists) | |
6753 | const_TokenPtr t = lexer.peek_token (); | |
6754 | while (t->get_id () == SCOPE_RESOLUTION) | |
6755 | { | |
6756 | // skip scope resolution operator | |
6757 | lexer.skip_token (); | |
6758 | ||
6759 | // parse the actual segment - it is an error if it doesn't exist now | |
6760 | AST::PathExprSegment segment = parse_path_expr_segment (); | |
6761 | if (segment.is_error ()) | |
6762 | { | |
6763 | // skip after somewhere? | |
6764 | Error error (t->get_locus (), | |
6765 | "could not parse path expression segment in qualified " | |
6766 | "path in expression"); | |
6767 | add_error (std::move (error)); | |
6768 | ||
6769 | return AST::QualifiedPathInExpression::create_error (); | |
6770 | } | |
6771 | ||
6772 | segments.push_back (std::move (segment)); | |
6773 | ||
6774 | t = lexer.peek_token (); | |
6775 | } | |
6776 | ||
6777 | segments.shrink_to_fit (); | |
6778 | ||
6779 | // FIXME: outer attr parsing | |
6780 | return AST::QualifiedPathInExpression (std::move (qual_path_type), | |
6781 | std::move (segments), {}, locus); | |
6782 | } | |
6783 | ||
6784 | // Parses the type syntactical construction at the start of a qualified path. | |
6785 | template <typename ManagedTokenSource> | |
6786 | AST::QualifiedPathType | |
6787 | Parser<ManagedTokenSource>::parse_qualified_path_type ( | |
6788 | location_t pratt_parsed_loc) | |
6789 | { | |
6790 | location_t locus = pratt_parsed_loc; | |
6791 | /* TODO: should this actually be error? is there anywhere where this could | |
6792 | * be valid? */ | |
6793 | if (locus == UNKNOWN_LOCATION) | |
6794 | { | |
6795 | locus = lexer.peek_token ()->get_locus (); | |
6796 | ||
6797 | if (lexer.peek_token ()->get_id () == LEFT_SHIFT) | |
6798 | lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE); | |
6799 | ||
6800 | // skip after somewhere? | |
6801 | if (!skip_token (LEFT_ANGLE)) | |
6802 | return AST::QualifiedPathType::create_error (); | |
6803 | } | |
6804 | ||
6805 | // parse type (required) | |
6806 | std::unique_ptr<AST::Type> type = parse_type (); | |
6807 | if (type == nullptr) | |
6808 | { | |
6809 | Error error (lexer.peek_token ()->get_locus (), | |
6810 | "could not parse type in qualified path type"); | |
6811 | add_error (std::move (error)); | |
6812 | ||
6813 | // skip somewhere? | |
6814 | return AST::QualifiedPathType::create_error (); | |
6815 | } | |
6816 | ||
6817 | // parse optional as clause | |
6818 | AST::TypePath as_type_path = AST::TypePath::create_error (); | |
6819 | if (lexer.peek_token ()->get_id () == AS) | |
6820 | { | |
6821 | lexer.skip_token (); | |
6822 | ||
6823 | // parse type path, which is required now | |
6824 | as_type_path = parse_type_path (); | |
6825 | if (as_type_path.is_error ()) | |
6826 | { | |
6827 | Error error ( | |
6828 | lexer.peek_token ()->get_locus (), | |
6829 | "could not parse type path in as clause in qualified path type"); | |
6830 | add_error (std::move (error)); | |
6831 | ||
6832 | // skip somewhere? | |
6833 | return AST::QualifiedPathType::create_error (); | |
6834 | } | |
6835 | } | |
6836 | ||
6837 | /* NOTE: should actually be a right-angle token, so | |
6838 | * skip_generics_right_angle shouldn't be required */ | |
6839 | if (!skip_token (RIGHT_ANGLE)) | |
6840 | { | |
6841 | // skip after somewhere? | |
6842 | return AST::QualifiedPathType::create_error (); | |
6843 | } | |
6844 | ||
6845 | return AST::QualifiedPathType (std::move (type), locus, | |
6846 | std::move (as_type_path)); | |
6847 | } | |
6848 | ||
6849 | // Parses a fully qualified path in type (i.e. a type). | |
6850 | template <typename ManagedTokenSource> | |
6851 | AST::QualifiedPathInType | |
6852 | Parser<ManagedTokenSource>::parse_qualified_path_in_type () | |
6853 | { | |
6854 | location_t locus = lexer.peek_token ()->get_locus (); | |
6855 | // parse the qualified path type (required) | |
6856 | AST::QualifiedPathType qual_path_type = parse_qualified_path_type (); | |
6857 | if (qual_path_type.is_error ()) | |
6858 | { | |
6859 | // TODO: should this create a parse error? | |
6860 | return AST::QualifiedPathInType::create_error (); | |
6861 | } | |
6862 | ||
6863 | // parse initial required segment | |
6864 | if (!expect_token (SCOPE_RESOLUTION)) | |
6865 | { | |
6866 | // skip after somewhere? | |
6867 | ||
6868 | return AST::QualifiedPathInType::create_error (); | |
6869 | } | |
6870 | std::unique_ptr<AST::TypePathSegment> initial_segment | |
6871 | = parse_type_path_segment (); | |
6872 | if (initial_segment == nullptr) | |
6873 | { | |
6874 | // skip after somewhere? | |
6875 | Error error (lexer.peek_token ()->get_locus (), | |
6876 | "required initial type path segment in qualified path in " | |
6877 | "type could not be parsed"); | |
6878 | add_error (std::move (error)); | |
6879 | ||
6880 | return AST::QualifiedPathInType::create_error (); | |
6881 | } | |
6882 | ||
6883 | // parse optional segments (as long as scope resolution operator exists) | |
6884 | std::vector<std::unique_ptr<AST::TypePathSegment>> segments; | |
6885 | const_TokenPtr t = lexer.peek_token (); | |
6886 | while (t->get_id () == SCOPE_RESOLUTION) | |
6887 | { | |
6888 | // skip scope resolution operator | |
6889 | lexer.skip_token (); | |
6890 | ||
6891 | // parse the actual segment - it is an error if it doesn't exist now | |
6892 | std::unique_ptr<AST::TypePathSegment> segment | |
6893 | = parse_type_path_segment (); | |
6894 | if (segment == nullptr) | |
6895 | { | |
6896 | // skip after somewhere? | |
6897 | Error error ( | |
6898 | t->get_locus (), | |
6899 | "could not parse type path segment in qualified path in type"); | |
6900 | add_error (std::move (error)); | |
6901 | ||
6902 | return AST::QualifiedPathInType::create_error (); | |
6903 | } | |
6904 | ||
6905 | segments.push_back (std::move (segment)); | |
6906 | ||
6907 | t = lexer.peek_token (); | |
6908 | } | |
6909 | ||
6910 | segments.shrink_to_fit (); | |
6911 | ||
6912 | return AST::QualifiedPathInType (std::move (qual_path_type), | |
6913 | std::move (initial_segment), | |
6914 | std::move (segments), locus); | |
6915 | } | |
6916 | ||
6917 | // Parses a self param. Also handles self param not existing. | |
6918 | template <typename ManagedTokenSource> | |
6919 | tl::expected<std::unique_ptr<AST::Param>, ParseSelfError> | |
6920 | Parser<ManagedTokenSource>::parse_self_param () | |
6921 | { | |
6922 | bool has_reference = false; | |
6923 | AST::Lifetime lifetime = AST::Lifetime::elided (); | |
6924 | ||
6925 | location_t locus = lexer.peek_token ()->get_locus (); | |
6926 | ||
6927 | // TODO: Feels off, find a better way to clearly express this | |
6928 | std::vector<std::vector<TokenId>> ptrs | |
6929 | = {{ASTERISK, SELF} /* *self */, | |
6930 | {ASTERISK, CONST, SELF} /* *const self */, | |
6931 | {ASTERISK, MUT, SELF} /* *mut self */}; | |
6932 | ||
6933 | for (auto &s : ptrs) | |
6934 | { | |
6935 | size_t i = 0; | |
6936 | for (i = 0; i < s.size (); i++) | |
6937 | if (lexer.peek_token (i)->get_id () != s[i]) | |
6938 | break; | |
6939 | if (i == s.size ()) | |
6940 | { | |
6941 | rust_error_at (lexer.peek_token ()->get_locus (), | |
6942 | "cannot pass %<self%> by raw pointer"); | |
6943 | return tl::make_unexpected (ParseSelfError::SELF_PTR); | |
6944 | } | |
6945 | } | |
6946 | ||
6947 | // Trying to find those patterns: | |
6948 | // | |
6949 | // &'lifetime mut self | |
6950 | // &'lifetime self | |
6951 | // & mut self | |
6952 | // & self | |
6953 | // mut self | |
6954 | // self | |
6955 | // | |
6956 | // If not found, it is probably a function, exit and let function parsing | |
6957 | // handle it. | |
6958 | bool is_self = false; | |
6959 | for (size_t i = 0; i < 5; i++) | |
6960 | if (lexer.peek_token (i)->get_id () == SELF) | |
6961 | is_self = true; | |
6962 | ||
6963 | if (!is_self) | |
6964 | return tl::make_unexpected (ParseSelfError::NOT_SELF); | |
6965 | ||
6966 | // test if self is a reference parameter | |
6967 | if (lexer.peek_token ()->get_id () == AMP) | |
6968 | { | |
6969 | has_reference = true; | |
6970 | lexer.skip_token (); | |
6971 | ||
6972 | // now test whether it has a lifetime | |
6973 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
6974 | { | |
6975 | // something went wrong somehow | |
6976 | if (auto parsed_lifetime = parse_lifetime (true)) | |
6977 | { | |
6978 | lifetime = parsed_lifetime.value (); | |
6979 | } | |
6980 | else | |
6981 | { | |
6982 | Error error (lexer.peek_token ()->get_locus (), | |
6983 | "failed to parse lifetime in self param"); | |
6984 | add_error (std::move (error)); | |
6985 | ||
6986 | // skip after somewhere? | |
6987 | return tl::make_unexpected (ParseSelfError::PARSING); | |
6988 | } | |
6989 | } | |
6990 | } | |
6991 | ||
6992 | // test for mut | |
6993 | bool has_mut = false; | |
6994 | if (lexer.peek_token ()->get_id () == MUT) | |
6995 | { | |
6996 | has_mut = true; | |
6997 | lexer.skip_token (); | |
6998 | } | |
6999 | ||
7000 | // skip self token | |
7001 | const_TokenPtr self_tok = lexer.peek_token (); | |
7002 | if (self_tok->get_id () != SELF) | |
7003 | { | |
7004 | // skip after somewhere? | |
7005 | return tl::make_unexpected (ParseSelfError::NOT_SELF); | |
7006 | } | |
7007 | lexer.skip_token (); | |
7008 | ||
7009 | // parse optional type | |
7010 | std::unique_ptr<AST::Type> type = nullptr; | |
7011 | if (lexer.peek_token ()->get_id () == COLON) | |
7012 | { | |
7013 | lexer.skip_token (); | |
7014 | ||
7015 | // type is now required | |
7016 | type = parse_type (); | |
7017 | if (type == nullptr) | |
7018 | { | |
7019 | Error error (lexer.peek_token ()->get_locus (), | |
7020 | "could not parse type in self param"); | |
7021 | add_error (std::move (error)); | |
7022 | ||
7023 | // skip after somewhere? | |
7024 | return tl::make_unexpected (ParseSelfError::PARSING); | |
7025 | } | |
7026 | } | |
7027 | ||
7028 | // ensure that cannot have both type and reference | |
7029 | if (type != nullptr && has_reference) | |
7030 | { | |
7031 | Error error ( | |
7032 | lexer.peek_token ()->get_locus (), | |
7033 | "cannot have both a reference and a type specified in a self param"); | |
7034 | add_error (std::move (error)); | |
7035 | ||
7036 | // skip after somewhere? | |
7037 | return tl::make_unexpected (ParseSelfError::PARSING); | |
7038 | } | |
7039 | ||
7040 | if (has_reference) | |
7041 | { | |
7042 | return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut, | |
7043 | locus); | |
7044 | } | |
7045 | else | |
7046 | { | |
7047 | // note that type may be nullptr here and that's fine | |
7048 | return std::make_unique<AST::SelfParam> (std::move (type), has_mut, | |
7049 | locus); | |
7050 | } | |
7051 | } | |
7052 | ||
7053 | /* Parses an expression or macro statement. */ | |
7054 | template <typename ManagedTokenSource> | |
7055 | std::unique_ptr<AST::Stmt> | |
7056 | Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, | |
7057 | ParseRestrictions restrictions) | |
7058 | { | |
7059 | location_t locus = lexer.peek_token ()->get_locus (); | |
7060 | ||
7061 | std::unique_ptr<AST::Expr> expr; | |
7062 | ||
7063 | switch (lexer.peek_token ()->get_id ()) | |
7064 | { | |
7065 | case IDENTIFIER: | |
7066 | case CRATE: | |
7067 | case SUPER: | |
7068 | case SELF: | |
7069 | case SELF_ALIAS: | |
7070 | case DOLLAR_SIGN: | |
7071 | case SCOPE_RESOLUTION: { | |
7072 | AST::PathInExpression path = parse_path_in_expression (); | |
7073 | std::unique_ptr<AST::Expr> null_denotation; | |
7074 | ||
7075 | if (lexer.peek_token ()->get_id () == EXCLAM) | |
7076 | { | |
7077 | // Bind a reference to avoid -Wredundant-move on post-P1825R0 | |
7078 | // compilers. Change to non-reference type and remove the moves | |
7079 | // below once C++20 is required to build gcc. | |
7080 | std::unique_ptr<AST::MacroInvocation> &&invoc | |
7081 | = parse_macro_invocation_partial (std::move (path), | |
7082 | std::move (outer_attrs)); | |
7083 | ||
7084 | if (restrictions.consume_semi && maybe_skip_token (SEMICOLON)) | |
7085 | { | |
7086 | invoc->add_semicolon (); | |
7087 | // Macro invocation with semicolon. | |
7088 | return std::move (invoc); | |
7089 | } | |
7090 | ||
7091 | TokenId after_macro = lexer.peek_token ()->get_id (); | |
7092 | ||
7093 | if (restrictions.allow_close_after_expr_stmt | |
7094 | && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY | |
7095 | || after_macro == RIGHT_SQUARE)) | |
7096 | return std::move (invoc); | |
7097 | ||
7098 | if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type () | |
7099 | == AST::CURLY | |
7100 | && after_macro != DOT && after_macro != QUESTION_MARK) | |
7101 | { | |
7102 | rust_debug ("braced macro statement"); | |
7103 | return std::move (invoc); | |
7104 | } | |
7105 | ||
7106 | null_denotation = std::move (invoc); | |
7107 | } | |
7108 | else | |
7109 | { | |
7110 | null_denotation | |
7111 | = null_denotation_path (std::move (path), {}, restrictions); | |
7112 | } | |
7113 | ||
7114 | expr = left_denotations (std::move (null_denotation), LBP_LOWEST, | |
7115 | std::move (outer_attrs), restrictions); | |
7116 | break; | |
7117 | } | |
7118 | default: | |
7119 | restrictions.expr_can_be_stmt = true; | |
7120 | expr = parse_expr (std::move (outer_attrs), restrictions); | |
7121 | break; | |
7122 | } | |
7123 | ||
7124 | if (expr == nullptr) | |
7125 | { | |
7126 | // expr is required, error | |
7127 | Error error (lexer.peek_token ()->get_locus (), | |
7128 | "failed to parse expr in expr statement"); | |
7129 | add_error (std::move (error)); | |
7130 | ||
7131 | skip_after_semicolon (); | |
7132 | return nullptr; | |
7133 | } | |
7134 | ||
7135 | bool has_semi = false; | |
7136 | ||
7137 | if (restrictions.consume_semi) | |
7138 | { | |
7139 | if (maybe_skip_token (SEMICOLON)) | |
7140 | { | |
7141 | has_semi = true; | |
7142 | } | |
7143 | else if (expr->is_expr_without_block ()) | |
7144 | { | |
7145 | if (restrictions.allow_close_after_expr_stmt) | |
7146 | { | |
7147 | TokenId id = lexer.peek_token ()->get_id (); | |
7148 | if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE) | |
7149 | { | |
7150 | expect_token (SEMICOLON); | |
7151 | return nullptr; | |
7152 | } | |
7153 | } | |
7154 | else | |
7155 | { | |
7156 | expect_token (SEMICOLON); | |
7157 | return nullptr; | |
7158 | } | |
7159 | } | |
7160 | } | |
7161 | ||
7162 | return std::unique_ptr<AST::ExprStmt> ( | |
7163 | new AST::ExprStmt (std::move (expr), locus, has_semi)); | |
7164 | } | |
7165 | ||
7166 | // Parses a block expression, including the curly braces at start and end. | |
7167 | template <typename ManagedTokenSource> | |
7168 | std::unique_ptr<AST::BlockExpr> | |
7169 | Parser<ManagedTokenSource>::parse_block_expr ( | |
7170 | AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label, | |
7171 | location_t pratt_parsed_loc) | |
7172 | { | |
7173 | location_t locus = pratt_parsed_loc; | |
7174 | if (locus == UNKNOWN_LOCATION) | |
7175 | { | |
7176 | locus = lexer.peek_token ()->get_locus (); | |
7177 | if (!skip_token (LEFT_CURLY)) | |
7178 | { | |
7179 | skip_after_end_block (); | |
7180 | return nullptr; | |
7181 | } | |
7182 | } | |
7183 | ||
7184 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
7185 | ||
7186 | // parse statements and expression | |
7187 | std::vector<std::unique_ptr<AST::Stmt>> stmts; | |
7188 | std::unique_ptr<AST::Expr> expr = nullptr; | |
7189 | ||
7190 | const_TokenPtr t = lexer.peek_token (); | |
7191 | while (t->get_id () != RIGHT_CURLY) | |
7192 | { | |
7193 | ExprOrStmt expr_or_stmt = parse_stmt_or_expr (); | |
7194 | if (expr_or_stmt.is_error ()) | |
7195 | { | |
7196 | Error error ( | |
7197 | t->get_locus (), | |
7198 | "failed to parse statement or expression in block expression"); | |
7199 | add_error (std::move (error)); | |
7200 | ||
7201 | return nullptr; | |
7202 | } | |
7203 | ||
7204 | t = lexer.peek_token (); | |
7205 | ||
7206 | if (expr_or_stmt.stmt != nullptr) | |
7207 | { | |
7208 | stmts.push_back (std::move (expr_or_stmt.stmt)); | |
7209 | } | |
7210 | else | |
7211 | { | |
7212 | // assign to expression and end parsing inside | |
7213 | expr = std::move (expr_or_stmt.expr); | |
7214 | break; | |
7215 | } | |
7216 | } | |
7217 | ||
7218 | location_t end_locus = t->get_locus (); | |
7219 | ||
7220 | if (!skip_token (RIGHT_CURLY)) | |
7221 | { | |
7222 | Error error (t->get_locus (), | |
7223 | "error may be from having an expression (as opposed to " | |
7224 | "statement) in the body of the function but not last"); | |
7225 | add_error (std::move (error)); | |
7226 | ||
7227 | skip_after_end_block (); | |
7228 | return nullptr; | |
7229 | } | |
7230 | ||
7231 | // grammar allows for empty block expressions | |
7232 | ||
7233 | stmts.shrink_to_fit (); | |
7234 | ||
7235 | return std::unique_ptr<AST::BlockExpr> ( | |
7236 | new AST::BlockExpr (std::move (stmts), std::move (expr), | |
7237 | std::move (inner_attrs), std::move (outer_attrs), | |
7238 | std::move (label), locus, end_locus)); | |
7239 | } | |
7240 | ||
7241 | /* Parses a "grouped" expression (expression in parentheses), used to control | |
7242 | * precedence. */ | |
7243 | template <typename ManagedTokenSource> | |
7244 | std::unique_ptr<AST::GroupedExpr> | |
7245 | Parser<ManagedTokenSource>::parse_grouped_expr (AST::AttrVec outer_attrs) | |
7246 | { | |
7247 | location_t locus = lexer.peek_token ()->get_locus (); | |
7248 | skip_token (LEFT_PAREN); | |
7249 | ||
7250 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
7251 | ||
7252 | // parse required expr inside parentheses | |
7253 | std::unique_ptr<AST::Expr> expr_in_parens = parse_expr (); | |
7254 | if (expr_in_parens == nullptr) | |
7255 | { | |
7256 | // skip after somewhere? | |
7257 | // error? | |
7258 | return nullptr; | |
7259 | } | |
7260 | ||
7261 | if (!skip_token (RIGHT_PAREN)) | |
7262 | { | |
7263 | // skip after somewhere? | |
7264 | return nullptr; | |
7265 | } | |
7266 | ||
7267 | return std::unique_ptr<AST::GroupedExpr> ( | |
7268 | new AST::GroupedExpr (std::move (expr_in_parens), std::move (inner_attrs), | |
7269 | std::move (outer_attrs), locus)); | |
7270 | } | |
7271 | ||
7272 | // Parses a closure expression (closure definition). | |
7273 | template <typename ManagedTokenSource> | |
7274 | std::unique_ptr<AST::ClosureExpr> | |
7275 | Parser<ManagedTokenSource>::parse_closure_expr (AST::AttrVec outer_attrs) | |
7276 | { | |
7277 | location_t locus = lexer.peek_token ()->get_locus (); | |
7278 | // detect optional "move" | |
7279 | bool has_move = false; | |
7280 | if (lexer.peek_token ()->get_id () == MOVE) | |
7281 | { | |
7282 | lexer.skip_token (); | |
7283 | has_move = true; | |
7284 | } | |
7285 | ||
7286 | // handle parameter list | |
7287 | std::vector<AST::ClosureParam> params; | |
7288 | ||
7289 | const_TokenPtr t = lexer.peek_token (); | |
7290 | switch (t->get_id ()) | |
7291 | { | |
7292 | case OR: | |
7293 | // skip token, no parameters | |
7294 | lexer.skip_token (); | |
7295 | break; | |
7296 | case PIPE: | |
7297 | // actually may have parameters | |
7298 | lexer.skip_token (); | |
7299 | t = lexer.peek_token (); | |
7300 | ||
7301 | while (t->get_id () != PIPE) | |
7302 | { | |
7303 | AST::ClosureParam param = parse_closure_param (); | |
7304 | if (param.is_error ()) | |
7305 | { | |
7306 | // TODO is this really an error? | |
7307 | Error error (t->get_locus (), "could not parse closure param"); | |
7308 | add_error (std::move (error)); | |
7309 | ||
7310 | break; | |
7311 | } | |
7312 | params.push_back (std::move (param)); | |
7313 | ||
7314 | if (lexer.peek_token ()->get_id () != COMMA) | |
7315 | { | |
7316 | lexer.skip_token (); | |
7317 | // not an error but means param list is done | |
7318 | break; | |
7319 | } | |
7320 | // skip comma | |
7321 | lexer.skip_token (); | |
7322 | ||
7323 | t = lexer.peek_token (); | |
7324 | } | |
7325 | params.shrink_to_fit (); | |
7326 | break; | |
7327 | default: | |
7328 | add_error (Error (t->get_locus (), | |
7329 | "unexpected token %qs in closure expression - expected " | |
7330 | "%<|%> or %<||%>", | |
7331 | t->get_token_description ())); | |
7332 | ||
7333 | // skip somewhere? | |
7334 | return nullptr; | |
7335 | } | |
7336 | ||
7337 | // again branch based on next token | |
7338 | t = lexer.peek_token (); | |
7339 | if (t->get_id () == RETURN_TYPE) | |
7340 | { | |
7341 | // must be return type closure with block expr | |
7342 | ||
7343 | // skip "return type" token | |
7344 | lexer.skip_token (); | |
7345 | ||
7346 | // parse actual type, which is required | |
7347 | std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds (); | |
7348 | if (type == nullptr) | |
7349 | { | |
7350 | // error | |
7351 | Error error (t->get_locus (), "failed to parse type for closure"); | |
7352 | add_error (std::move (error)); | |
7353 | ||
7354 | // skip somewhere? | |
7355 | return nullptr; | |
7356 | } | |
7357 | ||
7358 | // parse block expr, which is required | |
7359 | std::unique_ptr<AST::BlockExpr> block = parse_block_expr (); | |
7360 | if (block == nullptr) | |
7361 | { | |
7362 | // error | |
7363 | Error error (lexer.peek_token ()->get_locus (), | |
7364 | "failed to parse block expr in closure"); | |
7365 | add_error (std::move (error)); | |
7366 | ||
7367 | // skip somewhere? | |
7368 | return nullptr; | |
7369 | } | |
7370 | ||
7371 | return std::unique_ptr<AST::ClosureExprInnerTyped> ( | |
7372 | new AST::ClosureExprInnerTyped (std::move (type), std::move (block), | |
7373 | std::move (params), locus, has_move, | |
7374 | std::move (outer_attrs))); | |
7375 | } | |
7376 | else | |
7377 | { | |
7378 | // must be expr-only closure | |
7379 | ||
7380 | // parse expr, which is required | |
7381 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
7382 | if (expr == nullptr) | |
7383 | { | |
7384 | Error error (t->get_locus (), | |
7385 | "failed to parse expression in closure"); | |
7386 | add_error (std::move (error)); | |
7387 | ||
7388 | // skip somewhere? | |
7389 | return nullptr; | |
7390 | } | |
7391 | ||
7392 | return std::unique_ptr<AST::ClosureExprInner> ( | |
7393 | new AST::ClosureExprInner (std::move (expr), std::move (params), locus, | |
7394 | has_move, std::move (outer_attrs))); | |
7395 | } | |
7396 | } | |
7397 | ||
7398 | // Parses a literal token (to literal expression). | |
7399 | template <typename ManagedTokenSource> | |
7400 | std::unique_ptr<AST::LiteralExpr> | |
7401 | Parser<ManagedTokenSource>::parse_literal_expr (AST::AttrVec outer_attrs) | |
7402 | { | |
7403 | // TODO: change if literal representation in lexer changes | |
7404 | ||
7405 | std::string literal_value; | |
7406 | AST::Literal::LitType type = AST::Literal::STRING; | |
7407 | ||
7408 | // branch based on token | |
7409 | const_TokenPtr t = lexer.peek_token (); | |
7410 | switch (t->get_id ()) | |
7411 | { | |
7412 | case CHAR_LITERAL: | |
7413 | type = AST::Literal::CHAR; | |
7414 | literal_value = t->get_str (); | |
7415 | lexer.skip_token (); | |
7416 | break; | |
7417 | case STRING_LITERAL: | |
7418 | type = AST::Literal::STRING; | |
7419 | literal_value = t->get_str (); | |
7420 | lexer.skip_token (); | |
7421 | break; | |
7422 | case BYTE_CHAR_LITERAL: | |
7423 | type = AST::Literal::BYTE; | |
7424 | literal_value = t->get_str (); | |
7425 | lexer.skip_token (); | |
7426 | break; | |
7427 | case BYTE_STRING_LITERAL: | |
7428 | type = AST::Literal::BYTE_STRING; | |
7429 | literal_value = t->get_str (); | |
7430 | lexer.skip_token (); | |
7431 | break; | |
7432 | case RAW_STRING_LITERAL: | |
7433 | type = AST::Literal::RAW_STRING; | |
7434 | literal_value = t->get_str (); | |
7435 | lexer.skip_token (); | |
7436 | break; | |
7437 | case INT_LITERAL: | |
7438 | type = AST::Literal::INT; | |
7439 | literal_value = t->get_str (); | |
7440 | lexer.skip_token (); | |
7441 | break; | |
7442 | case FLOAT_LITERAL: | |
7443 | type = AST::Literal::FLOAT; | |
7444 | literal_value = t->get_str (); | |
7445 | lexer.skip_token (); | |
7446 | break; | |
7447 | // case BOOL_LITERAL | |
7448 | // use true and false keywords rather than "bool literal" Rust terminology | |
7449 | case TRUE_LITERAL: | |
7450 | type = AST::Literal::BOOL; | |
7451 | literal_value = Values::Keywords::TRUE_LITERAL; | |
7452 | lexer.skip_token (); | |
7453 | break; | |
7454 | case FALSE_LITERAL: | |
7455 | type = AST::Literal::BOOL; | |
7456 | literal_value = Values::Keywords::FALSE_LITERAL; | |
7457 | lexer.skip_token (); | |
7458 | break; | |
7459 | default: | |
7460 | // error - cannot be a literal expr | |
7461 | add_error (Error (t->get_locus (), | |
7462 | "unexpected token %qs when parsing literal expression", | |
7463 | t->get_token_description ())); | |
7464 | ||
7465 | // skip? | |
7466 | return nullptr; | |
7467 | } | |
7468 | ||
7469 | // create literal based on stuff in switch | |
7470 | return std::unique_ptr<AST::LiteralExpr> ( | |
7471 | new AST::LiteralExpr (std::move (literal_value), std::move (type), | |
7472 | t->get_type_hint (), std::move (outer_attrs), | |
7473 | t->get_locus ())); | |
7474 | } | |
7475 | ||
7476 | template <typename ManagedTokenSource> | |
7477 | std::unique_ptr<AST::BoxExpr> | |
7478 | Parser<ManagedTokenSource>::parse_box_expr (AST::AttrVec outer_attrs, | |
7479 | location_t pratt_parsed_loc) | |
7480 | { | |
7481 | location_t locus = pratt_parsed_loc; | |
7482 | if (locus == UNKNOWN_LOCATION) | |
7483 | { | |
7484 | locus = lexer.peek_token ()->get_locus (); | |
7485 | skip_token (BOX); | |
7486 | } | |
7487 | ||
7488 | ParseRestrictions restrictions; | |
7489 | restrictions.expr_can_be_null = false; | |
7490 | ||
7491 | std::unique_ptr<AST::Expr> expr = parse_expr (AST::AttrVec (), restrictions); | |
7492 | ||
7493 | return std::unique_ptr<AST::BoxExpr> ( | |
7494 | new AST::BoxExpr (std::move (expr), std::move (outer_attrs), locus)); | |
7495 | } | |
7496 | ||
7497 | // Parses a return expression (including any expression to return). | |
7498 | template <typename ManagedTokenSource> | |
7499 | std::unique_ptr<AST::ReturnExpr> | |
7500 | Parser<ManagedTokenSource>::parse_return_expr (AST::AttrVec outer_attrs, | |
7501 | location_t pratt_parsed_loc) | |
7502 | { | |
7503 | location_t locus = pratt_parsed_loc; | |
7504 | if (locus == UNKNOWN_LOCATION) | |
7505 | { | |
7506 | locus = lexer.peek_token ()->get_locus (); | |
7507 | skip_token (RETURN_KW); | |
7508 | } | |
7509 | ||
7510 | // parse expression to return, if it exists | |
7511 | ParseRestrictions restrictions; | |
7512 | restrictions.expr_can_be_null = true; | |
7513 | std::unique_ptr<AST::Expr> returned_expr | |
7514 | = parse_expr (AST::AttrVec (), restrictions); | |
7515 | ||
7516 | return std::unique_ptr<AST::ReturnExpr> ( | |
7517 | new AST::ReturnExpr (std::move (returned_expr), std::move (outer_attrs), | |
7518 | locus)); | |
7519 | } | |
7520 | ||
7521 | /* Parses a break expression (including any label to break to AND any return | |
7522 | * expression). */ | |
7523 | template <typename ManagedTokenSource> | |
7524 | std::unique_ptr<AST::BreakExpr> | |
7525 | Parser<ManagedTokenSource>::parse_break_expr (AST::AttrVec outer_attrs, | |
7526 | location_t pratt_parsed_loc) | |
7527 | { | |
7528 | location_t locus = pratt_parsed_loc; | |
7529 | if (locus == UNKNOWN_LOCATION) | |
7530 | { | |
7531 | locus = lexer.peek_token ()->get_locus (); | |
7532 | skip_token (BREAK); | |
7533 | } | |
7534 | ||
7535 | auto parsed_label = parse_lifetime (false); | |
7536 | auto label = (parsed_label) | |
7537 | ? tl::optional<AST::Lifetime> (parsed_label.value ()) | |
7538 | : tl::nullopt; | |
7539 | ||
7540 | // parse break return expression if it exists | |
7541 | ParseRestrictions restrictions; | |
7542 | restrictions.expr_can_be_null = true; | |
7543 | std::unique_ptr<AST::Expr> return_expr | |
7544 | = parse_expr (AST::AttrVec (), restrictions); | |
7545 | ||
7546 | return std::unique_ptr<AST::BreakExpr> ( | |
7547 | new AST::BreakExpr (std::move (label), std::move (return_expr), | |
7548 | std::move (outer_attrs), locus)); | |
7549 | } | |
7550 | ||
7551 | // Parses a continue expression (including any label to continue from). | |
7552 | template <typename ManagedTokenSource> | |
7553 | std::unique_ptr<AST::ContinueExpr> | |
7554 | Parser<ManagedTokenSource>::parse_continue_expr (AST::AttrVec outer_attrs, | |
7555 | location_t pratt_parsed_loc) | |
7556 | { | |
7557 | location_t locus = pratt_parsed_loc; | |
7558 | if (locus == UNKNOWN_LOCATION) | |
7559 | { | |
7560 | locus = lexer.peek_token ()->get_locus (); | |
7561 | skip_token (CONTINUE); | |
7562 | } | |
7563 | ||
7564 | auto parsed_label = parse_lifetime (false); | |
7565 | auto label = (parsed_label) | |
7566 | ? tl::optional<AST::Lifetime> (parsed_label.value ()) | |
7567 | : tl::nullopt; | |
7568 | ||
7569 | return std::unique_ptr<AST::ContinueExpr> ( | |
7570 | new AST::ContinueExpr (std::move (label), std::move (outer_attrs), locus)); | |
7571 | } | |
7572 | ||
7573 | // Parses a loop label used in loop expressions. | |
7574 | template <typename ManagedTokenSource> | |
7575 | tl::expected<AST::LoopLabel, ParseLoopLabelError> | |
7576 | Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok) | |
7577 | { | |
7578 | // parse lifetime - if doesn't exist, assume no label | |
7579 | if (tok->get_id () != LIFETIME) | |
7580 | { | |
7581 | // not necessarily an error | |
7582 | return tl::unexpected<ParseLoopLabelError> ( | |
7583 | ParseLoopLabelError::NOT_LOOP_LABEL); | |
7584 | } | |
7585 | /* FIXME: check for named lifetime requirement here? or check in semantic | |
7586 | * analysis phase? */ | |
7587 | AST::Lifetime label = lifetime_from_token (tok); | |
7588 | ||
7589 | if (!skip_token (COLON)) | |
7590 | { | |
7591 | // skip somewhere? | |
7592 | return tl::unexpected<ParseLoopLabelError> ( | |
7593 | ParseLoopLabelError::MISSING_COLON); | |
7594 | } | |
7595 | ||
7596 | return tl::expected<AST::LoopLabel, ParseLoopLabelError> ( | |
7597 | AST::LoopLabel (std::move (label), tok->get_locus ())); | |
7598 | } | |
7599 | ||
7600 | /* Parses an if expression of any kind, including with else, else if, else if | |
7601 | * let, and neither. Note that any outer attributes will be ignored because if | |
7602 | * expressions don't support them. */ | |
7603 | template <typename ManagedTokenSource> | |
7604 | std::unique_ptr<AST::IfExpr> | |
7605 | Parser<ManagedTokenSource>::parse_if_expr (AST::AttrVec outer_attrs, | |
7606 | location_t pratt_parsed_loc) | |
7607 | { | |
7608 | // TODO: make having outer attributes an error? | |
7609 | location_t locus = pratt_parsed_loc; | |
7610 | if (locus == UNKNOWN_LOCATION) | |
7611 | { | |
7612 | locus = lexer.peek_token ()->get_locus (); | |
7613 | if (!skip_token (IF)) | |
7614 | { | |
7615 | skip_after_end_block (); | |
7616 | return nullptr; | |
7617 | } | |
7618 | } | |
7619 | ||
7620 | // detect accidental if let | |
7621 | if (lexer.peek_token ()->get_id () == LET) | |
7622 | { | |
7623 | Error error (lexer.peek_token ()->get_locus (), | |
7624 | "if let expression probably exists, but is being parsed " | |
7625 | "as an if expression. This may be a parser error"); | |
7626 | add_error (std::move (error)); | |
7627 | ||
7628 | // skip somewhere? | |
7629 | return nullptr; | |
7630 | } | |
7631 | ||
7632 | /* parse required condition expr - HACK to prevent struct expr from being | |
7633 | * parsed */ | |
7634 | ParseRestrictions no_struct_expr; | |
7635 | no_struct_expr.can_be_struct_expr = false; | |
7636 | std::unique_ptr<AST::Expr> condition = parse_expr ({}, no_struct_expr); | |
7637 | if (condition == nullptr) | |
7638 | { | |
7639 | Error error (lexer.peek_token ()->get_locus (), | |
7640 | "failed to parse condition expression in if expression"); | |
7641 | add_error (std::move (error)); | |
7642 | ||
7643 | // skip somewhere? | |
7644 | return nullptr; | |
7645 | } | |
7646 | ||
7647 | // parse required block expr | |
7648 | std::unique_ptr<AST::BlockExpr> if_body = parse_block_expr (); | |
7649 | if (if_body == nullptr) | |
7650 | { | |
7651 | Error error (lexer.peek_token ()->get_locus (), | |
7652 | "failed to parse if body block expression in if expression"); | |
7653 | add_error (std::move (error)); | |
7654 | ||
7655 | // skip somewhere? | |
7656 | return nullptr; | |
7657 | } | |
7658 | ||
7659 | // branch to parse end or else (and then else, else if, or else if let) | |
7660 | if (lexer.peek_token ()->get_id () != ELSE) | |
7661 | { | |
7662 | // single selection - end of if expression | |
7663 | return std::unique_ptr<AST::IfExpr> ( | |
7664 | new AST::IfExpr (std::move (condition), std::move (if_body), | |
7665 | std::move (outer_attrs), locus)); | |
7666 | } | |
7667 | else | |
7668 | { | |
7669 | // double or multiple selection - branch on end, else if, or else if let | |
7670 | ||
7671 | // skip "else" | |
7672 | lexer.skip_token (); | |
7673 | ||
7674 | // branch on whether next token is '{' or 'if' | |
7675 | const_TokenPtr t = lexer.peek_token (); | |
7676 | switch (t->get_id ()) | |
7677 | { | |
7678 | case LEFT_CURLY: { | |
7679 | // double selection - else | |
7680 | // parse else block expr (required) | |
7681 | std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr (); | |
7682 | if (else_body == nullptr) | |
7683 | { | |
7684 | Error error (lexer.peek_token ()->get_locus (), | |
7685 | "failed to parse else body block expression in " | |
7686 | "if expression"); | |
7687 | add_error (std::move (error)); | |
7688 | ||
7689 | // skip somewhere? | |
7690 | return nullptr; | |
7691 | } | |
7692 | ||
7693 | return std::unique_ptr<AST::IfExprConseqElse> ( | |
7694 | new AST::IfExprConseqElse (std::move (condition), | |
7695 | std::move (if_body), | |
7696 | std::move (else_body), | |
7697 | std::move (outer_attrs), locus)); | |
7698 | } | |
7699 | case IF: { | |
7700 | // multiple selection - else if or else if let | |
7701 | // branch on whether next token is 'let' or not | |
7702 | if (lexer.peek_token (1)->get_id () == LET) | |
7703 | { | |
7704 | // parse if let expr (required) | |
7705 | std::unique_ptr<AST::IfLetExpr> if_let_expr | |
7706 | = parse_if_let_expr (); | |
7707 | if (if_let_expr == nullptr) | |
7708 | { | |
7709 | Error error (lexer.peek_token ()->get_locus (), | |
7710 | "failed to parse (else) if let expression " | |
7711 | "after if expression"); | |
7712 | add_error (std::move (error)); | |
7713 | ||
7714 | // skip somewhere? | |
7715 | return nullptr; | |
7716 | } | |
7717 | ||
7718 | return std::unique_ptr<AST::IfExprConseqElse> ( | |
7719 | new AST::IfExprConseqElse (std::move (condition), | |
7720 | std::move (if_body), | |
7721 | std::move (if_let_expr), | |
7722 | std::move (outer_attrs), locus)); | |
7723 | } | |
7724 | else | |
7725 | { | |
7726 | // parse if expr (required) | |
7727 | std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr (); | |
7728 | if (if_expr == nullptr) | |
7729 | { | |
7730 | Error error (lexer.peek_token ()->get_locus (), | |
7731 | "failed to parse (else) if expression after " | |
7732 | "if expression"); | |
7733 | add_error (std::move (error)); | |
7734 | ||
7735 | // skip somewhere? | |
7736 | return nullptr; | |
7737 | } | |
7738 | ||
7739 | return std::unique_ptr<AST::IfExprConseqElse> ( | |
7740 | new AST::IfExprConseqElse (std::move (condition), | |
7741 | std::move (if_body), | |
7742 | std::move (if_expr), | |
7743 | std::move (outer_attrs), locus)); | |
7744 | } | |
7745 | } | |
7746 | default: | |
7747 | // error - invalid token | |
7748 | add_error (Error (t->get_locus (), | |
7749 | "unexpected token %qs after else in if expression", | |
7750 | t->get_token_description ())); | |
7751 | ||
7752 | // skip somewhere? | |
7753 | return nullptr; | |
7754 | } | |
7755 | } | |
7756 | } | |
7757 | ||
7758 | /* Parses an if let expression of any kind, including with else, else if, else | |
7759 | * if let, and none. Note that any outer attributes will be ignored as if let | |
7760 | * expressions don't support them. */ | |
7761 | template <typename ManagedTokenSource> | |
7762 | std::unique_ptr<AST::IfLetExpr> | |
7763 | Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs, | |
7764 | location_t pratt_parsed_loc) | |
7765 | { | |
7766 | // TODO: make having outer attributes an error? | |
7767 | location_t locus = pratt_parsed_loc; | |
7768 | if (locus == UNKNOWN_LOCATION) | |
7769 | { | |
7770 | locus = lexer.peek_token ()->get_locus (); | |
7771 | if (!skip_token (IF)) | |
7772 | { | |
7773 | skip_after_end_block (); | |
7774 | return nullptr; | |
7775 | } | |
7776 | } | |
7777 | ||
7778 | // detect accidental if expr parsed as if let expr | |
7779 | if (lexer.peek_token ()->get_id () != LET) | |
7780 | { | |
7781 | Error error (lexer.peek_token ()->get_locus (), | |
7782 | "if expression probably exists, but is being parsed as an " | |
7783 | "if let expression. This may be a parser error"); | |
7784 | add_error (std::move (error)); | |
7785 | ||
7786 | // skip somewhere? | |
7787 | return nullptr; | |
7788 | } | |
7789 | lexer.skip_token (); | |
7790 | ||
7791 | // parse match arm patterns (which are required) | |
7792 | std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns | |
7793 | = parse_match_arm_patterns (EQUAL); | |
7794 | if (match_arm_patterns.empty ()) | |
7795 | { | |
7796 | Error error ( | |
7797 | lexer.peek_token ()->get_locus (), | |
7798 | "failed to parse any match arm patterns in if let expression"); | |
7799 | add_error (std::move (error)); | |
7800 | ||
7801 | // skip somewhere? | |
7802 | return nullptr; | |
7803 | } | |
7804 | ||
7805 | if (!skip_token (EQUAL)) | |
7806 | { | |
7807 | // skip somewhere? | |
7808 | return nullptr; | |
7809 | } | |
7810 | ||
7811 | // parse expression (required) - HACK to prevent struct expr being parsed | |
7812 | ParseRestrictions no_struct_expr; | |
7813 | no_struct_expr.can_be_struct_expr = false; | |
7814 | std::unique_ptr<AST::Expr> scrutinee_expr = parse_expr ({}, no_struct_expr); | |
7815 | if (scrutinee_expr == nullptr) | |
7816 | { | |
7817 | Error error (lexer.peek_token ()->get_locus (), | |
7818 | "failed to parse scrutinee expression in if let expression"); | |
7819 | add_error (std::move (error)); | |
7820 | ||
7821 | // skip somewhere? | |
7822 | return nullptr; | |
7823 | } | |
7824 | /* TODO: check for expression not being a struct expression or lazy boolean | |
7825 | * expression here? or actually probably in semantic analysis. */ | |
7826 | ||
7827 | // parse block expression (required) | |
7828 | std::unique_ptr<AST::BlockExpr> if_let_body = parse_block_expr (); | |
7829 | if (if_let_body == nullptr) | |
7830 | { | |
7831 | Error error ( | |
7832 | lexer.peek_token ()->get_locus (), | |
7833 | "failed to parse if let body block expression in if let expression"); | |
7834 | add_error (std::move (error)); | |
7835 | ||
7836 | // skip somewhere? | |
7837 | return nullptr; | |
7838 | } | |
7839 | ||
7840 | // branch to parse end or else (and then else, else if, or else if let) | |
7841 | if (lexer.peek_token ()->get_id () != ELSE) | |
7842 | { | |
7843 | // single selection - end of if let expression | |
7844 | return std::unique_ptr<AST::IfLetExpr> ( | |
7845 | new AST::IfLetExpr (std::move (match_arm_patterns), | |
7846 | std::move (scrutinee_expr), std::move (if_let_body), | |
7847 | std::move (outer_attrs), locus)); | |
7848 | } | |
7849 | else | |
7850 | { | |
7851 | // double or multiple selection - branch on end, else if, or else if let | |
7852 | ||
7853 | // skip "else" | |
7854 | lexer.skip_token (); | |
7855 | ||
7856 | // branch on whether next token is '{' or 'if' | |
7857 | const_TokenPtr t = lexer.peek_token (); | |
7858 | switch (t->get_id ()) | |
7859 | { | |
7860 | case LEFT_CURLY: { | |
7861 | // double selection - else | |
7862 | // parse else block expr (required) | |
7863 | std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr (); | |
7864 | if (else_body == nullptr) | |
7865 | { | |
7866 | Error error (lexer.peek_token ()->get_locus (), | |
7867 | "failed to parse else body block expression in " | |
7868 | "if let expression"); | |
7869 | add_error (std::move (error)); | |
7870 | ||
7871 | // skip somewhere? | |
7872 | return nullptr; | |
7873 | } | |
7874 | ||
7875 | return std::unique_ptr<AST::IfLetExprConseqElse> ( | |
7876 | new AST::IfLetExprConseqElse (std::move (match_arm_patterns), | |
7877 | std::move (scrutinee_expr), | |
7878 | std::move (if_let_body), | |
7879 | std::move (else_body), | |
7880 | std::move (outer_attrs), locus)); | |
7881 | } | |
7882 | case IF: { | |
7883 | // multiple selection - else if or else if let | |
7884 | // branch on whether next token is 'let' or not | |
7885 | if (lexer.peek_token (1)->get_id () == LET) | |
7886 | { | |
7887 | // parse if let expr (required) | |
7888 | std::unique_ptr<AST::IfLetExpr> if_let_expr | |
7889 | = parse_if_let_expr (); | |
7890 | if (if_let_expr == nullptr) | |
7891 | { | |
7892 | Error error (lexer.peek_token ()->get_locus (), | |
7893 | "failed to parse (else) if let expression " | |
7894 | "after if let expression"); | |
7895 | add_error (std::move (error)); | |
7896 | ||
7897 | // skip somewhere? | |
7898 | return nullptr; | |
7899 | } | |
7900 | ||
7901 | return std::unique_ptr<AST::IfLetExprConseqElse> ( | |
7902 | new AST::IfLetExprConseqElse ( | |
7903 | std::move (match_arm_patterns), std::move (scrutinee_expr), | |
7904 | std::move (if_let_body), std::move (if_let_expr), | |
7905 | std::move (outer_attrs), locus)); | |
7906 | } | |
7907 | else | |
7908 | { | |
7909 | // parse if expr (required) | |
7910 | std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr (); | |
7911 | if (if_expr == nullptr) | |
7912 | { | |
7913 | Error error (lexer.peek_token ()->get_locus (), | |
7914 | "failed to parse (else) if expression after " | |
7915 | "if let expression"); | |
7916 | add_error (std::move (error)); | |
7917 | ||
7918 | // skip somewhere? | |
7919 | return nullptr; | |
7920 | } | |
7921 | ||
7922 | return std::unique_ptr<AST::IfLetExprConseqElse> ( | |
7923 | new AST::IfLetExprConseqElse ( | |
7924 | std::move (match_arm_patterns), std::move (scrutinee_expr), | |
7925 | std::move (if_let_body), std::move (if_expr), | |
7926 | std::move (outer_attrs), locus)); | |
7927 | } | |
7928 | } | |
7929 | default: | |
7930 | // error - invalid token | |
7931 | add_error ( | |
7932 | Error (t->get_locus (), | |
7933 | "unexpected token %qs after else in if let expression", | |
7934 | t->get_token_description ())); | |
7935 | ||
7936 | // skip somewhere? | |
7937 | return nullptr; | |
7938 | } | |
7939 | } | |
7940 | } | |
7941 | ||
7942 | /* TODO: possibly decide on different method of handling label (i.e. not | |
7943 | * parameter) */ | |
7944 | ||
7945 | /* Parses a "loop" infinite loop expression. Label is not parsed and should be | |
7946 | * parsed via parse_labelled_loop_expr, which would call this. */ | |
7947 | template <typename ManagedTokenSource> | |
7948 | std::unique_ptr<AST::LoopExpr> | |
7949 | Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs, | |
7950 | tl::optional<AST::LoopLabel> label, | |
7951 | location_t pratt_parsed_loc) | |
7952 | { | |
7953 | location_t locus = pratt_parsed_loc; | |
7954 | if (locus == UNKNOWN_LOCATION) | |
7955 | { | |
7956 | if (label) | |
7957 | locus = label->get_locus (); | |
7958 | else | |
7959 | locus = lexer.peek_token ()->get_locus (); | |
7960 | ||
7961 | if (!skip_token (LOOP)) | |
7962 | { | |
7963 | skip_after_end_block (); | |
7964 | return nullptr; | |
7965 | } | |
7966 | } | |
7967 | else | |
7968 | { | |
7969 | if (label) | |
7970 | locus = label->get_locus (); | |
7971 | } | |
7972 | ||
7973 | // parse loop body, which is required | |
7974 | std::unique_ptr<AST::BlockExpr> loop_body = parse_block_expr (); | |
7975 | if (loop_body == nullptr) | |
7976 | { | |
7977 | Error error (lexer.peek_token ()->get_locus (), | |
7978 | "could not parse loop body in (infinite) loop expression"); | |
7979 | add_error (std::move (error)); | |
7980 | ||
7981 | return nullptr; | |
7982 | } | |
7983 | ||
7984 | return std::unique_ptr<AST::LoopExpr> ( | |
7985 | new AST::LoopExpr (std::move (loop_body), locus, std::move (label), | |
7986 | std::move (outer_attrs))); | |
7987 | } | |
7988 | ||
7989 | /* Parses a "while" loop expression. Label is not parsed and should be parsed | |
7990 | * via parse_labelled_loop_expr, which would call this. */ | |
7991 | template <typename ManagedTokenSource> | |
7992 | std::unique_ptr<AST::WhileLoopExpr> | |
7993 | Parser<ManagedTokenSource>::parse_while_loop_expr ( | |
7994 | AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label, | |
7995 | location_t pratt_parsed_loc) | |
7996 | { | |
7997 | location_t locus = pratt_parsed_loc; | |
7998 | if (locus == UNKNOWN_LOCATION) | |
7999 | { | |
8000 | if (label) | |
8001 | locus = label->get_locus (); | |
8002 | else | |
8003 | locus = lexer.peek_token ()->get_locus (); | |
8004 | ||
8005 | if (!skip_token (WHILE)) | |
8006 | { | |
8007 | skip_after_end_block (); | |
8008 | return nullptr; | |
8009 | } | |
8010 | } | |
8011 | else | |
8012 | { | |
8013 | if (label) | |
8014 | locus = label->get_locus (); | |
8015 | } | |
8016 | ||
8017 | // ensure it isn't a while let loop | |
8018 | if (lexer.peek_token ()->get_id () == LET) | |
8019 | { | |
8020 | Error error (lexer.peek_token ()->get_locus (), | |
8021 | "appears to be while let loop but is being parsed by " | |
8022 | "while loop - this may be a compiler issue"); | |
8023 | add_error (std::move (error)); | |
8024 | ||
8025 | // skip somewhere? | |
8026 | return nullptr; | |
8027 | } | |
8028 | ||
8029 | // parse loop predicate (required) with HACK to prevent struct expr parsing | |
8030 | ParseRestrictions no_struct_expr; | |
8031 | no_struct_expr.can_be_struct_expr = false; | |
8032 | std::unique_ptr<AST::Expr> predicate = parse_expr ({}, no_struct_expr); | |
8033 | if (predicate == nullptr) | |
8034 | { | |
8035 | Error error (lexer.peek_token ()->get_locus (), | |
8036 | "failed to parse predicate expression in while loop"); | |
8037 | add_error (std::move (error)); | |
8038 | ||
8039 | // skip somewhere? | |
8040 | return nullptr; | |
8041 | } | |
8042 | /* TODO: check that it isn't struct expression here? actually, probably in | |
8043 | * semantic analysis */ | |
8044 | ||
8045 | // parse loop body (required) | |
8046 | std::unique_ptr<AST::BlockExpr> body = parse_block_expr (); | |
8047 | if (body == nullptr) | |
8048 | { | |
8049 | Error error (lexer.peek_token ()->get_locus (), | |
8050 | "failed to parse loop body block expression in while loop"); | |
8051 | add_error (std::move (error)); | |
8052 | ||
8053 | // skip somewhere | |
8054 | return nullptr; | |
8055 | } | |
8056 | ||
8057 | return std::unique_ptr<AST::WhileLoopExpr> ( | |
8058 | new AST::WhileLoopExpr (std::move (predicate), std::move (body), locus, | |
8059 | std::move (label), std::move (outer_attrs))); | |
8060 | } | |
8061 | ||
8062 | /* Parses a "while let" loop expression. Label is not parsed and should be | |
8063 | * parsed via parse_labelled_loop_expr, which would call this. */ | |
8064 | template <typename ManagedTokenSource> | |
8065 | std::unique_ptr<AST::WhileLetLoopExpr> | |
8066 | Parser<ManagedTokenSource>::parse_while_let_loop_expr ( | |
8067 | AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label) | |
8068 | { | |
8069 | location_t locus = UNKNOWN_LOCATION; | |
8070 | if (label) | |
8071 | locus = label->get_locus (); | |
8072 | else | |
8073 | locus = lexer.peek_token ()->get_locus (); | |
8074 | maybe_skip_token (WHILE); | |
8075 | ||
8076 | /* check for possible accidental recognition of a while loop as a while let | |
8077 | * loop */ | |
8078 | if (lexer.peek_token ()->get_id () != LET) | |
8079 | { | |
8080 | Error error (lexer.peek_token ()->get_locus (), | |
8081 | "appears to be a while loop but is being parsed by " | |
8082 | "while let loop - this may be a compiler issue"); | |
8083 | add_error (std::move (error)); | |
8084 | ||
8085 | // skip somewhere | |
8086 | return nullptr; | |
8087 | } | |
8088 | // as this token is definitely let now, save the computation of comparison | |
8089 | lexer.skip_token (); | |
8090 | ||
8091 | // parse predicate patterns | |
8092 | std::vector<std::unique_ptr<AST::Pattern>> predicate_patterns | |
8093 | = parse_match_arm_patterns (EQUAL); | |
8094 | // TODO: have to ensure that there is at least 1 pattern? | |
8095 | ||
8096 | if (!skip_token (EQUAL)) | |
8097 | { | |
8098 | // skip somewhere? | |
8099 | return nullptr; | |
8100 | } | |
8101 | ||
8102 | /* parse predicate expression, which is required (and HACK to prevent struct | |
8103 | * expr) */ | |
8104 | ParseRestrictions no_struct_expr; | |
8105 | no_struct_expr.can_be_struct_expr = false; | |
8106 | std::unique_ptr<AST::Expr> predicate_expr = parse_expr ({}, no_struct_expr); | |
8107 | if (predicate_expr == nullptr) | |
8108 | { | |
8109 | Error error (lexer.peek_token ()->get_locus (), | |
8110 | "failed to parse predicate expression in while let loop"); | |
8111 | add_error (std::move (error)); | |
8112 | ||
8113 | // skip somewhere? | |
8114 | return nullptr; | |
8115 | } | |
8116 | /* TODO: ensure that struct expression is not parsed? Actually, probably in | |
8117 | * semantic analysis. */ | |
8118 | ||
8119 | // parse loop body, which is required | |
8120 | std::unique_ptr<AST::BlockExpr> body = parse_block_expr (); | |
8121 | if (body == nullptr) | |
8122 | { | |
8123 | Error error (lexer.peek_token ()->get_locus (), | |
8124 | "failed to parse block expr (loop body) of while let loop"); | |
8125 | add_error (std::move (error)); | |
8126 | ||
8127 | // skip somewhere? | |
8128 | return nullptr; | |
8129 | } | |
8130 | ||
8131 | return std::unique_ptr<AST::WhileLetLoopExpr> (new AST::WhileLetLoopExpr ( | |
8132 | std::move (predicate_patterns), std::move (predicate_expr), | |
8133 | std::move (body), locus, std::move (label), std::move (outer_attrs))); | |
8134 | } | |
8135 | ||
8136 | /* Parses a "for" iterative loop. Label is not parsed and should be parsed via | |
8137 | * parse_labelled_loop_expr, which would call this. */ | |
8138 | template <typename ManagedTokenSource> | |
8139 | std::unique_ptr<AST::ForLoopExpr> | |
8140 | Parser<ManagedTokenSource>::parse_for_loop_expr ( | |
8141 | AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label) | |
8142 | { | |
8143 | location_t locus = UNKNOWN_LOCATION; | |
8144 | if (label) | |
8145 | locus = label->get_locus (); | |
8146 | else | |
8147 | locus = lexer.peek_token ()->get_locus (); | |
8148 | maybe_skip_token (FOR); | |
8149 | ||
8150 | // parse pattern, which is required | |
8151 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
8152 | if (pattern == nullptr) | |
8153 | { | |
8154 | Error error (lexer.peek_token ()->get_locus (), | |
8155 | "failed to parse iterator pattern in for loop"); | |
8156 | add_error (std::move (error)); | |
8157 | ||
8158 | // skip somewhere? | |
8159 | return nullptr; | |
8160 | } | |
8161 | ||
8162 | if (!skip_token (IN)) | |
8163 | { | |
8164 | // skip somewhere? | |
8165 | return nullptr; | |
8166 | } | |
8167 | ||
8168 | /* parse iterator expression, which is required - also HACK to prevent | |
8169 | * struct expr */ | |
8170 | ParseRestrictions no_struct_expr; | |
8171 | no_struct_expr.can_be_struct_expr = false; | |
8172 | std::unique_ptr<AST::Expr> expr = parse_expr ({}, no_struct_expr); | |
8173 | if (expr == nullptr) | |
8174 | { | |
8175 | Error error (lexer.peek_token ()->get_locus (), | |
8176 | "failed to parse iterator expression in for loop"); | |
8177 | add_error (std::move (error)); | |
8178 | ||
8179 | // skip somewhere? | |
8180 | return nullptr; | |
8181 | } | |
8182 | // TODO: check to ensure this isn't struct expr? Or in semantic analysis. | |
8183 | ||
8184 | // parse loop body, which is required | |
8185 | std::unique_ptr<AST::BlockExpr> body = parse_block_expr (); | |
8186 | if (body == nullptr) | |
8187 | { | |
8188 | Error error (lexer.peek_token ()->get_locus (), | |
8189 | "failed to parse loop body block expression in for loop"); | |
8190 | add_error (std::move (error)); | |
8191 | ||
8192 | // skip somewhere? | |
8193 | return nullptr; | |
8194 | } | |
8195 | ||
8196 | return std::unique_ptr<AST::ForLoopExpr> ( | |
8197 | new AST::ForLoopExpr (std::move (pattern), std::move (expr), | |
8198 | std::move (body), locus, std::move (label), | |
8199 | std::move (outer_attrs))); | |
8200 | } | |
8201 | ||
8202 | // Parses a loop expression with label (any kind of loop - disambiguates). | |
8203 | template <typename ManagedTokenSource> | |
8204 | std::unique_ptr<AST::Expr> | |
8205 | Parser<ManagedTokenSource>::parse_labelled_loop_expr (const_TokenPtr tok, | |
8206 | AST::AttrVec outer_attrs) | |
8207 | { | |
8208 | /* TODO: decide whether it should not work if there is no label, or parse it | |
8209 | * with no label at the moment, I will make it not work with no label | |
8210 | * because that's the implication. */ | |
8211 | ||
8212 | if (tok->get_id () != LIFETIME) | |
8213 | { | |
8214 | Error error (tok->get_locus (), | |
8215 | "expected lifetime in labelled loop expr (to parse loop " | |
8216 | "label) - found %qs", | |
8217 | tok->get_token_description ()); | |
8218 | add_error (std::move (error)); | |
8219 | ||
8220 | // skip? | |
8221 | return nullptr; | |
8222 | } | |
8223 | ||
8224 | // parse loop label (required) | |
8225 | // TODO: Convert this return type to tl::expected instead of tl::optional | |
8226 | auto parsed_label = parse_loop_label (tok); | |
8227 | if (!parsed_label) | |
8228 | { | |
8229 | Error error (lexer.peek_token ()->get_locus (), | |
8230 | "failed to parse loop label in labelled loop expr"); | |
8231 | add_error (std::move (error)); | |
8232 | ||
8233 | // skip? | |
8234 | return nullptr; | |
8235 | } | |
8236 | ||
8237 | auto label = parsed_label | |
8238 | ? tl::optional<AST::LoopLabel> (parsed_label.value ()) | |
8239 | : tl::nullopt; | |
8240 | ||
8241 | // branch on next token | |
8242 | const_TokenPtr t = lexer.peek_token (); | |
8243 | switch (t->get_id ()) | |
8244 | { | |
8245 | case LOOP: | |
8246 | return parse_loop_expr (std::move (outer_attrs), std::move (label)); | |
8247 | case FOR: | |
8248 | return parse_for_loop_expr (std::move (outer_attrs), std::move (label)); | |
8249 | case WHILE: | |
8250 | // further disambiguate into while vs while let | |
8251 | if (lexer.peek_token (1)->get_id () == LET) | |
8252 | { | |
8253 | return parse_while_let_loop_expr (std::move (outer_attrs), | |
8254 | std::move (label)); | |
8255 | } | |
8256 | else | |
8257 | { | |
8258 | return parse_while_loop_expr (std::move (outer_attrs), | |
8259 | std::move (label)); | |
8260 | } | |
8261 | case LEFT_CURLY: | |
8262 | return parse_block_expr (std::move (outer_attrs), std::move (label)); | |
8263 | default: | |
8264 | // error | |
8265 | add_error (Error (t->get_locus (), | |
8266 | "unexpected token %qs when parsing labelled loop", | |
8267 | t->get_token_description ())); | |
8268 | ||
8269 | // skip? | |
8270 | return nullptr; | |
8271 | } | |
8272 | } | |
8273 | ||
8274 | // Parses a match expression. | |
8275 | template <typename ManagedTokenSource> | |
8276 | std::unique_ptr<AST::MatchExpr> | |
8277 | Parser<ManagedTokenSource>::parse_match_expr (AST::AttrVec outer_attrs, | |
8278 | location_t pratt_parsed_loc) | |
8279 | { | |
8280 | location_t locus = pratt_parsed_loc; | |
8281 | if (locus == UNKNOWN_LOCATION) | |
8282 | { | |
8283 | locus = lexer.peek_token ()->get_locus (); | |
8284 | skip_token (MATCH_KW); | |
8285 | } | |
8286 | ||
8287 | /* parse scrutinee expression, which is required (and HACK to prevent struct | |
8288 | * expr) */ | |
8289 | ParseRestrictions no_struct_expr; | |
8290 | no_struct_expr.can_be_struct_expr = false; | |
8291 | std::unique_ptr<AST::Expr> scrutinee = parse_expr ({}, no_struct_expr); | |
8292 | if (scrutinee == nullptr) | |
8293 | { | |
8294 | Error error (lexer.peek_token ()->get_locus (), | |
8295 | "failed to parse scrutinee expression in match expression"); | |
8296 | add_error (std::move (error)); | |
8297 | ||
8298 | // skip somewhere? | |
8299 | return nullptr; | |
8300 | } | |
8301 | /* TODO: check for scrutinee expr not being struct expr? or do so in | |
8302 | * semantic analysis */ | |
8303 | ||
8304 | if (!skip_token (LEFT_CURLY)) | |
8305 | { | |
8306 | // skip somewhere? | |
8307 | return nullptr; | |
8308 | } | |
8309 | ||
8310 | // parse inner attributes (if they exist) | |
8311 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
8312 | ||
8313 | // parse match arms (if they exist) | |
8314 | // std::vector<std::unique_ptr<AST::MatchCase> > match_arms; | |
8315 | std::vector<AST::MatchCase> match_arms; | |
8316 | ||
8317 | // parse match cases | |
8318 | while (lexer.peek_token ()->get_id () != RIGHT_CURLY) | |
8319 | { | |
8320 | // parse match arm itself, which is required | |
8321 | AST::MatchArm arm = parse_match_arm (); | |
8322 | if (arm.is_error ()) | |
8323 | { | |
8324 | // TODO is this worth throwing everything away? | |
8325 | Error error (lexer.peek_token ()->get_locus (), | |
8326 | "failed to parse match arm in match arms"); | |
8327 | add_error (std::move (error)); | |
8328 | ||
8329 | return nullptr; | |
8330 | } | |
8331 | ||
8332 | if (!skip_token (MATCH_ARROW)) | |
8333 | { | |
8334 | // skip after somewhere? | |
8335 | // TODO is returning here a good idea? or is break better? | |
8336 | return nullptr; | |
8337 | } | |
8338 | ||
8339 | ParseRestrictions restrictions; | |
8340 | restrictions.expr_can_be_stmt = true; | |
8341 | ||
8342 | std::unique_ptr<AST::Expr> expr = parse_expr ({}, restrictions); | |
8343 | ||
8344 | if (expr == nullptr) | |
8345 | { | |
8346 | Error error (lexer.peek_token ()->get_locus (), | |
8347 | "failed to parse expr in match arm in match expr"); | |
8348 | add_error (std::move (error)); | |
8349 | ||
8350 | // skip somewhere? | |
8351 | return nullptr; | |
8352 | } | |
8353 | ||
8354 | bool is_expr_without_block = expr->is_expr_without_block (); | |
8355 | ||
8356 | match_arms.push_back (AST::MatchCase (std::move (arm), std::move (expr))); | |
8357 | ||
8358 | // handle comma presence | |
8359 | if (lexer.peek_token ()->get_id () != COMMA) | |
8360 | { | |
8361 | if (!is_expr_without_block) | |
8362 | { | |
8363 | // allowed even if not final case | |
8364 | continue; | |
8365 | } | |
8366 | else if (is_expr_without_block | |
8367 | && lexer.peek_token ()->get_id () != RIGHT_CURLY) | |
8368 | { | |
8369 | // not allowed if not final case | |
8370 | Error error (lexer.peek_token ()->get_locus (), | |
8371 | "exprwithoutblock requires comma after match case " | |
8372 | "expression in match arm (if not final case)"); | |
8373 | add_error (std::move (error)); | |
8374 | ||
8375 | return nullptr; | |
8376 | } | |
8377 | else | |
8378 | { | |
8379 | // otherwise, must be final case, so fine | |
8380 | break; | |
8381 | } | |
8382 | } | |
8383 | lexer.skip_token (); | |
8384 | } | |
8385 | ||
8386 | if (!skip_token (RIGHT_CURLY)) | |
8387 | { | |
8388 | // skip somewhere? | |
8389 | return nullptr; | |
8390 | } | |
8391 | ||
8392 | match_arms.shrink_to_fit (); | |
8393 | ||
8394 | return std::unique_ptr<AST::MatchExpr> ( | |
8395 | new AST::MatchExpr (std::move (scrutinee), std::move (match_arms), | |
8396 | std::move (inner_attrs), std::move (outer_attrs), | |
8397 | locus)); | |
8398 | } | |
8399 | ||
8400 | // Parses the "pattern" part of the match arm (the 'case x:' equivalent). | |
8401 | template <typename ManagedTokenSource> | |
8402 | AST::MatchArm | |
8403 | Parser<ManagedTokenSource>::parse_match_arm () | |
8404 | { | |
8405 | // parse optional outer attributes | |
8406 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
8407 | ||
8408 | // DEBUG | |
8409 | rust_debug ("about to start parsing match arm patterns"); | |
8410 | ||
8411 | // break early if find right curly | |
8412 | if (lexer.peek_token ()->get_id () == RIGHT_CURLY) | |
8413 | { | |
8414 | // not an error | |
8415 | return AST::MatchArm::create_error (); | |
8416 | } | |
8417 | ||
8418 | // parse match arm patterns - at least 1 is required | |
8419 | std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns | |
8420 | = parse_match_arm_patterns (RIGHT_CURLY); | |
8421 | if (match_arm_patterns.empty ()) | |
8422 | { | |
8423 | Error error (lexer.peek_token ()->get_locus (), | |
8424 | "failed to parse any patterns in match arm"); | |
8425 | add_error (std::move (error)); | |
8426 | ||
8427 | // skip somewhere? | |
8428 | return AST::MatchArm::create_error (); | |
8429 | } | |
8430 | ||
8431 | // DEBUG | |
8432 | rust_debug ("successfully parsed match arm patterns"); | |
8433 | ||
8434 | // parse match arm guard expr if it exists | |
8435 | std::unique_ptr<AST::Expr> guard_expr = nullptr; | |
8436 | if (lexer.peek_token ()->get_id () == IF) | |
8437 | { | |
8438 | lexer.skip_token (); | |
8439 | ||
8440 | guard_expr = parse_expr (); | |
8441 | if (guard_expr == nullptr) | |
8442 | { | |
8443 | Error error (lexer.peek_token ()->get_locus (), | |
8444 | "failed to parse guard expression in match arm"); | |
8445 | add_error (std::move (error)); | |
8446 | ||
8447 | // skip somewhere? | |
8448 | return AST::MatchArm::create_error (); | |
8449 | } | |
8450 | } | |
8451 | ||
8452 | // DEBUG | |
8453 | rust_debug ("successfully parsed match arm"); | |
8454 | ||
8455 | return AST::MatchArm (std::move (match_arm_patterns), | |
8456 | lexer.peek_token ()->get_locus (), | |
8457 | std::move (guard_expr), std::move (outer_attrs)); | |
8458 | } | |
8459 | ||
8460 | /* Parses the patterns used in a match arm. End token id is the id of the | |
8461 | * token that would exist after the patterns are done (e.g. '}' for match | |
8462 | * expr, '=' for if let and while let). */ | |
8463 | template <typename ManagedTokenSource> | |
8464 | std::vector<std::unique_ptr<AST::Pattern>> | |
8465 | Parser<ManagedTokenSource>::parse_match_arm_patterns (TokenId end_token_id) | |
8466 | { | |
8467 | // skip optional leading '|' | |
8468 | if (lexer.peek_token ()->get_id () == PIPE) | |
8469 | lexer.skip_token (); | |
8470 | /* TODO: do I even need to store the result of this? can't be used. | |
8471 | * If semantically different, I need a wrapped "match arm patterns" object | |
8472 | * for this. */ | |
8473 | ||
8474 | std::vector<std::unique_ptr<AST::Pattern>> patterns; | |
8475 | ||
8476 | // quick break out if end_token_id | |
8477 | if (lexer.peek_token ()->get_id () == end_token_id) | |
8478 | return patterns; | |
8479 | ||
8480 | // parse required pattern - if doesn't exist, return empty | |
8481 | std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern (); | |
8482 | if (initial_pattern == nullptr) | |
8483 | { | |
8484 | // FIXME: should this be an error? | |
8485 | return patterns; | |
8486 | } | |
8487 | patterns.push_back (std::move (initial_pattern)); | |
8488 | ||
8489 | // DEBUG | |
8490 | rust_debug ("successfully parsed initial match arm pattern"); | |
8491 | ||
8492 | // parse new patterns as long as next char is '|' | |
8493 | const_TokenPtr t = lexer.peek_token (); | |
8494 | while (t->get_id () == PIPE) | |
8495 | { | |
8496 | // skip pipe token | |
8497 | lexer.skip_token (); | |
8498 | ||
8499 | // break if hit end token id | |
8500 | if (lexer.peek_token ()->get_id () == end_token_id) | |
8501 | break; | |
8502 | ||
8503 | // parse pattern | |
8504 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
8505 | if (pattern == nullptr) | |
8506 | { | |
8507 | // this is an error | |
8508 | Error error (lexer.peek_token ()->get_locus (), | |
8509 | "failed to parse pattern in match arm patterns"); | |
8510 | add_error (std::move (error)); | |
8511 | ||
8512 | // skip somewhere? | |
8513 | return {}; | |
8514 | } | |
8515 | ||
8516 | patterns.push_back (std::move (pattern)); | |
8517 | ||
8518 | t = lexer.peek_token (); | |
8519 | } | |
8520 | ||
8521 | patterns.shrink_to_fit (); | |
8522 | ||
8523 | return patterns; | |
8524 | } | |
8525 | ||
8526 | // Parses an async block expression. | |
8527 | template <typename ManagedTokenSource> | |
8528 | std::unique_ptr<AST::AsyncBlockExpr> | |
8529 | Parser<ManagedTokenSource>::parse_async_block_expr (AST::AttrVec outer_attrs) | |
8530 | { | |
8531 | location_t locus = lexer.peek_token ()->get_locus (); | |
8532 | skip_token (ASYNC); | |
8533 | ||
8534 | // detect optional move token | |
8535 | bool has_move = false; | |
8536 | if (lexer.peek_token ()->get_id () == MOVE) | |
8537 | { | |
8538 | lexer.skip_token (); | |
8539 | has_move = true; | |
8540 | } | |
8541 | ||
8542 | // parse block expression (required) | |
8543 | std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr (); | |
8544 | if (block_expr == nullptr) | |
8545 | { | |
8546 | Error error ( | |
8547 | lexer.peek_token ()->get_locus (), | |
8548 | "failed to parse block expression of async block expression"); | |
8549 | add_error (std::move (error)); | |
8550 | ||
8551 | // skip somewhere? | |
8552 | return nullptr; | |
8553 | } | |
8554 | ||
8555 | return std::unique_ptr<AST::AsyncBlockExpr> ( | |
8556 | new AST::AsyncBlockExpr (std::move (block_expr), has_move, | |
8557 | std::move (outer_attrs), locus)); | |
8558 | } | |
8559 | ||
8560 | // Parses an unsafe block expression. | |
8561 | template <typename ManagedTokenSource> | |
8562 | std::unique_ptr<AST::UnsafeBlockExpr> | |
8563 | Parser<ManagedTokenSource>::parse_unsafe_block_expr ( | |
8564 | AST::AttrVec outer_attrs, location_t pratt_parsed_loc) | |
8565 | { | |
8566 | location_t locus = pratt_parsed_loc; | |
8567 | if (locus == UNKNOWN_LOCATION) | |
8568 | { | |
8569 | locus = lexer.peek_token ()->get_locus (); | |
8570 | skip_token (UNSAFE); | |
8571 | } | |
8572 | ||
8573 | // parse block expression (required) | |
8574 | std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr (); | |
8575 | if (block_expr == nullptr) | |
8576 | { | |
8577 | Error error ( | |
8578 | lexer.peek_token ()->get_locus (), | |
8579 | "failed to parse block expression of unsafe block expression"); | |
8580 | add_error (std::move (error)); | |
8581 | ||
8582 | // skip somewhere? | |
8583 | return nullptr; | |
8584 | } | |
8585 | ||
8586 | return std::unique_ptr<AST::UnsafeBlockExpr> ( | |
8587 | new AST::UnsafeBlockExpr (std::move (block_expr), std::move (outer_attrs), | |
8588 | locus)); | |
8589 | } | |
8590 | ||
8591 | // Parses an array definition expression. | |
8592 | template <typename ManagedTokenSource> | |
8593 | std::unique_ptr<AST::ArrayExpr> | |
8594 | Parser<ManagedTokenSource>::parse_array_expr (AST::AttrVec outer_attrs, | |
8595 | location_t pratt_parsed_loc) | |
8596 | { | |
8597 | location_t locus = pratt_parsed_loc; | |
8598 | if (locus == UNKNOWN_LOCATION) | |
8599 | { | |
8600 | locus = lexer.peek_token ()->get_locus (); | |
8601 | skip_token (LEFT_SQUARE); | |
8602 | } | |
8603 | ||
8604 | // parse optional inner attributes | |
8605 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
8606 | ||
8607 | // parse the "array elements" section, which is optional | |
8608 | if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) | |
8609 | { | |
8610 | // no array elements | |
8611 | lexer.skip_token (); | |
8612 | ||
8613 | std::vector<std::unique_ptr<AST::Expr>> exprs; | |
8614 | auto array_elems | |
8615 | = std::make_unique<AST::ArrayElemsValues> (std::move (exprs), locus); | |
8616 | return std::make_unique<AST::ArrayExpr> (std::move (array_elems), | |
8617 | std::move (inner_attrs), | |
8618 | std::move (outer_attrs), locus); | |
8619 | } | |
8620 | else | |
8621 | { | |
8622 | // should have array elements | |
8623 | // parse initial expression, which is required for either | |
8624 | std::unique_ptr<AST::Expr> initial_expr = parse_expr (); | |
8625 | if (initial_expr == nullptr) | |
8626 | { | |
8627 | Error error (lexer.peek_token ()->get_locus (), | |
8628 | "could not parse expression in array expression " | |
8629 | "(even though arrayelems seems to be present)"); | |
8630 | add_error (std::move (error)); | |
8631 | ||
8632 | // skip somewhere? | |
8633 | return nullptr; | |
8634 | } | |
8635 | ||
8636 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
8637 | { | |
8638 | // copy array elems | |
8639 | lexer.skip_token (); | |
8640 | ||
8641 | // parse copy amount expression (required) | |
8642 | std::unique_ptr<AST::Expr> copy_amount = parse_expr (); | |
8643 | if (copy_amount == nullptr) | |
8644 | { | |
8645 | Error error (lexer.peek_token ()->get_locus (), | |
8646 | "could not parse copy amount expression in array " | |
8647 | "expression (arrayelems)"); | |
8648 | add_error (std::move (error)); | |
8649 | ||
8650 | // skip somewhere? | |
8651 | return nullptr; | |
8652 | } | |
8653 | ||
8654 | skip_token (RIGHT_SQUARE); | |
8655 | ||
8656 | std::unique_ptr<AST::ArrayElemsCopied> copied_array_elems ( | |
8657 | new AST::ArrayElemsCopied (std::move (initial_expr), | |
8658 | std::move (copy_amount), locus)); | |
8659 | return std::unique_ptr<AST::ArrayExpr> ( | |
8660 | new AST::ArrayExpr (std::move (copied_array_elems), | |
8661 | std::move (inner_attrs), | |
8662 | std::move (outer_attrs), locus)); | |
8663 | } | |
8664 | else if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) | |
8665 | { | |
8666 | // single-element array expression | |
8667 | std::vector<std::unique_ptr<AST::Expr>> exprs; | |
8668 | exprs.reserve (1); | |
8669 | exprs.push_back (std::move (initial_expr)); | |
8670 | exprs.shrink_to_fit (); | |
8671 | ||
8672 | skip_token (RIGHT_SQUARE); | |
8673 | ||
8674 | std::unique_ptr<AST::ArrayElemsValues> array_elems ( | |
8675 | new AST::ArrayElemsValues (std::move (exprs), locus)); | |
8676 | return std::unique_ptr<AST::ArrayExpr> ( | |
8677 | new AST::ArrayExpr (std::move (array_elems), | |
8678 | std::move (inner_attrs), | |
8679 | std::move (outer_attrs), locus)); | |
8680 | } | |
8681 | else if (lexer.peek_token ()->get_id () == COMMA) | |
8682 | { | |
8683 | // multi-element array expression (or trailing comma) | |
8684 | std::vector<std::unique_ptr<AST::Expr>> exprs; | |
8685 | exprs.push_back (std::move (initial_expr)); | |
8686 | ||
8687 | const_TokenPtr t = lexer.peek_token (); | |
8688 | while (t->get_id () == COMMA) | |
8689 | { | |
8690 | lexer.skip_token (); | |
8691 | ||
8692 | // quick break if right square bracket | |
8693 | if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) | |
8694 | break; | |
8695 | ||
8696 | // parse expression (required) | |
8697 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
8698 | if (expr == nullptr) | |
8699 | { | |
8700 | Error error (lexer.peek_token ()->get_locus (), | |
8701 | "failed to parse element in array expression"); | |
8702 | add_error (std::move (error)); | |
8703 | ||
8704 | // skip somewhere? | |
8705 | return nullptr; | |
8706 | } | |
8707 | exprs.push_back (std::move (expr)); | |
8708 | ||
8709 | t = lexer.peek_token (); | |
8710 | } | |
8711 | ||
8712 | skip_token (RIGHT_SQUARE); | |
8713 | ||
8714 | exprs.shrink_to_fit (); | |
8715 | ||
8716 | std::unique_ptr<AST::ArrayElemsValues> array_elems ( | |
8717 | new AST::ArrayElemsValues (std::move (exprs), locus)); | |
8718 | return std::unique_ptr<AST::ArrayExpr> ( | |
8719 | new AST::ArrayExpr (std::move (array_elems), | |
8720 | std::move (inner_attrs), | |
8721 | std::move (outer_attrs), locus)); | |
8722 | } | |
8723 | else | |
8724 | { | |
8725 | // error | |
8726 | Error error (lexer.peek_token ()->get_locus (), | |
8727 | "unexpected token %qs in array expression (arrayelems)", | |
8728 | lexer.peek_token ()->get_token_description ()); | |
8729 | add_error (std::move (error)); | |
8730 | ||
8731 | // skip somewhere? | |
8732 | return nullptr; | |
8733 | } | |
8734 | } | |
8735 | } | |
8736 | ||
8737 | // Parses a single parameter used in a closure definition. | |
8738 | template <typename ManagedTokenSource> | |
8739 | AST::ClosureParam | |
8740 | Parser<ManagedTokenSource>::parse_closure_param () | |
8741 | { | |
8742 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
8743 | ||
8744 | // parse pattern (which is required) | |
8745 | std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt (); | |
8746 | if (pattern == nullptr) | |
8747 | { | |
8748 | // not necessarily an error | |
8749 | return AST::ClosureParam::create_error (); | |
8750 | } | |
8751 | ||
8752 | // parse optional type of param | |
8753 | std::unique_ptr<AST::Type> type = nullptr; | |
8754 | if (lexer.peek_token ()->get_id () == COLON) | |
8755 | { | |
8756 | lexer.skip_token (); | |
8757 | ||
8758 | // parse type, which is now required | |
8759 | type = parse_type (); | |
8760 | if (type == nullptr) | |
8761 | { | |
8762 | Error error (lexer.peek_token ()->get_locus (), | |
8763 | "failed to parse type in closure parameter"); | |
8764 | add_error (std::move (error)); | |
8765 | ||
8766 | // skip somewhere? | |
8767 | return AST::ClosureParam::create_error (); | |
8768 | } | |
8769 | } | |
8770 | ||
8771 | location_t loc = pattern->get_locus (); | |
8772 | return AST::ClosureParam (std::move (pattern), loc, std::move (type), | |
8773 | std::move (outer_attrs)); | |
8774 | } | |
8775 | ||
8776 | // Parses a grouped or tuple expression (disambiguates). | |
8777 | template <typename ManagedTokenSource> | |
8778 | std::unique_ptr<AST::ExprWithoutBlock> | |
8779 | Parser<ManagedTokenSource>::parse_grouped_or_tuple_expr ( | |
8780 | AST::AttrVec outer_attrs, location_t pratt_parsed_loc) | |
8781 | { | |
8782 | // adjustment to allow Pratt parsing to reuse function without copy-paste | |
8783 | location_t locus = pratt_parsed_loc; | |
8784 | if (locus == UNKNOWN_LOCATION) | |
8785 | { | |
8786 | locus = lexer.peek_token ()->get_locus (); | |
8787 | skip_token (LEFT_PAREN); | |
8788 | } | |
8789 | ||
8790 | // parse optional inner attributes | |
8791 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
8792 | ||
8793 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
8794 | { | |
8795 | // must be empty tuple | |
8796 | lexer.skip_token (); | |
8797 | ||
8798 | // create tuple with empty tuple elems | |
8799 | return std::unique_ptr<AST::TupleExpr> ( | |
8800 | new AST::TupleExpr (std::vector<std::unique_ptr<AST::Expr>> (), | |
8801 | std::move (inner_attrs), std::move (outer_attrs), | |
8802 | locus)); | |
8803 | } | |
8804 | ||
8805 | // parse first expression (required) | |
8806 | std::unique_ptr<AST::Expr> first_expr = parse_expr (); | |
8807 | if (first_expr == nullptr) | |
8808 | { | |
8809 | Error error (lexer.peek_token ()->get_locus (), | |
8810 | "failed to parse expression in grouped or tuple expression"); | |
8811 | add_error (std::move (error)); | |
8812 | ||
8813 | // skip after somewhere? | |
8814 | return nullptr; | |
8815 | } | |
8816 | ||
8817 | // detect whether grouped expression with right parentheses as next token | |
8818 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
8819 | { | |
8820 | // must be grouped expr | |
8821 | lexer.skip_token (); | |
8822 | ||
8823 | // create grouped expr | |
8824 | return std::unique_ptr<AST::GroupedExpr> ( | |
8825 | new AST::GroupedExpr (std::move (first_expr), std::move (inner_attrs), | |
8826 | std::move (outer_attrs), locus)); | |
8827 | } | |
8828 | else if (lexer.peek_token ()->get_id () == COMMA) | |
8829 | { | |
8830 | // tuple expr | |
8831 | std::vector<std::unique_ptr<AST::Expr>> exprs; | |
8832 | exprs.push_back (std::move (first_expr)); | |
8833 | ||
8834 | // parse potential other tuple exprs | |
8835 | const_TokenPtr t = lexer.peek_token (); | |
8836 | while (t->get_id () == COMMA) | |
8837 | { | |
8838 | lexer.skip_token (); | |
8839 | ||
8840 | // break out if right paren | |
8841 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
8842 | break; | |
8843 | ||
8844 | // parse expr, which is now required | |
8845 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
8846 | if (expr == nullptr) | |
8847 | { | |
8848 | Error error (lexer.peek_token ()->get_locus (), | |
8849 | "failed to parse expr in tuple expr"); | |
8850 | add_error (std::move (error)); | |
8851 | ||
8852 | // skip somewhere? | |
8853 | return nullptr; | |
8854 | } | |
8855 | exprs.push_back (std::move (expr)); | |
8856 | ||
8857 | t = lexer.peek_token (); | |
8858 | } | |
8859 | ||
8860 | // skip right paren | |
8861 | skip_token (RIGHT_PAREN); | |
8862 | ||
8863 | return std::unique_ptr<AST::TupleExpr> ( | |
8864 | new AST::TupleExpr (std::move (exprs), std::move (inner_attrs), | |
8865 | std::move (outer_attrs), locus)); | |
8866 | } | |
8867 | else | |
8868 | { | |
8869 | // error | |
8870 | const_TokenPtr t = lexer.peek_token (); | |
8871 | Error error (t->get_locus (), | |
8872 | "unexpected token %qs in grouped or tuple expression " | |
8873 | "(parenthesised expression) - expected %<)%> for grouped " | |
8874 | "expr and %<,%> for tuple expr", | |
8875 | t->get_token_description ()); | |
8876 | add_error (std::move (error)); | |
8877 | ||
8878 | // skip somewhere? | |
8879 | return nullptr; | |
8880 | } | |
8881 | } | |
8882 | ||
8883 | // Parses a type (will further disambiguate any type). | |
8884 | template <typename ManagedTokenSource> | |
8885 | std::unique_ptr<AST::Type> | |
8886 | Parser<ManagedTokenSource>::parse_type (bool save_errors) | |
8887 | { | |
8888 | /* rules for all types: | |
8889 | * NeverType: '!' | |
8890 | * SliceType: '[' Type ']' | |
8891 | * InferredType: '_' | |
8892 | * MacroInvocation: SimplePath '!' DelimTokenTree | |
8893 | * ParenthesisedType: '(' Type ')' | |
8894 | * ImplTraitType: 'impl' TypeParamBounds | |
8895 | * TypeParamBounds (not type) TypeParamBound ( '+' TypeParamBound )* '+'? | |
8896 | * TypeParamBound Lifetime | TraitBound | |
8897 | * ImplTraitTypeOneBound: 'impl' TraitBound | |
8898 | * TraitObjectType: 'dyn'? TypeParamBounds | |
8899 | * TraitObjectTypeOneBound: 'dyn'? TraitBound | |
8900 | * TraitBound '?'? ForLifetimes? TypePath | '(' '?'? | |
8901 | * ForLifetimes? TypePath ')' BareFunctionType: ForLifetimes? | |
8902 | * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<' | |
8903 | * LifetimeParams '>' FunctionQualifiers ( 'async' | 'const' )? | |
8904 | * 'unsafe'? | |
8905 | * ('extern' abi?)? QualifiedPathInType: '<' Type ( 'as' TypePath )? '>' | |
8906 | * ( | |
8907 | * '::' TypePathSegment )+ TypePath: '::'? TypePathSegment ( | |
8908 | * '::' TypePathSegment)* ArrayType: '[' Type ';' Expr ']' | |
8909 | * ReferenceType: '&' Lifetime? 'mut'? TypeNoBounds | |
8910 | * RawPointerType: '*' ( 'mut' | 'const' ) TypeNoBounds | |
8911 | * TupleType: '(' Type etc. - regular tuple stuff. Also | |
8912 | * regular tuple vs parenthesised precedence | |
8913 | * | |
8914 | * Disambiguate between macro and type path via type path being parsed, and | |
8915 | * then if '!' found, convert type path to simple path for macro. Usual | |
8916 | * disambiguation for tuple vs parenthesised. For ImplTraitType and | |
8917 | * TraitObjectType individual disambiguations, they seem more like "special | |
8918 | * cases", so probably just try to parse the more general ImplTraitType or | |
8919 | * TraitObjectType and return OneBound versions if they satisfy those | |
8920 | * criteria. */ | |
8921 | ||
8922 | const_TokenPtr t = lexer.peek_token (); | |
8923 | switch (t->get_id ()) | |
8924 | { | |
8925 | case EXCLAM: | |
8926 | // never type - can't be macro as no path beforehand | |
8927 | lexer.skip_token (); | |
8928 | return std::unique_ptr<AST::NeverType> ( | |
8929 | new AST::NeverType (t->get_locus ())); | |
8930 | case LEFT_SQUARE: | |
8931 | // slice type or array type - requires further disambiguation | |
8932 | return parse_slice_or_array_type (); | |
8933 | case LEFT_SHIFT: | |
8934 | case LEFT_ANGLE: { | |
8935 | // qualified path in type | |
8936 | AST::QualifiedPathInType path = parse_qualified_path_in_type (); | |
8937 | if (path.is_error ()) | |
8938 | { | |
8939 | if (save_errors) | |
8940 | { | |
8941 | Error error (t->get_locus (), | |
8942 | "failed to parse qualified path in type"); | |
8943 | add_error (std::move (error)); | |
8944 | } | |
8945 | ||
8946 | return nullptr; | |
8947 | } | |
8948 | return std::unique_ptr<AST::QualifiedPathInType> ( | |
8949 | new AST::QualifiedPathInType (std::move (path))); | |
8950 | } | |
8951 | case UNDERSCORE: | |
8952 | // inferred type | |
8953 | lexer.skip_token (); | |
8954 | return std::unique_ptr<AST::InferredType> ( | |
8955 | new AST::InferredType (t->get_locus ())); | |
8956 | case ASTERISK: | |
8957 | // raw pointer type | |
8958 | return parse_raw_pointer_type (); | |
8959 | case AMP: // does this also include AMP_AMP? | |
8960 | case LOGICAL_AND: | |
8961 | // reference type | |
8962 | return parse_reference_type (); | |
8963 | case LIFETIME: { | |
8964 | /* probably a lifetime bound, so probably type param bounds in | |
8965 | * TraitObjectType */ | |
8966 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds | |
8967 | = parse_type_param_bounds (); | |
8968 | ||
8969 | return std::unique_ptr<AST::TraitObjectType> ( | |
8970 | new AST::TraitObjectType (std::move (bounds), t->get_locus (), | |
8971 | false)); | |
8972 | } | |
8973 | case IDENTIFIER: | |
8974 | case SUPER: | |
8975 | case SELF: | |
8976 | case SELF_ALIAS: | |
8977 | case CRATE: | |
8978 | case DOLLAR_SIGN: | |
8979 | case SCOPE_RESOLUTION: { | |
8980 | // macro invocation or type path - requires further disambiguation. | |
8981 | /* for parsing path component of each rule, perhaps parse it as a | |
8982 | * typepath and attempt conversion to simplepath if a trailing '!' is | |
8983 | * found */ | |
8984 | /* Type path also includes TraitObjectTypeOneBound BUT if it starts | |
8985 | * with it, it is exactly the same as a TypePath syntactically, so | |
8986 | * this is a syntactical ambiguity. As such, the parser will parse it | |
8987 | * as a TypePath. This, however, does not prevent TraitObjectType from | |
8988 | * starting with a typepath. */ | |
8989 | ||
8990 | // parse path as type path | |
8991 | AST::TypePath path = parse_type_path (); | |
8992 | if (path.is_error ()) | |
8993 | { | |
8994 | if (save_errors) | |
8995 | { | |
8996 | Error error (t->get_locus (), | |
8997 | "failed to parse path as first component of type"); | |
8998 | add_error (std::move (error)); | |
8999 | } | |
9000 | ||
9001 | return nullptr; | |
9002 | } | |
9003 | location_t locus = path.get_locus (); | |
9004 | ||
9005 | // branch on next token | |
9006 | t = lexer.peek_token (); | |
9007 | switch (t->get_id ()) | |
9008 | { | |
9009 | case EXCLAM: { | |
9010 | // macro invocation | |
9011 | // convert to simple path | |
9012 | AST::SimplePath macro_path = path.as_simple_path (); | |
9013 | if (macro_path.is_empty ()) | |
9014 | { | |
9015 | if (save_errors) | |
9016 | { | |
9017 | Error error (t->get_locus (), | |
9018 | "failed to parse simple path in macro " | |
9019 | "invocation (for type)"); | |
9020 | add_error (std::move (error)); | |
9021 | } | |
9022 | ||
9023 | return nullptr; | |
9024 | } | |
9025 | ||
9026 | lexer.skip_token (); | |
9027 | ||
9028 | AST::DelimTokenTree tok_tree = parse_delim_token_tree (); | |
9029 | ||
9030 | return AST::MacroInvocation::Regular ( | |
9031 | AST::MacroInvocData (std::move (macro_path), | |
9032 | std::move (tok_tree)), | |
9033 | {}, locus); | |
9034 | } | |
9035 | case PLUS: { | |
9036 | // type param bounds | |
9037 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; | |
9038 | ||
9039 | // convert type path to trait bound | |
9040 | std::unique_ptr<AST::TraitBound> path_bound ( | |
9041 | new AST::TraitBound (std::move (path), locus, false, false)); | |
9042 | bounds.push_back (std::move (path_bound)); | |
9043 | ||
9044 | /* parse rest of bounds - FIXME: better way to find when to stop | |
9045 | * parsing */ | |
9046 | while (t->get_id () == PLUS) | |
9047 | { | |
9048 | lexer.skip_token (); | |
9049 | ||
9050 | // parse bound if it exists - if not, assume end of sequence | |
9051 | std::unique_ptr<AST::TypeParamBound> bound | |
9052 | = parse_type_param_bound (); | |
9053 | if (bound == nullptr) | |
9054 | { | |
9055 | break; | |
9056 | } | |
9057 | bounds.push_back (std::move (bound)); | |
9058 | ||
9059 | t = lexer.peek_token (); | |
9060 | } | |
9061 | ||
9062 | return std::unique_ptr<AST::TraitObjectType> ( | |
9063 | new AST::TraitObjectType (std::move (bounds), locus, false)); | |
9064 | } | |
9065 | default: | |
9066 | // assume that this is a type path and not an error | |
9067 | return std::unique_ptr<AST::TypePath> ( | |
9068 | new AST::TypePath (std::move (path))); | |
9069 | } | |
9070 | } | |
9071 | case LEFT_PAREN: | |
9072 | /* tuple type or parenthesised type - requires further disambiguation | |
9073 | * (the usual). ok apparently can be a parenthesised TraitBound too, so | |
9074 | * could be TraitObjectTypeOneBound or TraitObjectType */ | |
9075 | return parse_paren_prefixed_type (); | |
9076 | case FOR: | |
9077 | // TraitObjectTypeOneBound or BareFunctionType | |
9078 | return parse_for_prefixed_type (); | |
9079 | case ASYNC: | |
9080 | case CONST: | |
9081 | case UNSAFE: | |
9082 | case EXTERN_KW: | |
9083 | case FN_KW: | |
9084 | // bare function type (with no for lifetimes) | |
9085 | return parse_bare_function_type (std::vector<AST::LifetimeParam> ()); | |
9086 | case IMPL: | |
9087 | lexer.skip_token (); | |
9088 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
9089 | { | |
9090 | /* cannot be one bound because lifetime prevents it from being | |
9091 | * traitbound */ | |
9092 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds | |
9093 | = parse_type_param_bounds (); | |
9094 | ||
9095 | return std::unique_ptr<AST::ImplTraitType> ( | |
9096 | new AST::ImplTraitType (std::move (bounds), t->get_locus ())); | |
9097 | } | |
9098 | else | |
9099 | { | |
9100 | // should be trait bound, so parse trait bound | |
9101 | std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound (); | |
9102 | if (initial_bound == nullptr) | |
9103 | { | |
9104 | if (save_errors) | |
9105 | { | |
9106 | Error error (lexer.peek_token ()->get_locus (), | |
9107 | "failed to parse ImplTraitType initial bound"); | |
9108 | add_error (std::move (error)); | |
9109 | } | |
9110 | ||
9111 | return nullptr; | |
9112 | } | |
9113 | ||
9114 | location_t locus = t->get_locus (); | |
9115 | ||
9116 | // short cut if next token isn't '+' | |
9117 | t = lexer.peek_token (); | |
9118 | if (t->get_id () != PLUS) | |
9119 | { | |
9120 | // convert trait bound to value object | |
9121 | AST::TraitBound value_bound (*initial_bound); | |
9122 | ||
9123 | // DEBUG: removed as unique ptr, so should auto-delete | |
9124 | // delete initial_bound; | |
9125 | ||
9126 | return std::unique_ptr<AST::ImplTraitTypeOneBound> ( | |
9127 | new AST::ImplTraitTypeOneBound (std::move (value_bound), | |
9128 | locus)); | |
9129 | } | |
9130 | ||
9131 | // parse additional type param bounds | |
9132 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; | |
9133 | bounds.push_back (std::move (initial_bound)); | |
9134 | while (t->get_id () == PLUS) | |
9135 | { | |
9136 | lexer.skip_token (); | |
9137 | ||
9138 | // parse bound if it exists | |
9139 | std::unique_ptr<AST::TypeParamBound> bound | |
9140 | = parse_type_param_bound (); | |
9141 | if (bound == nullptr) | |
9142 | { | |
9143 | // not an error as trailing plus may exist | |
9144 | break; | |
9145 | } | |
9146 | bounds.push_back (std::move (bound)); | |
9147 | ||
9148 | t = lexer.peek_token (); | |
9149 | } | |
9150 | ||
9151 | return std::unique_ptr<AST::ImplTraitType> ( | |
9152 | new AST::ImplTraitType (std::move (bounds), locus)); | |
9153 | } | |
9154 | case DYN: | |
9155 | case QUESTION_MARK: { | |
9156 | // either TraitObjectType or TraitObjectTypeOneBound | |
9157 | bool has_dyn = false; | |
9158 | if (t->get_id () == DYN) | |
9159 | { | |
9160 | lexer.skip_token (); | |
9161 | has_dyn = true; | |
9162 | } | |
9163 | ||
9164 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
9165 | { | |
9166 | /* cannot be one bound because lifetime prevents it from being | |
9167 | * traitbound */ | |
9168 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds | |
9169 | = parse_type_param_bounds (); | |
9170 | ||
9171 | return std::unique_ptr<AST::TraitObjectType> ( | |
9172 | new AST::TraitObjectType (std::move (bounds), t->get_locus (), | |
9173 | has_dyn)); | |
9174 | } | |
9175 | else | |
9176 | { | |
9177 | // should be trait bound, so parse trait bound | |
9178 | std::unique_ptr<AST::TraitBound> initial_bound | |
9179 | = parse_trait_bound (); | |
9180 | if (initial_bound == nullptr) | |
9181 | { | |
9182 | if (save_errors) | |
9183 | { | |
9184 | Error error ( | |
9185 | lexer.peek_token ()->get_locus (), | |
9186 | "failed to parse TraitObjectType initial bound"); | |
9187 | add_error (std::move (error)); | |
9188 | } | |
9189 | ||
9190 | return nullptr; | |
9191 | } | |
9192 | ||
9193 | // short cut if next token isn't '+' | |
9194 | t = lexer.peek_token (); | |
9195 | if (t->get_id () != PLUS) | |
9196 | { | |
9197 | // convert trait bound to value object | |
9198 | AST::TraitBound value_bound (*initial_bound); | |
9199 | ||
9200 | // DEBUG: removed as unique ptr, so should auto delete | |
9201 | // delete initial_bound; | |
9202 | ||
9203 | return std::unique_ptr<AST::TraitObjectTypeOneBound> ( | |
9204 | new AST::TraitObjectTypeOneBound (std::move (value_bound), | |
9205 | t->get_locus (), has_dyn)); | |
9206 | } | |
9207 | ||
9208 | // parse additional type param bounds | |
9209 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; | |
9210 | bounds.push_back (std::move (initial_bound)); | |
9211 | while (t->get_id () == PLUS) | |
9212 | { | |
9213 | lexer.skip_token (); | |
9214 | ||
9215 | // parse bound if it exists | |
9216 | std::unique_ptr<AST::TypeParamBound> bound | |
9217 | = parse_type_param_bound (); | |
9218 | if (bound == nullptr) | |
9219 | { | |
9220 | // not an error as trailing plus may exist | |
9221 | break; | |
9222 | } | |
9223 | bounds.push_back (std::move (bound)); | |
9224 | ||
9225 | t = lexer.peek_token (); | |
9226 | } | |
9227 | ||
9228 | return std::unique_ptr<AST::TraitObjectType> ( | |
9229 | new AST::TraitObjectType (std::move (bounds), t->get_locus (), | |
9230 | has_dyn)); | |
9231 | } | |
9232 | } | |
9233 | default: | |
9234 | if (save_errors) | |
9235 | add_error (Error (t->get_locus (), "unrecognised token %qs in type", | |
9236 | t->get_token_description ())); | |
9237 | ||
9238 | return nullptr; | |
9239 | } | |
9240 | } | |
9241 | ||
9242 | /* Parses a type that has '(' as its first character. Returns a tuple type, | |
9243 | * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending | |
9244 | * on following characters. */ | |
9245 | template <typename ManagedTokenSource> | |
9246 | std::unique_ptr<AST::Type> | |
9247 | Parser<ManagedTokenSource>::parse_paren_prefixed_type () | |
9248 | { | |
9249 | /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered | |
9250 | * a trait bound, not a parenthesised type, so that it can still be used in | |
9251 | * type param bounds. */ | |
9252 | ||
9253 | /* NOTE: this implementation is really shit but I couldn't think of a better | |
9254 | * one. It requires essentially breaking polymorphism and downcasting via | |
9255 | * virtual method abuse, as it was copied from the rustc implementation (in | |
9256 | * which types are reified due to tagged union), after a more OOP attempt by | |
9257 | * me failed. */ | |
9258 | location_t left_delim_locus = lexer.peek_token ()->get_locus (); | |
9259 | ||
9260 | // skip left delim | |
9261 | lexer.skip_token (); | |
9262 | /* while next token isn't close delim, parse comma-separated types, saving | |
9263 | * whether trailing comma happens */ | |
9264 | const_TokenPtr t = lexer.peek_token (); | |
9265 | bool trailing_comma = true; | |
9266 | std::vector<std::unique_ptr<AST::Type>> types; | |
9267 | ||
9268 | while (t->get_id () != RIGHT_PAREN) | |
9269 | { | |
9270 | std::unique_ptr<AST::Type> type = parse_type (); | |
9271 | if (type == nullptr) | |
9272 | { | |
9273 | Error error (t->get_locus (), | |
9274 | "failed to parse type inside parentheses (probably " | |
9275 | "tuple or parenthesised)"); | |
9276 | add_error (std::move (error)); | |
9277 | ||
9278 | return nullptr; | |
9279 | } | |
9280 | types.push_back (std::move (type)); | |
9281 | ||
9282 | t = lexer.peek_token (); | |
9283 | if (t->get_id () != COMMA) | |
9284 | { | |
9285 | trailing_comma = false; | |
9286 | break; | |
9287 | } | |
9288 | lexer.skip_token (); | |
9289 | ||
9290 | t = lexer.peek_token (); | |
9291 | } | |
9292 | ||
9293 | if (!skip_token (RIGHT_PAREN)) | |
9294 | { | |
9295 | return nullptr; | |
9296 | } | |
9297 | ||
9298 | // if only one type and no trailing comma, then not a tuple type | |
9299 | if (types.size () == 1 && !trailing_comma) | |
9300 | { | |
9301 | // must be a TraitObjectType (with more than one bound) | |
9302 | if (lexer.peek_token ()->get_id () == PLUS) | |
9303 | { | |
9304 | // create type param bounds vector | |
9305 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; | |
9306 | ||
9307 | // HACK: convert type to traitbound and add to bounds | |
9308 | std::unique_ptr<AST::Type> released_ptr = std::move (types[0]); | |
9309 | std::unique_ptr<AST::TraitBound> converted_bound ( | |
9310 | released_ptr->to_trait_bound (true)); | |
9311 | if (converted_bound == nullptr) | |
9312 | { | |
9313 | Error error ( | |
9314 | lexer.peek_token ()->get_locus (), | |
9315 | "failed to hackily converted parsed type to trait bound"); | |
9316 | add_error (std::move (error)); | |
9317 | ||
9318 | return nullptr; | |
9319 | } | |
9320 | bounds.push_back (std::move (converted_bound)); | |
9321 | ||
9322 | t = lexer.peek_token (); | |
9323 | while (t->get_id () == PLUS) | |
9324 | { | |
9325 | lexer.skip_token (); | |
9326 | ||
9327 | // attempt to parse typeparambound | |
9328 | std::unique_ptr<AST::TypeParamBound> bound | |
9329 | = parse_type_param_bound (); | |
9330 | if (bound == nullptr) | |
9331 | { | |
9332 | // not an error if null | |
9333 | break; | |
9334 | } | |
9335 | bounds.push_back (std::move (bound)); | |
9336 | ||
9337 | t = lexer.peek_token (); | |
9338 | } | |
9339 | ||
9340 | return std::unique_ptr<AST::TraitObjectType> ( | |
9341 | new AST::TraitObjectType (std::move (bounds), left_delim_locus, | |
9342 | false)); | |
9343 | } | |
9344 | else | |
9345 | { | |
9346 | // release vector pointer | |
9347 | std::unique_ptr<AST::Type> released_ptr = std::move (types[0]); | |
9348 | /* HACK: attempt to convert to trait bound. if fails, parenthesised | |
9349 | * type */ | |
9350 | std::unique_ptr<AST::TraitBound> converted_bound ( | |
9351 | released_ptr->to_trait_bound (true)); | |
9352 | if (converted_bound == nullptr) | |
9353 | { | |
9354 | // parenthesised type | |
9355 | return std::unique_ptr<AST::ParenthesisedType> ( | |
9356 | new AST::ParenthesisedType (std::move (released_ptr), | |
9357 | left_delim_locus)); | |
9358 | } | |
9359 | else | |
9360 | { | |
9361 | // trait object type (one bound) | |
9362 | ||
9363 | // get value semantics trait bound | |
9364 | AST::TraitBound value_bound (*converted_bound); | |
9365 | ||
9366 | return std::unique_ptr<AST::TraitObjectTypeOneBound> ( | |
9367 | new AST::TraitObjectTypeOneBound (value_bound, | |
9368 | left_delim_locus)); | |
9369 | } | |
9370 | } | |
9371 | } | |
9372 | else | |
9373 | { | |
9374 | return std::unique_ptr<AST::TupleType> ( | |
9375 | new AST::TupleType (std::move (types), left_delim_locus)); | |
9376 | } | |
9377 | /* TODO: ensure that this ensures that dynamic dispatch for traits is not | |
9378 | * lost somehow */ | |
9379 | } | |
9380 | ||
9381 | /* Parses a type that has 'for' as its first character. This means it has a | |
9382 | * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or | |
9383 | * TraitObjectTypeOneBound depending on following characters. */ | |
9384 | template <typename ManagedTokenSource> | |
9385 | std::unique_ptr<AST::Type> | |
9386 | Parser<ManagedTokenSource>::parse_for_prefixed_type () | |
9387 | { | |
9388 | location_t for_locus = lexer.peek_token ()->get_locus (); | |
9389 | // parse for lifetimes in type | |
9390 | std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes (); | |
9391 | ||
9392 | // branch on next token - either function or a trait type | |
9393 | const_TokenPtr t = lexer.peek_token (); | |
9394 | switch (t->get_id ()) | |
9395 | { | |
9396 | case ASYNC: | |
9397 | case CONST: | |
9398 | case UNSAFE: | |
9399 | case EXTERN_KW: | |
9400 | case FN_KW: | |
9401 | return parse_bare_function_type (std::move (for_lifetimes)); | |
9402 | case SCOPE_RESOLUTION: | |
9403 | case IDENTIFIER: | |
9404 | case SUPER: | |
9405 | case SELF: | |
9406 | case SELF_ALIAS: | |
9407 | case CRATE: | |
9408 | case DOLLAR_SIGN: { | |
9409 | // path, so trait type | |
9410 | ||
9411 | // parse type path to finish parsing trait bound | |
9412 | AST::TypePath path = parse_type_path (); | |
9413 | ||
9414 | t = lexer.peek_token (); | |
9415 | if (t->get_id () != PLUS) | |
9416 | { | |
9417 | // must be one-bound trait type | |
9418 | // create trait bound value object | |
9419 | AST::TraitBound bound (std::move (path), for_locus, false, false, | |
9420 | std::move (for_lifetimes)); | |
9421 | ||
9422 | return std::unique_ptr<AST::TraitObjectTypeOneBound> ( | |
9423 | new AST::TraitObjectTypeOneBound (std::move (bound), for_locus)); | |
9424 | } | |
9425 | ||
9426 | /* more than one bound trait type (or at least parsed as it - could be | |
9427 | * trailing '+') create trait bound pointer and bounds */ | |
9428 | std::unique_ptr<AST::TraitBound> initial_bound ( | |
9429 | new AST::TraitBound (std::move (path), for_locus, false, false, | |
9430 | std::move (for_lifetimes))); | |
9431 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; | |
9432 | bounds.push_back (std::move (initial_bound)); | |
9433 | ||
9434 | while (t->get_id () == PLUS) | |
9435 | { | |
9436 | lexer.skip_token (); | |
9437 | ||
9438 | // parse type param bound if it exists | |
9439 | std::unique_ptr<AST::TypeParamBound> bound | |
9440 | = parse_type_param_bound (); | |
9441 | if (bound == nullptr) | |
9442 | { | |
9443 | // not an error - e.g. trailing plus | |
9444 | return nullptr; | |
9445 | } | |
9446 | bounds.push_back (std::move (bound)); | |
9447 | ||
9448 | t = lexer.peek_token (); | |
9449 | } | |
9450 | ||
9451 | return std::unique_ptr<AST::TraitObjectType> ( | |
9452 | new AST::TraitObjectType (std::move (bounds), for_locus, false)); | |
9453 | } | |
9454 | default: | |
9455 | // error | |
9456 | add_error (Error (t->get_locus (), | |
9457 | "unrecognised token %qs in bare function type or trait " | |
9458 | "object type or trait object type one bound", | |
9459 | t->get_token_description ())); | |
9460 | ||
9461 | return nullptr; | |
9462 | } | |
9463 | } | |
9464 | ||
9465 | // Parses a maybe named param used in bare function types. | |
9466 | template <typename ManagedTokenSource> | |
9467 | AST::MaybeNamedParam | |
9468 | Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs) | |
9469 | { | |
9470 | /* Basically guess that param is named if first token is identifier or | |
9471 | * underscore and second token is semicolon. This should probably have no | |
9472 | * exceptions. rustc uses backtracking to parse these, but at the time of | |
9473 | * writing gccrs has no backtracking capabilities. */ | |
9474 | const_TokenPtr current = lexer.peek_token (); | |
9475 | const_TokenPtr next = lexer.peek_token (1); | |
9476 | ||
9477 | Identifier name; | |
9478 | AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED; | |
9479 | ||
9480 | if (current->get_id () == IDENTIFIER && next->get_id () == COLON) | |
9481 | { | |
9482 | // named param | |
9483 | name = {current}; | |
9484 | kind = AST::MaybeNamedParam::IDENTIFIER; | |
9485 | lexer.skip_token (1); | |
9486 | } | |
9487 | else if (current->get_id () == UNDERSCORE && next->get_id () == COLON) | |
9488 | { | |
9489 | // wildcard param | |
9490 | name = {Values::Keywords::UNDERSCORE, current->get_locus ()}; | |
9491 | kind = AST::MaybeNamedParam::WILDCARD; | |
9492 | lexer.skip_token (1); | |
9493 | } | |
9494 | ||
9495 | // parse type (required) | |
9496 | std::unique_ptr<AST::Type> type = parse_type (); | |
9497 | if (type == nullptr) | |
9498 | { | |
9499 | Error error (lexer.peek_token ()->get_locus (), | |
9500 | "failed to parse type in maybe named param"); | |
9501 | add_error (std::move (error)); | |
9502 | ||
9503 | return AST::MaybeNamedParam::create_error (); | |
9504 | } | |
9505 | ||
9506 | return AST::MaybeNamedParam (std::move (name), kind, std::move (type), | |
9507 | std::move (outer_attrs), current->get_locus ()); | |
9508 | } | |
9509 | ||
9510 | /* Parses a bare function type (with the given for lifetimes for convenience - | |
9511 | * does not parse them itself). */ | |
9512 | template <typename ManagedTokenSource> | |
9513 | std::unique_ptr<AST::BareFunctionType> | |
9514 | Parser<ManagedTokenSource>::parse_bare_function_type ( | |
9515 | std::vector<AST::LifetimeParam> for_lifetimes) | |
9516 | { | |
9517 | // TODO: pass in for lifetime location as param | |
9518 | location_t best_try_locus = lexer.peek_token ()->get_locus (); | |
9519 | ||
9520 | AST::FunctionQualifiers qualifiers = parse_function_qualifiers (); | |
9521 | ||
9522 | if (!skip_token (FN_KW)) | |
9523 | return nullptr; | |
9524 | ||
9525 | if (!skip_token (LEFT_PAREN)) | |
9526 | return nullptr; | |
9527 | ||
9528 | // parse function params, if they exist | |
9529 | std::vector<AST::MaybeNamedParam> params; | |
9530 | bool is_variadic = false; | |
9531 | AST::AttrVec variadic_attrs; | |
9532 | ||
9533 | const_TokenPtr t = lexer.peek_token (); | |
9534 | while (t->get_id () != RIGHT_PAREN) | |
9535 | { | |
9536 | AST::AttrVec temp_attrs = parse_outer_attributes (); | |
9537 | ||
9538 | if (lexer.peek_token ()->get_id () == ELLIPSIS) | |
9539 | { | |
9540 | lexer.skip_token (); | |
9541 | is_variadic = true; | |
9542 | variadic_attrs = std::move (temp_attrs); | |
9543 | ||
9544 | t = lexer.peek_token (); | |
9545 | ||
9546 | if (t->get_id () != RIGHT_PAREN) | |
9547 | { | |
9548 | Error error (t->get_locus (), | |
9549 | "expected right parentheses after variadic in maybe " | |
9550 | "named function " | |
9551 | "parameters, found %qs", | |
9552 | t->get_token_description ()); | |
9553 | add_error (std::move (error)); | |
9554 | ||
9555 | return nullptr; | |
9556 | } | |
9557 | ||
9558 | break; | |
9559 | } | |
9560 | ||
9561 | AST::MaybeNamedParam param | |
9562 | = parse_maybe_named_param (std::move (temp_attrs)); | |
9563 | if (param.is_error ()) | |
9564 | { | |
9565 | Error error ( | |
9566 | lexer.peek_token ()->get_locus (), | |
9567 | "failed to parse maybe named param in bare function type"); | |
9568 | add_error (std::move (error)); | |
9569 | ||
9570 | return nullptr; | |
9571 | } | |
9572 | params.push_back (std::move (param)); | |
9573 | ||
9574 | if (lexer.peek_token ()->get_id () != COMMA) | |
9575 | break; | |
9576 | ||
9577 | lexer.skip_token (); | |
9578 | t = lexer.peek_token (); | |
9579 | } | |
9580 | ||
9581 | if (!skip_token (RIGHT_PAREN)) | |
9582 | return nullptr; | |
9583 | ||
9584 | // bare function return type, if exists | |
9585 | std::unique_ptr<AST::TypeNoBounds> return_type = nullptr; | |
9586 | if (lexer.peek_token ()->get_id () == RETURN_TYPE) | |
9587 | { | |
9588 | lexer.skip_token (); | |
9589 | ||
9590 | // parse required TypeNoBounds | |
9591 | return_type = parse_type_no_bounds (); | |
9592 | if (return_type == nullptr) | |
9593 | { | |
9594 | Error error (lexer.peek_token ()->get_locus (), | |
9595 | "failed to parse return type (type no bounds) in bare " | |
9596 | "function type"); | |
9597 | add_error (std::move (error)); | |
9598 | ||
9599 | return nullptr; | |
9600 | } | |
9601 | } | |
9602 | ||
9603 | return std::unique_ptr<AST::BareFunctionType> ( | |
9604 | new AST::BareFunctionType (std::move (for_lifetimes), | |
9605 | std::move (qualifiers), std::move (params), | |
9606 | is_variadic, std::move (variadic_attrs), | |
9607 | std::move (return_type), best_try_locus)); | |
9608 | } | |
9609 | ||
9610 | template <typename ManagedTokenSource> | |
9611 | std::unique_ptr<AST::ReferenceType> | |
9612 | Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus) | |
9613 | { | |
9614 | // parse optional lifetime | |
9615 | AST::Lifetime lifetime = AST::Lifetime::elided (); | |
9616 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
9617 | { | |
9618 | auto parsed_lifetime = parse_lifetime (true); | |
9619 | if (parsed_lifetime) | |
9620 | { | |
9621 | lifetime = parsed_lifetime.value (); | |
9622 | } | |
9623 | else | |
9624 | { | |
9625 | Error error (lexer.peek_token ()->get_locus (), | |
9626 | "failed to parse lifetime in reference type"); | |
9627 | add_error (std::move (error)); | |
9628 | ||
9629 | return nullptr; | |
9630 | } | |
9631 | } | |
9632 | ||
9633 | bool is_mut = false; | |
9634 | if (lexer.peek_token ()->get_id () == MUT) | |
9635 | { | |
9636 | lexer.skip_token (); | |
9637 | is_mut = true; | |
9638 | } | |
9639 | ||
9640 | // parse type no bounds, which is required | |
9641 | std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds (); | |
9642 | if (type == nullptr) | |
9643 | { | |
9644 | Error error (lexer.peek_token ()->get_locus (), | |
9645 | "failed to parse referenced type in reference type"); | |
9646 | add_error (std::move (error)); | |
9647 | ||
9648 | return nullptr; | |
9649 | } | |
9650 | ||
9651 | return std::unique_ptr<AST::ReferenceType> ( | |
9652 | new AST::ReferenceType (is_mut, std::move (type), locus, | |
9653 | std::move (lifetime))); | |
9654 | } | |
9655 | ||
9656 | // Parses a reference type (mutable or immutable, with given lifetime). | |
9657 | template <typename ManagedTokenSource> | |
9658 | std::unique_ptr<AST::ReferenceType> | |
9659 | Parser<ManagedTokenSource>::parse_reference_type () | |
9660 | { | |
9661 | auto t = lexer.peek_token (); | |
9662 | auto locus = t->get_locus (); | |
9663 | ||
9664 | switch (t->get_id ()) | |
9665 | { | |
9666 | case AMP: | |
9667 | skip_token (AMP); | |
9668 | return parse_reference_type_inner (locus); | |
9669 | case LOGICAL_AND: | |
9670 | skip_token (LOGICAL_AND); | |
9671 | return std::unique_ptr<AST::ReferenceType> ( | |
9672 | new AST::ReferenceType (false, parse_reference_type_inner (locus), | |
9673 | locus)); | |
9674 | default: | |
9675 | rust_unreachable (); | |
9676 | } | |
9677 | } | |
9678 | ||
9679 | // Parses a raw (unsafe) pointer type. | |
9680 | template <typename ManagedTokenSource> | |
9681 | std::unique_ptr<AST::RawPointerType> | |
9682 | Parser<ManagedTokenSource>::parse_raw_pointer_type () | |
9683 | { | |
9684 | location_t locus = lexer.peek_token ()->get_locus (); | |
9685 | skip_token (ASTERISK); | |
9686 | ||
9687 | AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST; | |
9688 | ||
9689 | // branch on next token for pointer kind info | |
9690 | const_TokenPtr t = lexer.peek_token (); | |
9691 | switch (t->get_id ()) | |
9692 | { | |
9693 | case MUT: | |
9694 | kind = AST::RawPointerType::MUT; | |
9695 | lexer.skip_token (); | |
9696 | break; | |
9697 | case CONST: | |
9698 | kind = AST::RawPointerType::CONST; | |
9699 | lexer.skip_token (); | |
9700 | break; | |
9701 | default: | |
9702 | add_error (Error (t->get_locus (), | |
9703 | "unrecognised token %qs in raw pointer type", | |
9704 | t->get_token_description ())); | |
9705 | ||
9706 | return nullptr; | |
9707 | } | |
9708 | ||
9709 | // parse type no bounds (required) | |
9710 | std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds (); | |
9711 | if (type == nullptr) | |
9712 | { | |
9713 | Error error (lexer.peek_token ()->get_locus (), | |
9714 | "failed to parse pointed type of raw pointer type"); | |
9715 | add_error (std::move (error)); | |
9716 | ||
9717 | return nullptr; | |
9718 | } | |
9719 | ||
9720 | return std::unique_ptr<AST::RawPointerType> ( | |
9721 | new AST::RawPointerType (kind, std::move (type), locus)); | |
9722 | } | |
9723 | ||
9724 | /* Parses a slice or array type, depending on following arguments (as | |
9725 | * lookahead is not possible). */ | |
9726 | template <typename ManagedTokenSource> | |
9727 | std::unique_ptr<AST::TypeNoBounds> | |
9728 | Parser<ManagedTokenSource>::parse_slice_or_array_type () | |
9729 | { | |
9730 | location_t locus = lexer.peek_token ()->get_locus (); | |
9731 | skip_token (LEFT_SQUARE); | |
9732 | ||
9733 | // parse inner type (required) | |
9734 | std::unique_ptr<AST::Type> inner_type = parse_type (); | |
9735 | if (inner_type == nullptr) | |
9736 | { | |
9737 | Error error (lexer.peek_token ()->get_locus (), | |
9738 | "failed to parse inner type in slice or array type"); | |
9739 | add_error (std::move (error)); | |
9740 | ||
9741 | return nullptr; | |
9742 | } | |
9743 | ||
9744 | // branch on next token | |
9745 | const_TokenPtr t = lexer.peek_token (); | |
9746 | switch (t->get_id ()) | |
9747 | { | |
9748 | case RIGHT_SQUARE: | |
9749 | // slice type | |
9750 | lexer.skip_token (); | |
9751 | ||
9752 | return std::unique_ptr<AST::SliceType> ( | |
9753 | new AST::SliceType (std::move (inner_type), locus)); | |
9754 | case SEMICOLON: { | |
9755 | // array type | |
9756 | lexer.skip_token (); | |
9757 | ||
9758 | // parse required array size expression | |
9759 | std::unique_ptr<AST::Expr> size = parse_expr (); | |
9760 | if (size == nullptr) | |
9761 | { | |
9762 | Error error (lexer.peek_token ()->get_locus (), | |
9763 | "failed to parse size expression in array type"); | |
9764 | add_error (std::move (error)); | |
9765 | ||
9766 | return nullptr; | |
9767 | } | |
9768 | ||
9769 | if (!skip_token (RIGHT_SQUARE)) | |
9770 | { | |
9771 | return nullptr; | |
9772 | } | |
9773 | ||
9774 | return std::unique_ptr<AST::ArrayType> ( | |
9775 | new AST::ArrayType (std::move (inner_type), std::move (size), locus)); | |
9776 | } | |
9777 | default: | |
9778 | // error | |
9779 | add_error ( | |
9780 | Error (t->get_locus (), | |
9781 | "unrecognised token %qs in slice or array type after inner type", | |
9782 | t->get_token_description ())); | |
9783 | ||
9784 | return nullptr; | |
9785 | } | |
9786 | } | |
9787 | ||
9788 | // Parses a type, taking into account type boundary disambiguation. | |
9789 | template <typename ManagedTokenSource> | |
9790 | std::unique_ptr<AST::TypeNoBounds> | |
9791 | Parser<ManagedTokenSource>::parse_type_no_bounds () | |
9792 | { | |
9793 | const_TokenPtr t = lexer.peek_token (); | |
9794 | switch (t->get_id ()) | |
9795 | { | |
9796 | case EXCLAM: | |
9797 | // never type - can't be macro as no path beforehand | |
9798 | lexer.skip_token (); | |
9799 | return std::unique_ptr<AST::NeverType> ( | |
9800 | new AST::NeverType (t->get_locus ())); | |
9801 | case LEFT_SQUARE: | |
9802 | // slice type or array type - requires further disambiguation | |
9803 | return parse_slice_or_array_type (); | |
9804 | case LEFT_SHIFT: | |
9805 | case LEFT_ANGLE: { | |
9806 | // qualified path in type | |
9807 | AST::QualifiedPathInType path = parse_qualified_path_in_type (); | |
9808 | if (path.is_error ()) | |
9809 | { | |
9810 | Error error (t->get_locus (), | |
9811 | "failed to parse qualified path in type"); | |
9812 | add_error (std::move (error)); | |
9813 | ||
9814 | return nullptr; | |
9815 | } | |
9816 | return std::unique_ptr<AST::QualifiedPathInType> ( | |
9817 | new AST::QualifiedPathInType (std::move (path))); | |
9818 | } | |
9819 | case UNDERSCORE: | |
9820 | // inferred type | |
9821 | lexer.skip_token (); | |
9822 | return std::unique_ptr<AST::InferredType> ( | |
9823 | new AST::InferredType (t->get_locus ())); | |
9824 | case ASTERISK: | |
9825 | // raw pointer type | |
9826 | return parse_raw_pointer_type (); | |
9827 | case AMP: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND? | |
9828 | case LOGICAL_AND: | |
9829 | // reference type | |
9830 | return parse_reference_type (); | |
9831 | case LIFETIME: | |
9832 | /* probably a lifetime bound, so probably type param bounds in | |
9833 | * TraitObjectType. this is not allowed, but detection here for error | |
9834 | * message */ | |
9835 | add_error (Error (t->get_locus (), | |
9836 | "lifetime bounds (i.e. in type param bounds, in " | |
9837 | "TraitObjectType) are not allowed as TypeNoBounds")); | |
9838 | ||
9839 | return nullptr; | |
9840 | case IDENTIFIER: | |
9841 | case SUPER: | |
9842 | case SELF: | |
9843 | case SELF_ALIAS: | |
9844 | case CRATE: | |
9845 | case DOLLAR_SIGN: | |
9846 | case SCOPE_RESOLUTION: { | |
9847 | // macro invocation or type path - requires further disambiguation. | |
9848 | /* for parsing path component of each rule, perhaps parse it as a | |
9849 | * typepath and attempt conversion to simplepath if a trailing '!' is | |
9850 | * found */ | |
9851 | /* Type path also includes TraitObjectTypeOneBound BUT if it starts | |
9852 | * with it, it is exactly the same as a TypePath syntactically, so | |
9853 | * this is a syntactical ambiguity. As such, the parser will parse it | |
9854 | * as a TypePath. This, however, does not prevent TraitObjectType from | |
9855 | * starting with a typepath. */ | |
9856 | ||
9857 | // parse path as type path | |
9858 | AST::TypePath path = parse_type_path (); | |
9859 | if (path.is_error ()) | |
9860 | { | |
9861 | Error error ( | |
9862 | t->get_locus (), | |
9863 | "failed to parse path as first component of type no bounds"); | |
9864 | add_error (std::move (error)); | |
9865 | ||
9866 | return nullptr; | |
9867 | } | |
9868 | location_t locus = path.get_locus (); | |
9869 | ||
9870 | // branch on next token | |
9871 | t = lexer.peek_token (); | |
9872 | switch (t->get_id ()) | |
9873 | { | |
9874 | case EXCLAM: { | |
9875 | // macro invocation | |
9876 | // convert to simple path | |
9877 | AST::SimplePath macro_path = path.as_simple_path (); | |
9878 | if (macro_path.is_empty ()) | |
9879 | { | |
9880 | Error error (t->get_locus (), | |
9881 | "failed to parse simple path in macro " | |
9882 | "invocation (for type)"); | |
9883 | add_error (std::move (error)); | |
9884 | ||
9885 | return nullptr; | |
9886 | } | |
9887 | ||
9888 | lexer.skip_token (); | |
9889 | ||
9890 | AST::DelimTokenTree tok_tree = parse_delim_token_tree (); | |
9891 | ||
9892 | return AST::MacroInvocation::Regular ( | |
9893 | AST::MacroInvocData (std::move (macro_path), | |
9894 | std::move (tok_tree)), | |
9895 | {}, locus); | |
9896 | } | |
9897 | default: | |
9898 | // assume that this is a type path and not an error | |
9899 | return std::unique_ptr<AST::TypePath> ( | |
9900 | new AST::TypePath (std::move (path))); | |
9901 | } | |
9902 | } | |
9903 | case LEFT_PAREN: | |
9904 | /* tuple type or parenthesised type - requires further disambiguation | |
9905 | * (the usual). ok apparently can be a parenthesised TraitBound too, so | |
9906 | * could be TraitObjectTypeOneBound */ | |
9907 | return parse_paren_prefixed_type_no_bounds (); | |
9908 | case FOR: | |
9909 | case ASYNC: | |
9910 | case CONST: | |
9911 | case UNSAFE: | |
9912 | case EXTERN_KW: | |
9913 | case FN_KW: | |
9914 | // bare function type (with no for lifetimes) | |
9915 | return parse_bare_function_type (std::vector<AST::LifetimeParam> ()); | |
9916 | case IMPL: | |
9917 | lexer.skip_token (); | |
9918 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
9919 | { | |
9920 | /* cannot be one bound because lifetime prevents it from being | |
9921 | * traitbound not allowed as type no bounds, only here for error | |
9922 | * message */ | |
9923 | Error error ( | |
9924 | lexer.peek_token ()->get_locus (), | |
9925 | "lifetime (probably lifetime bound, in type param " | |
9926 | "bounds, in ImplTraitType) is not allowed in TypeNoBounds"); | |
9927 | add_error (std::move (error)); | |
9928 | ||
9929 | return nullptr; | |
9930 | } | |
9931 | else | |
9932 | { | |
9933 | // should be trait bound, so parse trait bound | |
9934 | std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound (); | |
9935 | if (initial_bound == nullptr) | |
9936 | { | |
9937 | Error error (lexer.peek_token ()->get_locus (), | |
9938 | "failed to parse ImplTraitTypeOneBound bound"); | |
9939 | add_error (std::move (error)); | |
9940 | ||
9941 | return nullptr; | |
9942 | } | |
9943 | ||
9944 | location_t locus = t->get_locus (); | |
9945 | ||
9946 | // ensure not a trait with multiple bounds | |
9947 | t = lexer.peek_token (); | |
9948 | if (t->get_id () == PLUS) | |
9949 | { | |
9950 | Error error (t->get_locus (), | |
9951 | "plus after trait bound means an ImplTraitType, " | |
9952 | "which is not allowed as a TypeNoBounds"); | |
9953 | add_error (std::move (error)); | |
9954 | ||
9955 | return nullptr; | |
9956 | } | |
9957 | ||
9958 | // convert trait bound to value object | |
9959 | AST::TraitBound value_bound (*initial_bound); | |
9960 | ||
9961 | return std::unique_ptr<AST::ImplTraitTypeOneBound> ( | |
9962 | new AST::ImplTraitTypeOneBound (std::move (value_bound), locus)); | |
9963 | } | |
9964 | case DYN: | |
9965 | case QUESTION_MARK: { | |
9966 | // either TraitObjectTypeOneBound | |
9967 | bool has_dyn = false; | |
9968 | if (t->get_id () == DYN) | |
9969 | { | |
9970 | lexer.skip_token (); | |
9971 | has_dyn = true; | |
9972 | } | |
9973 | ||
9974 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
9975 | { | |
9976 | /* means that cannot be TraitObjectTypeOneBound - so here for | |
9977 | * error message */ | |
9978 | Error error (lexer.peek_token ()->get_locus (), | |
9979 | "lifetime as bound in TraitObjectTypeOneBound " | |
9980 | "is not allowed, so cannot be TypeNoBounds"); | |
9981 | add_error (std::move (error)); | |
9982 | ||
9983 | return nullptr; | |
9984 | } | |
9985 | ||
9986 | // should be trait bound, so parse trait bound | |
9987 | std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound (); | |
9988 | if (initial_bound == nullptr) | |
9989 | { | |
9990 | Error error ( | |
9991 | lexer.peek_token ()->get_locus (), | |
9992 | "failed to parse TraitObjectTypeOneBound initial bound"); | |
9993 | add_error (std::move (error)); | |
9994 | ||
9995 | return nullptr; | |
9996 | } | |
9997 | ||
9998 | location_t locus = t->get_locus (); | |
9999 | ||
10000 | // detect error with plus as next token | |
10001 | t = lexer.peek_token (); | |
10002 | if (t->get_id () == PLUS) | |
10003 | { | |
10004 | Error error (t->get_locus (), | |
10005 | "plus after trait bound means a TraitObjectType, " | |
10006 | "which is not allowed as a TypeNoBounds"); | |
10007 | add_error (std::move (error)); | |
10008 | ||
10009 | return nullptr; | |
10010 | } | |
10011 | ||
10012 | // convert trait bound to value object | |
10013 | AST::TraitBound value_bound (*initial_bound); | |
10014 | ||
10015 | return std::unique_ptr<AST::TraitObjectTypeOneBound> ( | |
10016 | new AST::TraitObjectTypeOneBound (std::move (value_bound), locus, | |
10017 | has_dyn)); | |
10018 | } | |
10019 | default: | |
10020 | add_error (Error (t->get_locus (), | |
10021 | "unrecognised token %qs in type no bounds", | |
10022 | t->get_token_description ())); | |
10023 | ||
10024 | return nullptr; | |
10025 | } | |
10026 | } | |
10027 | ||
10028 | // Parses a type no bounds beginning with '('. | |
10029 | template <typename ManagedTokenSource> | |
10030 | std::unique_ptr<AST::TypeNoBounds> | |
10031 | Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds () | |
10032 | { | |
10033 | /* NOTE: this could probably be parsed without the HACK solution of | |
10034 | * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/ | |
10035 | ||
10036 | /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is | |
10037 | * considered a trait bound, not a parenthesised type, so that it can still | |
10038 | * be used in type param bounds. */ | |
10039 | ||
10040 | location_t left_paren_locus = lexer.peek_token ()->get_locus (); | |
10041 | ||
10042 | // skip left delim | |
10043 | lexer.skip_token (); | |
10044 | /* while next token isn't close delim, parse comma-separated types, saving | |
10045 | * whether trailing comma happens */ | |
10046 | const_TokenPtr t = lexer.peek_token (); | |
10047 | bool trailing_comma = true; | |
10048 | std::vector<std::unique_ptr<AST::Type>> types; | |
10049 | ||
10050 | while (t->get_id () != RIGHT_PAREN) | |
10051 | { | |
10052 | std::unique_ptr<AST::Type> type = parse_type (); | |
10053 | if (type == nullptr) | |
10054 | { | |
10055 | Error error (t->get_locus (), | |
10056 | "failed to parse type inside parentheses (probably " | |
10057 | "tuple or parenthesised)"); | |
10058 | add_error (std::move (error)); | |
10059 | ||
10060 | return nullptr; | |
10061 | } | |
10062 | types.push_back (std::move (type)); | |
10063 | ||
10064 | t = lexer.peek_token (); | |
10065 | if (t->get_id () != COMMA) | |
10066 | { | |
10067 | trailing_comma = false; | |
10068 | break; | |
10069 | } | |
10070 | lexer.skip_token (); | |
10071 | ||
10072 | t = lexer.peek_token (); | |
10073 | } | |
10074 | ||
10075 | if (!skip_token (RIGHT_PAREN)) | |
10076 | { | |
10077 | return nullptr; | |
10078 | } | |
10079 | ||
10080 | // if only one type and no trailing comma, then not a tuple type | |
10081 | if (types.size () == 1 && !trailing_comma) | |
10082 | { | |
10083 | // must be a TraitObjectType (with more than one bound) | |
10084 | if (lexer.peek_token ()->get_id () == PLUS) | |
10085 | { | |
10086 | // error - this is not allowed for type no bounds | |
10087 | Error error (lexer.peek_token ()->get_locus (), | |
10088 | "plus (implying TraitObjectType as type param " | |
10089 | "bounds) is not allowed in type no bounds"); | |
10090 | add_error (std::move (error)); | |
10091 | ||
10092 | return nullptr; | |
10093 | } | |
10094 | else | |
10095 | { | |
10096 | // release vector pointer | |
10097 | std::unique_ptr<AST::Type> released_ptr = std::move (types[0]); | |
10098 | /* HACK: attempt to convert to trait bound. if fails, parenthesised | |
10099 | * type */ | |
10100 | std::unique_ptr<AST::TraitBound> converted_bound ( | |
10101 | released_ptr->to_trait_bound (true)); | |
10102 | if (converted_bound == nullptr) | |
10103 | { | |
10104 | // parenthesised type | |
10105 | return std::unique_ptr<AST::ParenthesisedType> ( | |
10106 | new AST::ParenthesisedType (std::move (released_ptr), | |
10107 | left_paren_locus)); | |
10108 | } | |
10109 | else | |
10110 | { | |
10111 | // trait object type (one bound) | |
10112 | ||
10113 | // get value semantics trait bound | |
10114 | AST::TraitBound value_bound (*converted_bound); | |
10115 | ||
10116 | return std::unique_ptr<AST::TraitObjectTypeOneBound> ( | |
10117 | new AST::TraitObjectTypeOneBound (value_bound, | |
10118 | left_paren_locus)); | |
10119 | } | |
10120 | } | |
10121 | } | |
10122 | else | |
10123 | { | |
10124 | return std::unique_ptr<AST::TupleType> ( | |
10125 | new AST::TupleType (std::move (types), left_paren_locus)); | |
10126 | } | |
10127 | /* TODO: ensure that this ensures that dynamic dispatch for traits is not | |
10128 | * lost somehow */ | |
10129 | } | |
10130 | ||
10131 | /* Parses a literal pattern or range pattern. Assumes that literals passed in | |
10132 | * are valid range pattern bounds. Do not pass in paths in expressions, for | |
10133 | * instance. */ | |
10134 | template <typename ManagedTokenSource> | |
10135 | std::unique_ptr<AST::Pattern> | |
10136 | Parser<ManagedTokenSource>::parse_literal_or_range_pattern () | |
10137 | { | |
10138 | const_TokenPtr range_lower = lexer.peek_token (); | |
10139 | AST::Literal::LitType type = AST::Literal::STRING; | |
10140 | bool has_minus = false; | |
10141 | ||
10142 | // get lit type | |
10143 | switch (range_lower->get_id ()) | |
10144 | { | |
10145 | case CHAR_LITERAL: | |
10146 | type = AST::Literal::CHAR; | |
10147 | lexer.skip_token (); | |
10148 | break; | |
10149 | case BYTE_CHAR_LITERAL: | |
10150 | type = AST::Literal::BYTE; | |
10151 | lexer.skip_token (); | |
10152 | break; | |
10153 | case INT_LITERAL: | |
10154 | type = AST::Literal::INT; | |
10155 | lexer.skip_token (); | |
10156 | break; | |
10157 | case FLOAT_LITERAL: | |
10158 | type = AST::Literal::FLOAT; | |
10159 | lexer.skip_token (); | |
10160 | break; | |
10161 | case MINUS: | |
10162 | // branch on next token | |
10163 | range_lower = lexer.peek_token (1); | |
10164 | switch (range_lower->get_id ()) | |
10165 | { | |
10166 | case INT_LITERAL: | |
10167 | type = AST::Literal::INT; | |
10168 | has_minus = true; | |
10169 | lexer.skip_token (1); | |
10170 | break; | |
10171 | case FLOAT_LITERAL: | |
10172 | type = AST::Literal::FLOAT; | |
10173 | has_minus = true; | |
10174 | lexer.skip_token (1); | |
10175 | break; | |
10176 | default: | |
10177 | add_error (Error (range_lower->get_locus (), | |
10178 | "token type %qs cannot be parsed as range pattern " | |
10179 | "bound or literal after minus symbol", | |
10180 | range_lower->get_token_description ())); | |
10181 | ||
10182 | return nullptr; | |
10183 | } | |
10184 | break; | |
10185 | default: | |
10186 | add_error ( | |
10187 | Error (range_lower->get_locus (), | |
10188 | "token type %qs cannot be parsed as range pattern bound", | |
10189 | range_lower->get_token_description ())); | |
10190 | ||
10191 | return nullptr; | |
10192 | } | |
10193 | ||
10194 | const_TokenPtr next = lexer.peek_token (); | |
10195 | if (next->get_id () == DOT_DOT_EQ || next->get_id () == ELLIPSIS | |
10196 | || next->get_id () == DOT_DOT) | |
10197 | { | |
10198 | AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ()); | |
10199 | // range pattern | |
10200 | lexer.skip_token (); | |
10201 | std::unique_ptr<AST::RangePatternBound> lower ( | |
10202 | new AST::RangePatternBoundLiteral ( | |
10203 | AST::Literal (range_lower->get_str (), type, | |
10204 | PrimitiveCoreType::CORETYPE_UNKNOWN), | |
10205 | range_lower->get_locus (), has_minus)); | |
10206 | ||
10207 | std::unique_ptr<AST::RangePatternBound> upper | |
10208 | = parse_range_pattern_bound (); | |
10209 | if (upper == nullptr) | |
10210 | { | |
10211 | Error error (next->get_locus (), | |
10212 | "failed to parse range pattern bound in range pattern"); | |
10213 | add_error (std::move (error)); | |
10214 | ||
10215 | return nullptr; | |
10216 | } | |
10217 | ||
10218 | return std::unique_ptr<AST::RangePattern> ( | |
10219 | new AST::RangePattern (std::move (lower), std::move (upper), kind, | |
10220 | range_lower->get_locus ())); | |
10221 | } | |
10222 | else | |
10223 | { | |
10224 | // literal pattern | |
10225 | return std::unique_ptr<AST::LiteralPattern> ( | |
10226 | new AST::LiteralPattern (range_lower->get_str (), type, | |
10227 | range_lower->get_locus (), | |
10228 | range_lower->get_type_hint ())); | |
10229 | } | |
10230 | } | |
10231 | ||
10232 | // Parses a range pattern bound (value only). | |
10233 | template <typename ManagedTokenSource> | |
10234 | std::unique_ptr<AST::RangePatternBound> | |
10235 | Parser<ManagedTokenSource>::parse_range_pattern_bound () | |
10236 | { | |
10237 | const_TokenPtr range_lower = lexer.peek_token (); | |
10238 | location_t range_lower_locus = range_lower->get_locus (); | |
10239 | ||
10240 | // get lit type | |
10241 | switch (range_lower->get_id ()) | |
10242 | { | |
10243 | case CHAR_LITERAL: | |
10244 | lexer.skip_token (); | |
10245 | return std::unique_ptr<AST::RangePatternBoundLiteral> ( | |
10246 | new AST::RangePatternBoundLiteral ( | |
10247 | AST::Literal (range_lower->get_str (), AST::Literal::CHAR, | |
10248 | range_lower->get_type_hint ()), | |
10249 | range_lower_locus)); | |
10250 | case BYTE_CHAR_LITERAL: | |
10251 | lexer.skip_token (); | |
10252 | return std::unique_ptr<AST::RangePatternBoundLiteral> ( | |
10253 | new AST::RangePatternBoundLiteral ( | |
10254 | AST::Literal (range_lower->get_str (), AST::Literal::BYTE, | |
10255 | range_lower->get_type_hint ()), | |
10256 | range_lower_locus)); | |
10257 | case INT_LITERAL: | |
10258 | lexer.skip_token (); | |
10259 | return std::unique_ptr<AST::RangePatternBoundLiteral> ( | |
10260 | new AST::RangePatternBoundLiteral ( | |
10261 | AST::Literal (range_lower->get_str (), AST::Literal::INT, | |
10262 | range_lower->get_type_hint ()), | |
10263 | range_lower_locus)); | |
10264 | case FLOAT_LITERAL: | |
10265 | lexer.skip_token (); | |
10266 | rust_debug ("warning: used deprecated float range pattern bound"); | |
10267 | return std::unique_ptr<AST::RangePatternBoundLiteral> ( | |
10268 | new AST::RangePatternBoundLiteral ( | |
10269 | AST::Literal (range_lower->get_str (), AST::Literal::FLOAT, | |
10270 | range_lower->get_type_hint ()), | |
10271 | range_lower_locus)); | |
10272 | case MINUS: | |
10273 | // branch on next token | |
10274 | range_lower = lexer.peek_token (1); | |
10275 | switch (range_lower->get_id ()) | |
10276 | { | |
10277 | case INT_LITERAL: | |
10278 | lexer.skip_token (1); | |
10279 | return std::unique_ptr<AST::RangePatternBoundLiteral> ( | |
10280 | new AST::RangePatternBoundLiteral ( | |
10281 | AST::Literal (range_lower->get_str (), AST::Literal::INT, | |
10282 | range_lower->get_type_hint ()), | |
10283 | range_lower_locus, true)); | |
10284 | case FLOAT_LITERAL: | |
10285 | lexer.skip_token (1); | |
10286 | rust_debug ("warning: used deprecated float range pattern bound"); | |
10287 | return std::unique_ptr<AST::RangePatternBoundLiteral> ( | |
10288 | new AST::RangePatternBoundLiteral ( | |
10289 | AST::Literal (range_lower->get_str (), AST::Literal::FLOAT, | |
10290 | range_lower->get_type_hint ()), | |
10291 | range_lower_locus, true)); | |
10292 | default: | |
10293 | add_error (Error (range_lower->get_locus (), | |
10294 | "token type %qs cannot be parsed as range pattern " | |
10295 | "bound after minus symbol", | |
10296 | range_lower->get_token_description ())); | |
10297 | ||
10298 | return nullptr; | |
10299 | } | |
10300 | case IDENTIFIER: | |
10301 | case SUPER: | |
10302 | case SELF: | |
10303 | case SELF_ALIAS: | |
10304 | case CRATE: | |
10305 | case SCOPE_RESOLUTION: | |
10306 | case DOLLAR_SIGN: { | |
10307 | // path in expression | |
10308 | AST::PathInExpression path = parse_path_in_expression (); | |
10309 | if (path.is_error ()) | |
10310 | { | |
10311 | Error error ( | |
10312 | range_lower->get_locus (), | |
10313 | "failed to parse path in expression range pattern bound"); | |
10314 | add_error (std::move (error)); | |
10315 | ||
10316 | return nullptr; | |
10317 | } | |
10318 | return std::unique_ptr<AST::RangePatternBoundPath> ( | |
10319 | new AST::RangePatternBoundPath (std::move (path))); | |
10320 | } | |
10321 | case LEFT_SHIFT: | |
10322 | case LEFT_ANGLE: { | |
10323 | // qualified path in expression | |
10324 | AST::QualifiedPathInExpression path | |
10325 | = parse_qualified_path_in_expression (); | |
10326 | if (path.is_error ()) | |
10327 | { | |
10328 | Error error (range_lower->get_locus (), | |
10329 | "failed to parse qualified path in expression range " | |
10330 | "pattern bound"); | |
10331 | add_error (std::move (error)); | |
10332 | ||
10333 | return nullptr; | |
10334 | } | |
10335 | return std::unique_ptr<AST::RangePatternBoundQualPath> ( | |
10336 | new AST::RangePatternBoundQualPath (std::move (path))); | |
10337 | } | |
10338 | default: | |
10339 | add_error ( | |
10340 | Error (range_lower->get_locus (), | |
10341 | "token type %qs cannot be parsed as range pattern bound", | |
10342 | range_lower->get_token_description ())); | |
10343 | ||
10344 | return nullptr; | |
10345 | } | |
10346 | } | |
10347 | ||
10348 | template <typename ManagedTokenSource> | |
10349 | std::unique_ptr<AST::Pattern> | |
10350 | Parser<ManagedTokenSource>::parse_pattern () | |
10351 | { | |
10352 | location_t start_locus = lexer.peek_token ()->get_locus (); | |
10353 | ||
10354 | /* skip optional starting pipe */ | |
10355 | maybe_skip_token (PIPE); | |
10356 | ||
10357 | auto first = parse_pattern_no_alt (); | |
10358 | ||
10359 | if (lexer.peek_token ()->get_id () != PIPE) | |
10360 | /* no alternates */ | |
10361 | return first; | |
10362 | ||
10363 | std::vector<std::unique_ptr<AST::Pattern>> alts; | |
10364 | alts.push_back (std::move (first)); | |
10365 | ||
10366 | do | |
10367 | { | |
10368 | lexer.skip_token (); | |
10369 | alts.push_back (parse_pattern_no_alt ()); | |
10370 | } | |
10371 | ||
10372 | while (lexer.peek_token ()->get_id () == PIPE); | |
10373 | ||
10374 | /* alternates */ | |
10375 | return std::unique_ptr<AST::Pattern> ( | |
10376 | new AST::AltPattern (std::move (alts), start_locus)); | |
10377 | } | |
10378 | ||
10379 | // Parses a pattern without alternates ('|') | |
10380 | // (will further disambiguate any pattern). | |
10381 | template <typename ManagedTokenSource> | |
10382 | std::unique_ptr<AST::Pattern> | |
10383 | Parser<ManagedTokenSource>::parse_pattern_no_alt () | |
10384 | { | |
10385 | const_TokenPtr t = lexer.peek_token (); | |
10386 | switch (t->get_id ()) | |
10387 | { | |
10388 | case TRUE_LITERAL: | |
10389 | lexer.skip_token (); | |
10390 | return std::unique_ptr<AST::LiteralPattern> ( | |
10391 | new AST::LiteralPattern (Values::Keywords::TRUE_LITERAL, | |
10392 | AST::Literal::BOOL, t->get_locus (), | |
10393 | t->get_type_hint ())); | |
10394 | case FALSE_LITERAL: | |
10395 | lexer.skip_token (); | |
10396 | return std::unique_ptr<AST::LiteralPattern> ( | |
10397 | new AST::LiteralPattern (Values::Keywords::FALSE_LITERAL, | |
10398 | AST::Literal::BOOL, t->get_locus (), | |
10399 | t->get_type_hint ())); | |
10400 | case CHAR_LITERAL: | |
10401 | case BYTE_CHAR_LITERAL: | |
10402 | case INT_LITERAL: | |
10403 | case FLOAT_LITERAL: | |
10404 | return parse_literal_or_range_pattern (); | |
10405 | case STRING_LITERAL: | |
10406 | lexer.skip_token (); | |
10407 | return std::unique_ptr<AST::LiteralPattern> ( | |
10408 | new AST::LiteralPattern (t->get_str (), AST::Literal::STRING, | |
10409 | t->get_locus (), t->get_type_hint ())); | |
10410 | case BYTE_STRING_LITERAL: | |
10411 | lexer.skip_token (); | |
10412 | return std::unique_ptr<AST::LiteralPattern> ( | |
10413 | new AST::LiteralPattern (t->get_str (), AST::Literal::BYTE_STRING, | |
10414 | t->get_locus (), t->get_type_hint ())); | |
10415 | case RAW_STRING_LITERAL: | |
10416 | lexer.skip_token (); | |
10417 | return std::unique_ptr<AST::LiteralPattern> ( | |
10418 | new AST::LiteralPattern (t->get_str (), AST::Literal::RAW_STRING, | |
10419 | t->get_locus (), t->get_type_hint ())); | |
10420 | // raw string and raw byte string literals too if they are readded to | |
10421 | // lexer | |
10422 | case MINUS: | |
10423 | if (lexer.peek_token (1)->get_id () == INT_LITERAL) | |
10424 | { | |
10425 | return parse_literal_or_range_pattern (); | |
10426 | } | |
10427 | else if (lexer.peek_token (1)->get_id () == FLOAT_LITERAL) | |
10428 | { | |
10429 | return parse_literal_or_range_pattern (); | |
10430 | } | |
10431 | else | |
10432 | { | |
10433 | Error error (t->get_locus (), "unexpected token %<-%> in pattern - " | |
10434 | "did you forget an integer literal"); | |
10435 | add_error (std::move (error)); | |
10436 | ||
10437 | return nullptr; | |
10438 | } | |
10439 | case UNDERSCORE: | |
10440 | lexer.skip_token (); | |
10441 | return std::unique_ptr<AST::WildcardPattern> ( | |
10442 | new AST::WildcardPattern (t->get_locus ())); | |
10443 | case DOT_DOT: | |
10444 | lexer.skip_token (); | |
10445 | return std::unique_ptr<AST::RestPattern> ( | |
10446 | new AST::RestPattern (t->get_locus ())); | |
10447 | case REF: | |
10448 | case MUT: | |
10449 | return parse_identifier_pattern (); | |
10450 | case IDENTIFIER: | |
10451 | /* if identifier with no scope resolution afterwards, identifier | |
10452 | * pattern. if scope resolution afterwards, path pattern (or range | |
10453 | * pattern or struct pattern or tuple struct pattern) or macro | |
10454 | * invocation */ | |
10455 | return parse_ident_leading_pattern (); | |
10456 | case AMP: | |
10457 | case LOGICAL_AND: | |
10458 | // reference pattern | |
10459 | return parse_reference_pattern (); | |
10460 | case LEFT_PAREN: | |
10461 | // tuple pattern or grouped pattern | |
10462 | return parse_grouped_or_tuple_pattern (); | |
10463 | case LEFT_SQUARE: | |
10464 | // slice pattern | |
10465 | return parse_slice_pattern (); | |
10466 | case LEFT_SHIFT: | |
10467 | case LEFT_ANGLE: { | |
10468 | // qualified path in expression or qualified range pattern bound | |
10469 | AST::QualifiedPathInExpression path | |
10470 | = parse_qualified_path_in_expression (); | |
10471 | ||
10472 | if (lexer.peek_token ()->get_id () == DOT_DOT_EQ | |
10473 | || lexer.peek_token ()->get_id () == ELLIPSIS | |
10474 | || lexer.peek_token ()->get_id () == DOT_DOT) | |
10475 | { | |
10476 | // qualified range pattern bound, so parse rest of range pattern | |
10477 | AST::RangeKind kind | |
10478 | = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ()); | |
10479 | lexer.skip_token (); | |
10480 | ||
10481 | std::unique_ptr<AST::RangePatternBoundQualPath> lower_bound ( | |
10482 | new AST::RangePatternBoundQualPath (std::move (path))); | |
10483 | std::unique_ptr<AST::RangePatternBound> upper_bound | |
10484 | = parse_range_pattern_bound (); | |
10485 | ||
10486 | return std::unique_ptr<AST::RangePattern> ( | |
10487 | new AST::RangePattern (std::move (lower_bound), | |
10488 | std::move (upper_bound), kind, | |
10489 | t->get_locus ())); | |
10490 | } | |
10491 | else | |
10492 | { | |
10493 | // just qualified path in expression | |
10494 | return std::unique_ptr<AST::QualifiedPathInExpression> ( | |
10495 | new AST::QualifiedPathInExpression (std::move (path))); | |
10496 | } | |
10497 | } | |
10498 | case SUPER: | |
10499 | case SELF: | |
10500 | case SELF_ALIAS: | |
10501 | case CRATE: | |
10502 | case SCOPE_RESOLUTION: | |
10503 | case DOLLAR_SIGN: { | |
10504 | // path in expression or range pattern bound | |
10505 | AST::PathInExpression path = parse_path_in_expression (); | |
10506 | ||
10507 | const_TokenPtr next = lexer.peek_token (); | |
10508 | switch (next->get_id ()) | |
10509 | { | |
10510 | case DOT_DOT_EQ: | |
10511 | case DOT_DOT: | |
10512 | case ELLIPSIS: { | |
10513 | // qualified range pattern bound, so parse rest of range pattern | |
10514 | AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ()); | |
10515 | lexer.skip_token (); | |
10516 | ||
10517 | std::unique_ptr<AST::RangePatternBoundPath> lower_bound ( | |
10518 | new AST::RangePatternBoundPath (std::move (path))); | |
10519 | std::unique_ptr<AST::RangePatternBound> upper_bound | |
10520 | = parse_range_pattern_bound (); | |
10521 | ||
10522 | return std::unique_ptr<AST::RangePattern> ( | |
10523 | new AST::RangePattern (std::move (lower_bound), | |
10524 | std::move (upper_bound), kind, | |
10525 | next->get_locus ())); | |
10526 | } | |
10527 | case EXCLAM: | |
10528 | return parse_macro_invocation_partial (std::move (path), | |
10529 | AST::AttrVec ()); | |
10530 | case LEFT_PAREN: { | |
10531 | // tuple struct | |
10532 | lexer.skip_token (); | |
10533 | ||
10534 | // parse items | |
10535 | std::unique_ptr<AST::TupleStructItems> items | |
10536 | = parse_tuple_struct_items (); | |
10537 | if (items == nullptr) | |
10538 | { | |
10539 | Error error (lexer.peek_token ()->get_locus (), | |
10540 | "failed to parse tuple struct items"); | |
10541 | add_error (std::move (error)); | |
10542 | ||
10543 | return nullptr; | |
10544 | } | |
10545 | ||
10546 | if (!skip_token (RIGHT_PAREN)) | |
10547 | { | |
10548 | return nullptr; | |
10549 | } | |
10550 | ||
10551 | return std::unique_ptr<AST::TupleStructPattern> ( | |
10552 | new AST::TupleStructPattern (std::move (path), | |
10553 | std::move (items))); | |
10554 | } | |
10555 | case LEFT_CURLY: { | |
10556 | // struct | |
10557 | lexer.skip_token (); | |
10558 | ||
10559 | // parse elements (optional) | |
10560 | AST::StructPatternElements elems = parse_struct_pattern_elems (); | |
10561 | ||
10562 | if (!skip_token (RIGHT_CURLY)) | |
10563 | { | |
10564 | return nullptr; | |
10565 | } | |
10566 | ||
10567 | return std::unique_ptr<AST::StructPattern> ( | |
10568 | new AST::StructPattern (std::move (path), t->get_locus (), | |
10569 | std::move (elems))); | |
10570 | } | |
10571 | default: | |
10572 | // assume path in expression | |
10573 | return std::unique_ptr<AST::PathInExpression> ( | |
10574 | new AST::PathInExpression (std::move (path))); | |
10575 | } | |
10576 | } | |
10577 | default: | |
10578 | add_error (Error (t->get_locus (), "unexpected token %qs in pattern", | |
10579 | t->get_token_description ())); | |
10580 | ||
10581 | return nullptr; | |
10582 | } | |
10583 | } | |
10584 | ||
10585 | // Parses a single or double reference pattern. | |
10586 | template <typename ManagedTokenSource> | |
10587 | std::unique_ptr<AST::ReferencePattern> | |
10588 | Parser<ManagedTokenSource>::parse_reference_pattern () | |
10589 | { | |
10590 | // parse double or single ref | |
10591 | bool is_double_ref = false; | |
10592 | const_TokenPtr t = lexer.peek_token (); | |
10593 | switch (t->get_id ()) | |
10594 | { | |
10595 | case AMP: | |
10596 | // still false | |
10597 | lexer.skip_token (); | |
10598 | break; | |
10599 | case LOGICAL_AND: | |
10600 | is_double_ref = true; | |
10601 | lexer.skip_token (); | |
10602 | break; | |
10603 | default: | |
10604 | add_error (Error (t->get_locus (), | |
10605 | "unexpected token %qs in reference pattern", | |
10606 | t->get_token_description ())); | |
10607 | ||
10608 | return nullptr; | |
10609 | } | |
10610 | ||
10611 | // parse mut (if it exists) | |
10612 | bool is_mut = false; | |
10613 | if (lexer.peek_token ()->get_id () == MUT) | |
10614 | { | |
10615 | is_mut = true; | |
10616 | lexer.skip_token (); | |
10617 | } | |
10618 | ||
10619 | // parse pattern to get reference of (required) | |
10620 | std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt (); | |
10621 | if (pattern == nullptr) | |
10622 | { | |
10623 | Error error (lexer.peek_token ()->get_locus (), | |
10624 | "failed to parse pattern in reference pattern"); | |
10625 | add_error (std::move (error)); | |
10626 | ||
10627 | // skip somewhere? | |
10628 | return nullptr; | |
10629 | } | |
10630 | ||
10631 | return std::unique_ptr<AST::ReferencePattern> ( | |
10632 | new AST::ReferencePattern (std::move (pattern), is_mut, is_double_ref, | |
10633 | t->get_locus ())); | |
10634 | } | |
10635 | ||
10636 | /* Parses a grouped pattern or tuple pattern. Prefers grouped over tuple if | |
10637 | * only a single element with no commas. */ | |
10638 | template <typename ManagedTokenSource> | |
10639 | std::unique_ptr<AST::Pattern> | |
10640 | Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern () | |
10641 | { | |
10642 | location_t paren_locus = lexer.peek_token ()->get_locus (); | |
10643 | skip_token (LEFT_PAREN); | |
10644 | ||
10645 | // detect '..' token (ranged with no lower range) | |
10646 | if (lexer.peek_token ()->get_id () == DOT_DOT) | |
10647 | { | |
10648 | lexer.skip_token (); | |
10649 | ||
10650 | // parse new patterns while next token is a comma | |
10651 | std::vector<std::unique_ptr<AST::Pattern>> patterns; | |
10652 | ||
10653 | const_TokenPtr t = lexer.peek_token (); | |
10654 | while (t->get_id () == COMMA) | |
10655 | { | |
10656 | lexer.skip_token (); | |
10657 | ||
10658 | // break if next token is ')' | |
10659 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
10660 | { | |
10661 | break; | |
10662 | } | |
10663 | ||
10664 | // parse pattern, which is required | |
10665 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
10666 | if (pattern == nullptr) | |
10667 | { | |
10668 | Error error ( | |
10669 | lexer.peek_token ()->get_locus (), | |
10670 | "failed to parse pattern inside ranged tuple pattern"); | |
10671 | add_error (std::move (error)); | |
10672 | ||
10673 | // skip somewhere? | |
10674 | return nullptr; | |
10675 | } | |
10676 | patterns.push_back (std::move (pattern)); | |
10677 | ||
10678 | t = lexer.peek_token (); | |
10679 | } | |
10680 | ||
10681 | if (!skip_token (RIGHT_PAREN)) | |
10682 | { | |
10683 | // skip somewhere? | |
10684 | return nullptr; | |
10685 | } | |
10686 | ||
10687 | // create ranged tuple pattern items with only upper items | |
10688 | std::unique_ptr<AST::TuplePatternItemsRanged> items ( | |
10689 | new AST::TuplePatternItemsRanged ( | |
10690 | std::vector<std::unique_ptr<AST::Pattern>> (), std::move (patterns))); | |
10691 | return std::unique_ptr<AST::TuplePattern> ( | |
10692 | new AST::TuplePattern (std::move (items), paren_locus)); | |
10693 | } | |
10694 | else if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
10695 | { | |
10696 | skip_token (RIGHT_PAREN); | |
10697 | auto items = std::unique_ptr<AST::TuplePatternItemsMultiple> ( | |
10698 | new AST::TuplePatternItemsMultiple ( | |
10699 | std::vector<std::unique_ptr<AST::Pattern>> ())); | |
10700 | return std::unique_ptr<AST::TuplePattern> ( | |
10701 | new AST::TuplePattern (std::move (items), paren_locus)); | |
10702 | } | |
10703 | ||
10704 | // parse initial pattern (required) | |
10705 | std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern (); | |
10706 | if (initial_pattern == nullptr) | |
10707 | { | |
10708 | Error error (lexer.peek_token ()->get_locus (), | |
10709 | "failed to parse pattern in grouped or tuple pattern"); | |
10710 | add_error (std::move (error)); | |
10711 | ||
10712 | return nullptr; | |
10713 | } | |
10714 | ||
10715 | // branch on whether next token is a comma or not | |
10716 | const_TokenPtr t = lexer.peek_token (); | |
10717 | switch (t->get_id ()) | |
10718 | { | |
10719 | case RIGHT_PAREN: | |
10720 | // grouped pattern | |
10721 | lexer.skip_token (); | |
10722 | ||
10723 | return std::unique_ptr<AST::GroupedPattern> ( | |
10724 | new AST::GroupedPattern (std::move (initial_pattern), paren_locus)); | |
10725 | case COMMA: { | |
10726 | // tuple pattern | |
10727 | lexer.skip_token (); | |
10728 | ||
10729 | // create vector of patterns | |
10730 | std::vector<std::unique_ptr<AST::Pattern>> patterns; | |
10731 | patterns.push_back (std::move (initial_pattern)); | |
10732 | ||
10733 | t = lexer.peek_token (); | |
10734 | while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT) | |
10735 | { | |
10736 | // parse pattern (required) | |
10737 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
10738 | if (pattern == nullptr) | |
10739 | { | |
10740 | Error error (t->get_locus (), | |
10741 | "failed to parse pattern in tuple pattern"); | |
10742 | add_error (std::move (error)); | |
10743 | ||
10744 | return nullptr; | |
10745 | } | |
10746 | patterns.push_back (std::move (pattern)); | |
10747 | ||
10748 | if (lexer.peek_token ()->get_id () != COMMA) | |
10749 | break; | |
10750 | ||
10751 | lexer.skip_token (); | |
10752 | t = lexer.peek_token (); | |
10753 | } | |
10754 | ||
10755 | t = lexer.peek_token (); | |
10756 | if (t->get_id () == RIGHT_PAREN) | |
10757 | { | |
10758 | // non-ranged tuple pattern | |
10759 | lexer.skip_token (); | |
10760 | ||
10761 | std::unique_ptr<AST::TuplePatternItemsMultiple> items ( | |
10762 | new AST::TuplePatternItemsMultiple (std::move (patterns))); | |
10763 | return std::unique_ptr<AST::TuplePattern> ( | |
10764 | new AST::TuplePattern (std::move (items), paren_locus)); | |
10765 | } | |
10766 | else if (t->get_id () == DOT_DOT) | |
10767 | { | |
10768 | // ranged tuple pattern | |
10769 | lexer.skip_token (); | |
10770 | ||
10771 | // parse upper patterns | |
10772 | std::vector<std::unique_ptr<AST::Pattern>> upper_patterns; | |
10773 | t = lexer.peek_token (); | |
10774 | while (t->get_id () == COMMA) | |
10775 | { | |
10776 | lexer.skip_token (); | |
10777 | ||
10778 | // break if end | |
10779 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
10780 | break; | |
10781 | ||
10782 | // parse pattern (required) | |
10783 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
10784 | if (pattern == nullptr) | |
10785 | { | |
10786 | Error error (lexer.peek_token ()->get_locus (), | |
10787 | "failed to parse pattern in tuple pattern"); | |
10788 | add_error (std::move (error)); | |
10789 | ||
10790 | return nullptr; | |
10791 | } | |
10792 | upper_patterns.push_back (std::move (pattern)); | |
10793 | ||
10794 | t = lexer.peek_token (); | |
10795 | } | |
10796 | ||
10797 | if (!skip_token (RIGHT_PAREN)) | |
10798 | { | |
10799 | return nullptr; | |
10800 | } | |
10801 | ||
10802 | std::unique_ptr<AST::TuplePatternItemsRanged> items ( | |
10803 | new AST::TuplePatternItemsRanged (std::move (patterns), | |
10804 | std::move (upper_patterns))); | |
10805 | return std::unique_ptr<AST::TuplePattern> ( | |
10806 | new AST::TuplePattern (std::move (items), paren_locus)); | |
10807 | } | |
10808 | else | |
10809 | { | |
10810 | // some kind of error | |
10811 | Error error (t->get_locus (), | |
10812 | "failed to parse tuple pattern (probably) or maybe " | |
10813 | "grouped pattern"); | |
10814 | add_error (std::move (error)); | |
10815 | ||
10816 | return nullptr; | |
10817 | } | |
10818 | } | |
10819 | default: | |
10820 | // error | |
10821 | add_error (Error (t->get_locus (), | |
10822 | "unrecognised token %qs in grouped or tuple pattern " | |
10823 | "after first pattern", | |
10824 | t->get_token_description ())); | |
10825 | ||
10826 | return nullptr; | |
10827 | } | |
10828 | } | |
10829 | ||
10830 | /* Parses a slice pattern that can match arrays or slices. Parses the square | |
10831 | * brackets too. */ | |
10832 | template <typename ManagedTokenSource> | |
10833 | std::unique_ptr<AST::SlicePattern> | |
10834 | Parser<ManagedTokenSource>::parse_slice_pattern () | |
10835 | { | |
10836 | location_t square_locus = lexer.peek_token ()->get_locus (); | |
10837 | std::vector<std::unique_ptr<AST::Pattern>> patterns; | |
10838 | skip_token (LEFT_SQUARE); | |
10839 | ||
10840 | if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) | |
10841 | { | |
10842 | skip_token (RIGHT_SQUARE); | |
10843 | return std::unique_ptr<AST::SlicePattern> ( | |
10844 | new AST::SlicePattern (std::move (patterns), square_locus)); | |
10845 | } | |
10846 | ||
10847 | // parse initial pattern (required) | |
10848 | std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern (); | |
10849 | if (initial_pattern == nullptr) | |
10850 | { | |
10851 | Error error (lexer.peek_token ()->get_locus (), | |
10852 | "failed to parse initial pattern in slice pattern"); | |
10853 | add_error (std::move (error)); | |
10854 | ||
10855 | return nullptr; | |
10856 | } | |
10857 | ||
10858 | patterns.push_back (std::move (initial_pattern)); | |
10859 | ||
10860 | const_TokenPtr t = lexer.peek_token (); | |
10861 | while (t->get_id () == COMMA) | |
10862 | { | |
10863 | lexer.skip_token (); | |
10864 | ||
10865 | // break if end bracket | |
10866 | if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) | |
10867 | break; | |
10868 | ||
10869 | // parse pattern (required) | |
10870 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
10871 | if (pattern == nullptr) | |
10872 | { | |
10873 | Error error (lexer.peek_token ()->get_locus (), | |
10874 | "failed to parse pattern in slice pattern"); | |
10875 | add_error (std::move (error)); | |
10876 | ||
10877 | return nullptr; | |
10878 | } | |
10879 | patterns.push_back (std::move (pattern)); | |
10880 | ||
10881 | t = lexer.peek_token (); | |
10882 | } | |
10883 | ||
10884 | if (!skip_token (RIGHT_SQUARE)) | |
10885 | { | |
10886 | return nullptr; | |
10887 | } | |
10888 | ||
10889 | return std::unique_ptr<AST::SlicePattern> ( | |
10890 | new AST::SlicePattern (std::move (patterns), square_locus)); | |
10891 | } | |
10892 | ||
10893 | /* Parses an identifier pattern (pattern that binds a value matched to a | |
10894 | * variable). */ | |
10895 | template <typename ManagedTokenSource> | |
10896 | std::unique_ptr<AST::IdentifierPattern> | |
10897 | Parser<ManagedTokenSource>::parse_identifier_pattern () | |
10898 | { | |
10899 | location_t locus = lexer.peek_token ()->get_locus (); | |
10900 | ||
10901 | bool has_ref = false; | |
10902 | if (lexer.peek_token ()->get_id () == REF) | |
10903 | { | |
10904 | has_ref = true; | |
10905 | lexer.skip_token (); | |
10906 | ||
10907 | // DEBUG | |
10908 | rust_debug ("parsed ref in identifier pattern"); | |
10909 | } | |
10910 | ||
10911 | bool has_mut = false; | |
10912 | if (lexer.peek_token ()->get_id () == MUT) | |
10913 | { | |
10914 | has_mut = true; | |
10915 | lexer.skip_token (); | |
10916 | } | |
10917 | ||
10918 | // parse identifier (required) | |
10919 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
10920 | if (ident_tok == nullptr) | |
10921 | { | |
10922 | // skip somewhere? | |
10923 | return nullptr; | |
10924 | } | |
10925 | Identifier ident{ident_tok}; | |
10926 | ||
10927 | // DEBUG | |
10928 | rust_debug ("parsed identifier in identifier pattern"); | |
10929 | ||
10930 | // parse optional pattern binding thing | |
10931 | std::unique_ptr<AST::Pattern> bind_pattern = nullptr; | |
10932 | if (lexer.peek_token ()->get_id () == PATTERN_BIND) | |
10933 | { | |
10934 | lexer.skip_token (); | |
10935 | ||
10936 | // parse required pattern to bind | |
10937 | bind_pattern = parse_pattern (); | |
10938 | if (bind_pattern == nullptr) | |
10939 | { | |
10940 | Error error (lexer.peek_token ()->get_locus (), | |
10941 | "failed to parse pattern to bind in identifier pattern"); | |
10942 | add_error (std::move (error)); | |
10943 | ||
10944 | return nullptr; | |
10945 | } | |
10946 | } | |
10947 | ||
10948 | // DEBUG | |
10949 | rust_debug ("about to return identifier pattern"); | |
10950 | ||
10951 | return std::unique_ptr<AST::IdentifierPattern> ( | |
10952 | new AST::IdentifierPattern (std::move (ident), locus, has_ref, has_mut, | |
10953 | std::move (bind_pattern))); | |
10954 | } | |
10955 | ||
10956 | /* Parses a pattern that opens with an identifier. This includes identifier | |
10957 | * patterns, path patterns (and derivatives such as struct patterns, tuple | |
10958 | * struct patterns, and macro invocations), and ranges. */ | |
10959 | template <typename ManagedTokenSource> | |
10960 | std::unique_ptr<AST::Pattern> | |
10961 | Parser<ManagedTokenSource>::parse_ident_leading_pattern () | |
10962 | { | |
10963 | // ensure first token is actually identifier | |
10964 | const_TokenPtr initial_tok = lexer.peek_token (); | |
10965 | if (initial_tok->get_id () != IDENTIFIER) | |
10966 | { | |
10967 | return nullptr; | |
10968 | } | |
10969 | ||
10970 | // save initial identifier as it may be useful (but don't skip) | |
10971 | std::string initial_ident = initial_tok->get_str (); | |
10972 | ||
10973 | // parse next tokens as a PathInExpression | |
10974 | AST::PathInExpression path = parse_path_in_expression (); | |
10975 | ||
10976 | // branch on next token | |
10977 | const_TokenPtr t = lexer.peek_token (); | |
10978 | switch (t->get_id ()) | |
10979 | { | |
10980 | case EXCLAM: | |
10981 | return parse_macro_invocation_partial (std::move (path), AST::AttrVec ()); | |
10982 | case LEFT_PAREN: { | |
10983 | // tuple struct | |
10984 | lexer.skip_token (); | |
10985 | ||
10986 | // DEBUG | |
10987 | rust_debug ("parsing tuple struct pattern"); | |
10988 | ||
10989 | // parse items | |
10990 | std::unique_ptr<AST::TupleStructItems> items | |
10991 | = parse_tuple_struct_items (); | |
10992 | if (items == nullptr) | |
10993 | { | |
10994 | Error error (lexer.peek_token ()->get_locus (), | |
10995 | "failed to parse tuple struct items"); | |
10996 | add_error (std::move (error)); | |
10997 | ||
10998 | return nullptr; | |
10999 | } | |
11000 | ||
11001 | // DEBUG | |
11002 | rust_debug ("successfully parsed tuple struct items"); | |
11003 | ||
11004 | if (!skip_token (RIGHT_PAREN)) | |
11005 | { | |
11006 | return nullptr; | |
11007 | } | |
11008 | ||
11009 | // DEBUG | |
11010 | rust_debug ("successfully parsed tuple struct pattern"); | |
11011 | ||
11012 | return std::unique_ptr<AST::TupleStructPattern> ( | |
11013 | new AST::TupleStructPattern (std::move (path), std::move (items))); | |
11014 | } | |
11015 | case LEFT_CURLY: { | |
11016 | // struct | |
11017 | lexer.skip_token (); | |
11018 | ||
11019 | // parse elements (optional) | |
11020 | AST::StructPatternElements elems = parse_struct_pattern_elems (); | |
11021 | ||
11022 | if (!skip_token (RIGHT_CURLY)) | |
11023 | { | |
11024 | return nullptr; | |
11025 | } | |
11026 | ||
11027 | // DEBUG | |
11028 | rust_debug ("successfully parsed struct pattern"); | |
11029 | ||
11030 | return std::unique_ptr<AST::StructPattern> ( | |
11031 | new AST::StructPattern (std::move (path), initial_tok->get_locus (), | |
11032 | std::move (elems))); | |
11033 | } | |
11034 | case DOT_DOT_EQ: | |
11035 | case DOT_DOT: | |
11036 | case ELLIPSIS: { | |
11037 | // range | |
11038 | AST::RangeKind kind | |
11039 | = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ()); | |
11040 | ||
11041 | lexer.skip_token (); | |
11042 | ||
11043 | std::unique_ptr<AST::RangePatternBoundPath> lower_bound ( | |
11044 | new AST::RangePatternBoundPath (std::move (path))); | |
11045 | std::unique_ptr<AST::RangePatternBound> upper_bound | |
11046 | = parse_range_pattern_bound (); | |
11047 | ||
11048 | return std::unique_ptr<AST::RangePattern> ( | |
11049 | new AST::RangePattern (std::move (lower_bound), | |
11050 | std::move (upper_bound), kind, | |
11051 | t->get_locus ())); | |
11052 | } | |
11053 | case PATTERN_BIND: { | |
11054 | // only allow on single-segment paths | |
11055 | if (path.is_single_segment ()) | |
11056 | { | |
11057 | // identifier with pattern bind | |
11058 | lexer.skip_token (); | |
11059 | ||
11060 | std::unique_ptr<AST::Pattern> bind_pattern = parse_pattern (); | |
11061 | if (bind_pattern == nullptr) | |
11062 | { | |
11063 | Error error ( | |
11064 | t->get_locus (), | |
11065 | "failed to parse pattern to bind to identifier pattern"); | |
11066 | add_error (std::move (error)); | |
11067 | ||
11068 | return nullptr; | |
11069 | } | |
11070 | return std::unique_ptr<AST::IdentifierPattern> ( | |
11071 | new AST::IdentifierPattern (std::move (initial_ident), | |
11072 | initial_tok->get_locus (), false, | |
11073 | false, std::move (bind_pattern))); | |
11074 | } | |
11075 | Error error ( | |
11076 | t->get_locus (), | |
11077 | "failed to parse pattern bind to a path, not an identifier"); | |
11078 | add_error (std::move (error)); | |
11079 | ||
11080 | return nullptr; | |
11081 | } | |
11082 | default: | |
11083 | // assume identifier if single segment | |
11084 | if (path.is_single_segment ()) | |
11085 | { | |
11086 | return std::unique_ptr<AST::IdentifierPattern> ( | |
11087 | new AST::IdentifierPattern (std::move (initial_ident), | |
11088 | initial_tok->get_locus ())); | |
11089 | } | |
11090 | // return path otherwise | |
11091 | return std::unique_ptr<AST::PathInExpression> ( | |
11092 | new AST::PathInExpression (std::move (path))); | |
11093 | } | |
11094 | } | |
11095 | ||
11096 | // Parses tuple struct items if they exist. Does not parse parentheses. | |
11097 | template <typename ManagedTokenSource> | |
11098 | std::unique_ptr<AST::TupleStructItems> | |
11099 | Parser<ManagedTokenSource>::parse_tuple_struct_items () | |
11100 | { | |
11101 | std::vector<std::unique_ptr<AST::Pattern>> lower_patterns; | |
11102 | ||
11103 | // DEBUG | |
11104 | rust_debug ("started parsing tuple struct items"); | |
11105 | ||
11106 | // check for '..' at front | |
11107 | if (lexer.peek_token ()->get_id () == DOT_DOT) | |
11108 | { | |
11109 | // only parse upper patterns | |
11110 | lexer.skip_token (); | |
11111 | ||
11112 | // DEBUG | |
11113 | rust_debug ("'..' at front in tuple struct items detected"); | |
11114 | ||
11115 | std::vector<std::unique_ptr<AST::Pattern>> upper_patterns; | |
11116 | ||
11117 | const_TokenPtr t = lexer.peek_token (); | |
11118 | while (t->get_id () == COMMA) | |
11119 | { | |
11120 | lexer.skip_token (); | |
11121 | ||
11122 | // break if right paren | |
11123 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
11124 | break; | |
11125 | ||
11126 | // parse pattern, which is now required | |
11127 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
11128 | if (pattern == nullptr) | |
11129 | { | |
11130 | Error error (lexer.peek_token ()->get_locus (), | |
11131 | "failed to parse pattern in tuple struct items"); | |
11132 | add_error (std::move (error)); | |
11133 | ||
11134 | return nullptr; | |
11135 | } | |
11136 | upper_patterns.push_back (std::move (pattern)); | |
11137 | ||
11138 | t = lexer.peek_token (); | |
11139 | } | |
11140 | ||
11141 | // DEBUG | |
11142 | rust_debug ( | |
11143 | "finished parsing tuple struct items ranged (upper/none only)"); | |
11144 | ||
11145 | return std::unique_ptr<AST::TupleStructItemsRange> ( | |
11146 | new AST::TupleStructItemsRange (std::move (lower_patterns), | |
11147 | std::move (upper_patterns))); | |
11148 | } | |
11149 | ||
11150 | // has at least some lower patterns | |
11151 | const_TokenPtr t = lexer.peek_token (); | |
11152 | while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT) | |
11153 | { | |
11154 | // DEBUG | |
11155 | rust_debug ("about to parse pattern in tuple struct items"); | |
11156 | ||
11157 | // parse pattern, which is required | |
11158 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
11159 | if (pattern == nullptr) | |
11160 | { | |
11161 | Error error (t->get_locus (), | |
11162 | "failed to parse pattern in tuple struct items"); | |
11163 | add_error (std::move (error)); | |
11164 | ||
11165 | return nullptr; | |
11166 | } | |
11167 | lower_patterns.push_back (std::move (pattern)); | |
11168 | ||
11169 | // DEBUG | |
11170 | rust_debug ("successfully parsed pattern in tuple struct items"); | |
11171 | ||
11172 | if (lexer.peek_token ()->get_id () != COMMA) | |
11173 | { | |
11174 | // DEBUG | |
11175 | rust_debug ("broke out of parsing patterns in tuple struct " | |
11176 | "items as no comma"); | |
11177 | ||
11178 | break; | |
11179 | } | |
11180 | lexer.skip_token (); | |
11181 | t = lexer.peek_token (); | |
11182 | } | |
11183 | ||
11184 | // branch on next token | |
11185 | t = lexer.peek_token (); | |
11186 | switch (t->get_id ()) | |
11187 | { | |
11188 | case RIGHT_PAREN: | |
11189 | return std::unique_ptr<AST::TupleStructItemsNoRange> ( | |
11190 | new AST::TupleStructItemsNoRange (std::move (lower_patterns))); | |
11191 | case DOT_DOT: { | |
11192 | // has an upper range that must be parsed separately | |
11193 | lexer.skip_token (); | |
11194 | ||
11195 | std::vector<std::unique_ptr<AST::Pattern>> upper_patterns; | |
11196 | ||
11197 | t = lexer.peek_token (); | |
11198 | while (t->get_id () == COMMA) | |
11199 | { | |
11200 | lexer.skip_token (); | |
11201 | ||
11202 | // break if next token is right paren | |
11203 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
11204 | break; | |
11205 | ||
11206 | // parse pattern, which is required | |
11207 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
11208 | if (pattern == nullptr) | |
11209 | { | |
11210 | Error error (lexer.peek_token ()->get_locus (), | |
11211 | "failed to parse pattern in tuple struct items"); | |
11212 | add_error (std::move (error)); | |
11213 | ||
11214 | return nullptr; | |
11215 | } | |
11216 | upper_patterns.push_back (std::move (pattern)); | |
11217 | ||
11218 | t = lexer.peek_token (); | |
11219 | } | |
11220 | ||
11221 | return std::unique_ptr<AST::TupleStructItemsRange> ( | |
11222 | new AST::TupleStructItemsRange (std::move (lower_patterns), | |
11223 | std::move (upper_patterns))); | |
11224 | } | |
11225 | default: | |
11226 | // error | |
11227 | add_error (Error (t->get_locus (), | |
11228 | "unexpected token %qs in tuple struct items", | |
11229 | t->get_token_description ())); | |
11230 | ||
11231 | return nullptr; | |
11232 | } | |
11233 | } | |
11234 | ||
11235 | // Parses struct pattern elements if they exist. | |
11236 | template <typename ManagedTokenSource> | |
11237 | AST::StructPatternElements | |
11238 | Parser<ManagedTokenSource>::parse_struct_pattern_elems () | |
11239 | { | |
11240 | std::vector<std::unique_ptr<AST::StructPatternField>> fields; | |
11241 | ||
11242 | AST::AttrVec etc_attrs; | |
11243 | bool has_etc = false; | |
11244 | ||
11245 | // try parsing struct pattern fields | |
11246 | const_TokenPtr t = lexer.peek_token (); | |
11247 | while (t->get_id () != RIGHT_CURLY) | |
11248 | { | |
11249 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
11250 | ||
11251 | // parse etc (must be last in struct pattern, so breaks) | |
11252 | if (lexer.peek_token ()->get_id () == DOT_DOT) | |
11253 | { | |
11254 | lexer.skip_token (); | |
11255 | etc_attrs = std::move (outer_attrs); | |
11256 | has_etc = true; | |
11257 | break; | |
11258 | } | |
11259 | ||
11260 | std::unique_ptr<AST::StructPatternField> field | |
11261 | = parse_struct_pattern_field_partial (std::move (outer_attrs)); | |
11262 | if (field == nullptr) | |
11263 | { | |
11264 | Error error (lexer.peek_token ()->get_locus (), | |
11265 | "failed to parse struct pattern field"); | |
11266 | add_error (std::move (error)); | |
11267 | ||
11268 | // skip after somewhere? | |
11269 | return AST::StructPatternElements::create_empty (); | |
11270 | } | |
11271 | fields.push_back (std::move (field)); | |
11272 | ||
11273 | if (lexer.peek_token ()->get_id () != COMMA) | |
11274 | break; | |
11275 | ||
11276 | // skip comma | |
11277 | lexer.skip_token (); | |
11278 | t = lexer.peek_token (); | |
11279 | } | |
11280 | ||
11281 | if (has_etc) | |
11282 | return AST::StructPatternElements (std::move (fields), | |
11283 | std::move (etc_attrs)); | |
11284 | else | |
11285 | return AST::StructPatternElements (std::move (fields)); | |
11286 | } | |
11287 | ||
11288 | /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or | |
11289 | * identifier). */ | |
11290 | template <typename ManagedTokenSource> | |
11291 | std::unique_ptr<AST::StructPatternField> | |
11292 | Parser<ManagedTokenSource>::parse_struct_pattern_field () | |
11293 | { | |
11294 | // parse outer attributes (if they exist) | |
11295 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
11296 | ||
11297 | return parse_struct_pattern_field_partial (std::move (outer_attrs)); | |
11298 | } | |
11299 | ||
11300 | /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or | |
11301 | * identifier), with outer attributes passed in. */ | |
11302 | template <typename ManagedTokenSource> | |
11303 | std::unique_ptr<AST::StructPatternField> | |
11304 | Parser<ManagedTokenSource>::parse_struct_pattern_field_partial ( | |
11305 | AST::AttrVec outer_attrs) | |
11306 | { | |
11307 | // branch based on next token | |
11308 | const_TokenPtr t = lexer.peek_token (); | |
11309 | switch (t->get_id ()) | |
11310 | { | |
11311 | case INT_LITERAL: { | |
11312 | // tuple index | |
11313 | std::string index_str = t->get_str (); | |
11314 | int index = atoi (index_str.c_str ()); | |
11315 | ||
11316 | lexer.skip_token (); | |
11317 | ||
11318 | if (!skip_token (COLON)) | |
11319 | { | |
11320 | return nullptr; | |
11321 | } | |
11322 | ||
11323 | // parse required pattern | |
11324 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
11325 | if (pattern == nullptr) | |
11326 | { | |
11327 | Error error ( | |
11328 | t->get_locus (), | |
11329 | "failed to parse pattern in tuple index struct pattern field"); | |
11330 | add_error (std::move (error)); | |
11331 | ||
11332 | return nullptr; | |
11333 | } | |
11334 | ||
11335 | return std::unique_ptr<AST::StructPatternFieldTuplePat> ( | |
11336 | new AST::StructPatternFieldTuplePat (index, std::move (pattern), | |
11337 | std::move (outer_attrs), | |
11338 | t->get_locus ())); | |
11339 | } | |
11340 | case IDENTIFIER: | |
11341 | // identifier-pattern OR only identifier | |
11342 | // branch on next token | |
11343 | switch (lexer.peek_token (1)->get_id ()) | |
11344 | { | |
11345 | case COLON: { | |
11346 | // identifier-pattern | |
11347 | Identifier ident{t}; | |
11348 | lexer.skip_token (); | |
11349 | ||
11350 | skip_token (COLON); | |
11351 | ||
11352 | // parse required pattern | |
11353 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
11354 | if (pattern == nullptr) | |
11355 | { | |
11356 | Error error (t->get_locus (), | |
11357 | "failed to parse pattern in struct pattern field"); | |
11358 | add_error (std::move (error)); | |
11359 | ||
11360 | return nullptr; | |
11361 | } | |
11362 | ||
11363 | return std::unique_ptr<AST::StructPatternFieldIdentPat> ( | |
11364 | new AST::StructPatternFieldIdentPat (std::move (ident), | |
11365 | std::move (pattern), | |
11366 | std::move (outer_attrs), | |
11367 | t->get_locus ())); | |
11368 | } | |
11369 | case COMMA: | |
11370 | case RIGHT_CURLY: { | |
11371 | // identifier only | |
11372 | Identifier ident = {t}; | |
11373 | lexer.skip_token (); | |
11374 | ||
11375 | return std::unique_ptr<AST::StructPatternFieldIdent> ( | |
11376 | new AST::StructPatternFieldIdent (std::move (ident), false, false, | |
11377 | std::move (outer_attrs), | |
11378 | t->get_locus ())); | |
11379 | } | |
11380 | default: | |
11381 | // error | |
11382 | add_error (Error (t->get_locus (), | |
11383 | "unrecognised token %qs in struct pattern field", | |
11384 | t->get_token_description ())); | |
11385 | ||
11386 | return nullptr; | |
11387 | } | |
11388 | case REF: | |
11389 | case MUT: { | |
11390 | // only identifier | |
11391 | bool has_ref = false; | |
11392 | if (t->get_id () == REF) | |
11393 | { | |
11394 | has_ref = true; | |
11395 | lexer.skip_token (); | |
11396 | } | |
11397 | ||
11398 | bool has_mut = false; | |
11399 | if (lexer.peek_token ()->get_id () == MUT) | |
11400 | { | |
11401 | has_mut = true; | |
11402 | lexer.skip_token (); | |
11403 | } | |
11404 | ||
11405 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
11406 | if (ident_tok == nullptr) | |
11407 | { | |
11408 | return nullptr; | |
11409 | } | |
11410 | Identifier ident{ident_tok}; | |
11411 | ||
11412 | return std::unique_ptr<AST::StructPatternFieldIdent> ( | |
11413 | new AST::StructPatternFieldIdent (std::move (ident), has_ref, has_mut, | |
11414 | std::move (outer_attrs), | |
11415 | t->get_locus ())); | |
11416 | } | |
11417 | default: | |
11418 | // not necessarily an error | |
11419 | return nullptr; | |
11420 | } | |
11421 | } | |
11422 | ||
11423 | /* Parses a statement or expression (depending on whether a trailing semicolon | |
11424 | * exists). Useful for block expressions where it cannot be determined through | |
11425 | * lookahead whether it is a statement or expression to be parsed. */ | |
11426 | template <typename ManagedTokenSource> | |
11427 | ExprOrStmt | |
11428 | Parser<ManagedTokenSource>::parse_stmt_or_expr () | |
11429 | { | |
11430 | // quick exit for empty statement | |
11431 | const_TokenPtr t = lexer.peek_token (); | |
11432 | if (t->get_id () == SEMICOLON) | |
11433 | { | |
11434 | lexer.skip_token (); | |
11435 | std::unique_ptr<AST::EmptyStmt> stmt ( | |
11436 | new AST::EmptyStmt (t->get_locus ())); | |
11437 | return ExprOrStmt (std::move (stmt)); | |
11438 | } | |
11439 | ||
11440 | // parse outer attributes | |
11441 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
11442 | ParseRestrictions restrictions; | |
11443 | restrictions.expr_can_be_stmt = true; | |
11444 | std::unique_ptr<AST::Expr> expr; | |
11445 | ||
11446 | // parsing this will be annoying because of the many different possibilities | |
11447 | /* best may be just to copy paste in parse_item switch, and failing that try | |
11448 | * to parse outer attributes, and then pass them in to either a let | |
11449 | * statement or (fallback) expression statement. */ | |
11450 | // FIXME: think of a way to do this without such a large switch? | |
11451 | ||
11452 | /* FIXME: for expressions at least, the only way that they can really be | |
11453 | * parsed properly in this way is if they don't support operators on them. | |
11454 | * They must be pratt-parsed otherwise. As such due to composability, only | |
11455 | * explicit statements will have special cases here. This should roughly | |
11456 | * correspond to "expr-with-block", but this warning is here in case it | |
11457 | * isn't the case. */ | |
11458 | t = lexer.peek_token (); | |
11459 | switch (t->get_id ()) | |
11460 | { | |
11461 | case LET: { | |
11462 | // let statement | |
11463 | std::unique_ptr<AST::LetStmt> stmt ( | |
11464 | parse_let_stmt (std::move (outer_attrs))); | |
11465 | return ExprOrStmt (std::move (stmt)); | |
11466 | } | |
11467 | case PUB: | |
11468 | case MOD: | |
11469 | case EXTERN_KW: | |
11470 | case USE: | |
11471 | case FN_KW: | |
11472 | case TYPE: | |
11473 | case STRUCT_KW: | |
11474 | case ENUM_KW: | |
11475 | case CONST: | |
11476 | case STATIC_KW: | |
11477 | case AUTO: | |
11478 | case TRAIT: | |
11479 | case IMPL: { | |
11480 | std::unique_ptr<AST::VisItem> item ( | |
11481 | parse_vis_item (std::move (outer_attrs))); | |
11482 | return ExprOrStmt (std::move (item)); | |
11483 | } | |
11484 | /* TODO: implement union keyword but not really because of | |
11485 | * context-dependence crappy hack way to parse a union written below to | |
11486 | * separate it from the good code. */ | |
11487 | // case UNION: | |
11488 | case UNSAFE: { // maybe - unsafe traits are a thing | |
11489 | /* if any of these (should be all possible VisItem prefixes), parse a | |
11490 | * VisItem - can't parse item because would require reparsing outer | |
11491 | * attributes */ | |
11492 | const_TokenPtr t2 = lexer.peek_token (1); | |
11493 | switch (t2->get_id ()) | |
11494 | { | |
11495 | case LEFT_CURLY: { | |
11496 | // unsafe block: parse as expression | |
11497 | expr = parse_expr (std::move (outer_attrs), restrictions); | |
11498 | break; | |
11499 | } | |
11500 | case AUTO: | |
11501 | case TRAIT: { | |
11502 | // unsafe trait | |
11503 | std::unique_ptr<AST::VisItem> item ( | |
11504 | parse_vis_item (std::move (outer_attrs))); | |
11505 | return ExprOrStmt (std::move (item)); | |
11506 | } | |
11507 | case EXTERN_KW: | |
11508 | case FN_KW: { | |
11509 | // unsafe function | |
11510 | std::unique_ptr<AST::VisItem> item ( | |
11511 | parse_vis_item (std::move (outer_attrs))); | |
11512 | return ExprOrStmt (std::move (item)); | |
11513 | } | |
11514 | case IMPL: { | |
11515 | // unsafe trait impl | |
11516 | std::unique_ptr<AST::VisItem> item ( | |
11517 | parse_vis_item (std::move (outer_attrs))); | |
11518 | return ExprOrStmt (std::move (item)); | |
11519 | } | |
11520 | default: | |
11521 | add_error (Error (t2->get_locus (), | |
11522 | "unrecognised token %qs after parsing unsafe - " | |
11523 | "expected beginning of expression or statement", | |
11524 | t->get_token_description ())); | |
11525 | ||
11526 | // skip somewhere? | |
11527 | return ExprOrStmt::create_error (); | |
11528 | } | |
11529 | break; | |
11530 | } | |
11531 | /* FIXME: this is either a macro invocation or macro invocation semi. | |
11532 | * start parsing to determine which one it is. */ | |
11533 | // FIXME: old code there | |
11534 | ||
11535 | // crappy hack to do union "keyword" | |
11536 | case IDENTIFIER: | |
11537 | if (t->get_str () == Values::WeakKeywords::UNION | |
11538 | && lexer.peek_token (1)->get_id () == IDENTIFIER) | |
11539 | { | |
11540 | std::unique_ptr<AST::VisItem> item ( | |
11541 | parse_vis_item (std::move (outer_attrs))); | |
11542 | return ExprOrStmt (std::move (item)); | |
11543 | // or should this go straight to parsing union? | |
11544 | } | |
11545 | else if (t->get_str () == Values::WeakKeywords::MACRO_RULES | |
11546 | && lexer.peek_token (1)->get_id () == EXCLAM) | |
11547 | { | |
11548 | // macro_rules! macro item | |
11549 | std::unique_ptr<AST::Item> item ( | |
11550 | parse_macro_rules_def (std::move (outer_attrs))); | |
11551 | return ExprOrStmt (std::move (item)); | |
11552 | } | |
11553 | gcc_fallthrough (); | |
11554 | case SUPER: | |
11555 | case SELF: | |
11556 | case SELF_ALIAS: | |
11557 | case CRATE: | |
11558 | case SCOPE_RESOLUTION: | |
11559 | case DOLLAR_SIGN: { | |
11560 | AST::PathInExpression path = parse_path_in_expression (); | |
11561 | std::unique_ptr<AST::Expr> null_denotation; | |
11562 | ||
11563 | if (lexer.peek_token ()->get_id () == EXCLAM) | |
11564 | { | |
11565 | std::unique_ptr<AST::MacroInvocation> invoc | |
11566 | = parse_macro_invocation_partial (std::move (path), | |
11567 | std::move (outer_attrs)); | |
11568 | ||
11569 | if (restrictions.consume_semi && maybe_skip_token (SEMICOLON)) | |
11570 | { | |
11571 | invoc->add_semicolon (); | |
11572 | // Macro invocation with semicolon. | |
11573 | return ExprOrStmt ( | |
11574 | std::unique_ptr<AST::Stmt> (std::move (invoc))); | |
11575 | } | |
11576 | ||
11577 | TokenId after_macro = lexer.peek_token ()->get_id (); | |
11578 | ||
11579 | if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type () | |
11580 | == AST::CURLY | |
11581 | && after_macro != DOT && after_macro != QUESTION_MARK) | |
11582 | { | |
11583 | rust_debug ("braced macro statement"); | |
11584 | return ExprOrStmt ( | |
11585 | std::unique_ptr<AST::Stmt> (std::move (invoc))); | |
11586 | } | |
11587 | ||
11588 | null_denotation = std::move (invoc); | |
11589 | } | |
11590 | else | |
11591 | { | |
11592 | null_denotation | |
11593 | = null_denotation_path (std::move (path), {}, restrictions); | |
11594 | } | |
11595 | ||
11596 | expr = left_denotations (std::move (null_denotation), LBP_LOWEST, | |
11597 | std::move (outer_attrs), restrictions); | |
11598 | break; | |
11599 | } | |
11600 | default: | |
11601 | /* expression statement or expression itself - parse | |
11602 | * expression then make it statement if semi afterwards */ | |
11603 | expr = parse_expr (std::move (outer_attrs), restrictions); | |
11604 | break; | |
11605 | } | |
11606 | ||
11607 | const_TokenPtr after_expr = lexer.peek_token (); | |
11608 | if (after_expr->get_id () == SEMICOLON) | |
11609 | { | |
11610 | // must be expression statement | |
11611 | lexer.skip_token (); | |
11612 | ||
11613 | if (expr) | |
11614 | { | |
11615 | std::unique_ptr<AST::ExprStmt> stmt ( | |
11616 | new AST::ExprStmt (std::move (expr), t->get_locus (), true)); | |
11617 | return ExprOrStmt (std::move (stmt)); | |
11618 | } | |
11619 | else | |
11620 | { | |
11621 | return ExprOrStmt::create_error (); | |
11622 | } | |
11623 | } | |
11624 | ||
11625 | if (expr && !expr->is_expr_without_block () | |
11626 | && after_expr->get_id () != RIGHT_CURLY) | |
11627 | { | |
11628 | // block expression statement. | |
11629 | std::unique_ptr<AST::ExprStmt> stmt ( | |
11630 | new AST::ExprStmt (std::move (expr), t->get_locus (), false)); | |
11631 | return ExprOrStmt (std::move (stmt)); | |
11632 | } | |
11633 | ||
11634 | // return expression | |
11635 | return ExprOrStmt (std::move (expr)); | |
11636 | } | |
11637 | ||
11638 | // Parses a struct expression field. | |
11639 | template <typename ManagedTokenSource> | |
11640 | std::unique_ptr<AST::StructExprField> | |
11641 | Parser<ManagedTokenSource>::parse_struct_expr_field () | |
11642 | { | |
11643 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
11644 | const_TokenPtr t = lexer.peek_token (); | |
11645 | switch (t->get_id ()) | |
11646 | { | |
11647 | case IDENTIFIER: | |
11648 | if (lexer.peek_token (1)->get_id () == COLON) | |
11649 | { | |
11650 | // struct expr field with identifier and expr | |
11651 | Identifier ident = {t}; | |
11652 | lexer.skip_token (1); | |
11653 | ||
11654 | // parse expression (required) | |
11655 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
11656 | if (expr == nullptr) | |
11657 | { | |
11658 | Error error (t->get_locus (), | |
11659 | "failed to parse struct expression field with " | |
11660 | "identifier and expression"); | |
11661 | add_error (std::move (error)); | |
11662 | ||
11663 | return nullptr; | |
11664 | } | |
11665 | ||
11666 | return std::unique_ptr<AST::StructExprFieldIdentifierValue> ( | |
11667 | new AST::StructExprFieldIdentifierValue (std::move (ident), | |
11668 | std::move (expr), | |
11669 | std::move (outer_attrs), | |
11670 | t->get_locus ())); | |
11671 | } | |
11672 | else | |
11673 | { | |
11674 | // struct expr field with identifier only | |
11675 | Identifier ident{t}; | |
11676 | lexer.skip_token (); | |
11677 | ||
11678 | return std::unique_ptr<AST::StructExprFieldIdentifier> ( | |
11679 | new AST::StructExprFieldIdentifier (std::move (ident), | |
11680 | std::move (outer_attrs), | |
11681 | t->get_locus ())); | |
11682 | } | |
11683 | case INT_LITERAL: { | |
11684 | // parse tuple index field | |
11685 | int index = atoi (t->get_str ().c_str ()); | |
11686 | lexer.skip_token (); | |
11687 | ||
11688 | if (!skip_token (COLON)) | |
11689 | { | |
11690 | // skip somewhere? | |
11691 | return nullptr; | |
11692 | } | |
11693 | ||
11694 | // parse field expression (required) | |
11695 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
11696 | if (expr == nullptr) | |
11697 | { | |
11698 | Error error (t->get_locus (), | |
11699 | "failed to parse expr in struct (or enum) expr " | |
11700 | "field with tuple index"); | |
11701 | add_error (std::move (error)); | |
11702 | ||
11703 | return nullptr; | |
11704 | } | |
11705 | ||
11706 | return std::unique_ptr<AST::StructExprFieldIndexValue> ( | |
11707 | new AST::StructExprFieldIndexValue (index, std::move (expr), | |
11708 | std::move (outer_attrs), | |
11709 | t->get_locus ())); | |
11710 | } | |
11711 | case DOT_DOT: | |
11712 | /* this is a struct base and can't be parsed here, so just return | |
11713 | * nothing without erroring */ | |
11714 | ||
11715 | return nullptr; | |
11716 | default: | |
11717 | add_error ( | |
11718 | Error (t->get_locus (), | |
11719 | "unrecognised token %qs as first token of struct expr field - " | |
11720 | "expected identifier or integer literal", | |
11721 | t->get_token_description ())); | |
11722 | ||
11723 | return nullptr; | |
11724 | } | |
11725 | } | |
11726 | ||
11727 | // "Unexpected token" panic mode - flags gcc error at unexpected token | |
11728 | template <typename ManagedTokenSource> | |
11729 | void | |
11730 | Parser<ManagedTokenSource>::unexpected_token (const_TokenPtr t) | |
11731 | { | |
11732 | Error error (t->get_locus (), "unexpected token %qs\n", | |
11733 | t->get_token_description ()); | |
11734 | add_error (std::move (error)); | |
11735 | } | |
11736 | ||
11737 | /* Crappy "error recovery" performed after error by skipping tokens until a | |
11738 | * semi-colon is found */ | |
11739 | template <typename ManagedTokenSource> | |
11740 | void | |
11741 | Parser<ManagedTokenSource>::skip_after_semicolon () | |
11742 | { | |
11743 | const_TokenPtr t = lexer.peek_token (); | |
11744 | ||
11745 | while (t->get_id () != END_OF_FILE && t->get_id () != SEMICOLON) | |
11746 | { | |
11747 | lexer.skip_token (); | |
11748 | t = lexer.peek_token (); | |
11749 | } | |
11750 | ||
11751 | if (t->get_id () == SEMICOLON) | |
11752 | lexer.skip_token (); | |
11753 | } | |
11754 | ||
11755 | /* Skips the current token */ | |
11756 | template <typename ManagedTokenSource> | |
11757 | void | |
11758 | Parser<ManagedTokenSource>::skip_token () | |
11759 | { | |
11760 | lexer.skip_token (); | |
11761 | } | |
11762 | ||
11763 | /* Checks if current token has inputted id - skips it and returns true if so, | |
11764 | * diagnoses an error and returns false otherwise. */ | |
11765 | template <typename ManagedTokenSource> | |
11766 | bool | |
11767 | Parser<ManagedTokenSource>::skip_token (TokenId token_id) | |
11768 | { | |
11769 | return expect_token (token_id) != const_TokenPtr (); | |
11770 | } | |
11771 | ||
11772 | /* Checks if current token is similar to inputted token - skips it and returns | |
11773 | * true if so, diagnoses an error and returns false otherwise. */ | |
11774 | template <typename ManagedTokenSource> | |
11775 | bool | |
11776 | Parser<ManagedTokenSource>::skip_token (const_TokenPtr token) | |
11777 | { | |
11778 | return expect_token (token) != const_TokenPtr (); | |
11779 | } | |
11780 | ||
11781 | /* Checks if current token has inputted id - skips it and returns true if so, | |
11782 | * returns false otherwise without diagnosing an error */ | |
11783 | template <typename ManagedTokenSource> | |
11784 | bool | |
11785 | Parser<ManagedTokenSource>::maybe_skip_token (TokenId token_id) | |
11786 | { | |
11787 | if (lexer.peek_token ()->get_id () != token_id) | |
11788 | return false; | |
11789 | else | |
11790 | return skip_token (token_id); | |
11791 | } | |
11792 | ||
11793 | /* Checks the current token - if id is same as expected, skips and returns it, | |
11794 | * otherwise diagnoses error and returns null. */ | |
11795 | template <typename ManagedTokenSource> | |
11796 | const_TokenPtr | |
11797 | Parser<ManagedTokenSource>::expect_token (TokenId token_id) | |
11798 | { | |
11799 | const_TokenPtr t = lexer.peek_token (); | |
11800 | if (t->get_id () == token_id) | |
11801 | { | |
11802 | lexer.skip_token (); | |
11803 | return t; | |
11804 | } | |
11805 | else | |
11806 | { | |
11807 | Error error (t->get_locus (), "expecting %qs but %qs found", | |
11808 | get_token_description (token_id), | |
11809 | t->get_token_description ()); | |
11810 | add_error (std::move (error)); | |
11811 | ||
11812 | return const_TokenPtr (); | |
11813 | } | |
11814 | } | |
11815 | ||
11816 | /* Checks the current token - if same as expected, skips and returns it, | |
11817 | * otherwise diagnoses error and returns null. */ | |
11818 | template <typename ManagedTokenSource> | |
11819 | const_TokenPtr | |
11820 | Parser<ManagedTokenSource>::expect_token (const_TokenPtr token_expect) | |
11821 | { | |
11822 | const_TokenPtr t = lexer.peek_token (); | |
11823 | if (t->get_id () == token_expect->get_id () | |
11824 | && (!t->should_have_str () || t->get_str () == token_expect->get_str ())) | |
11825 | { | |
11826 | lexer.skip_token (); | |
11827 | return t; | |
11828 | } | |
11829 | else | |
11830 | { | |
11831 | Error error (t->get_locus (), "expecting %qs but %qs found", | |
11832 | token_expect->get_token_description (), | |
11833 | t->get_token_description ()); | |
11834 | add_error (std::move (error)); | |
11835 | ||
11836 | return const_TokenPtr (); | |
11837 | } | |
11838 | } | |
11839 | ||
11840 | // Skips all tokens until EOF or }. Don't use. | |
11841 | template <typename ManagedTokenSource> | |
11842 | void | |
11843 | Parser<ManagedTokenSource>::skip_after_end () | |
11844 | { | |
11845 | const_TokenPtr t = lexer.peek_token (); | |
11846 | ||
11847 | while (t->get_id () != END_OF_FILE && t->get_id () != RIGHT_CURLY) | |
11848 | { | |
11849 | lexer.skip_token (); | |
11850 | t = lexer.peek_token (); | |
11851 | } | |
11852 | ||
11853 | if (t->get_id () == RIGHT_CURLY) | |
11854 | { | |
11855 | lexer.skip_token (); | |
11856 | } | |
11857 | } | |
11858 | ||
11859 | /* A slightly more aware error-handler that skips all tokens until it reaches | |
11860 | * the end of the block scope (i.e. when left curly brackets = right curly | |
11861 | * brackets). Note: assumes currently in the middle of a block. Use | |
11862 | * skip_after_next_block to skip based on the assumption that the block | |
11863 | * has not been entered yet. */ | |
11864 | template <typename ManagedTokenSource> | |
11865 | void | |
11866 | Parser<ManagedTokenSource>::skip_after_end_block () | |
11867 | { | |
11868 | const_TokenPtr t = lexer.peek_token (); | |
11869 | int curly_count = 1; | |
11870 | ||
11871 | while (curly_count > 0 && t->get_id () != END_OF_FILE) | |
11872 | { | |
11873 | switch (t->get_id ()) | |
11874 | { | |
11875 | case LEFT_CURLY: | |
11876 | curly_count++; | |
11877 | break; | |
11878 | case RIGHT_CURLY: | |
11879 | curly_count--; | |
11880 | break; | |
11881 | default: | |
11882 | break; | |
11883 | } | |
11884 | lexer.skip_token (); | |
11885 | t = lexer.peek_token (); | |
11886 | } | |
11887 | } | |
11888 | ||
11889 | /* Skips tokens until the end of the next block. i.e. assumes that the block | |
11890 | * has not been entered yet. */ | |
11891 | template <typename ManagedTokenSource> | |
11892 | void | |
11893 | Parser<ManagedTokenSource>::skip_after_next_block () | |
11894 | { | |
11895 | const_TokenPtr t = lexer.peek_token (); | |
11896 | ||
11897 | // initial loop - skip until EOF if no left curlies encountered | |
11898 | while (t->get_id () != END_OF_FILE && t->get_id () != LEFT_CURLY) | |
11899 | { | |
11900 | lexer.skip_token (); | |
11901 | ||
11902 | t = lexer.peek_token (); | |
11903 | } | |
11904 | ||
11905 | // if next token is left, skip it and then skip after the block ends | |
11906 | if (t->get_id () == LEFT_CURLY) | |
11907 | { | |
11908 | lexer.skip_token (); | |
11909 | ||
11910 | skip_after_end_block (); | |
11911 | } | |
11912 | // otherwise, do nothing as EOF | |
11913 | } | |
11914 | ||
11915 | /* Skips all tokens until ] (the end of an attribute) - does not skip the ] | |
11916 | * (as designed for attribute body use) */ | |
11917 | template <typename ManagedTokenSource> | |
11918 | void | |
11919 | Parser<ManagedTokenSource>::skip_after_end_attribute () | |
11920 | { | |
11921 | const_TokenPtr t = lexer.peek_token (); | |
11922 | ||
11923 | while (t->get_id () != RIGHT_SQUARE) | |
11924 | { | |
11925 | lexer.skip_token (); | |
11926 | t = lexer.peek_token (); | |
11927 | } | |
11928 | ||
11929 | // Don't skip the RIGHT_SQUARE token | |
11930 | } | |
11931 | ||
11932 | /* Pratt parser impl of parse_expr. FIXME: this is only provisional and | |
11933 | * probably will be changed. */ | |
11934 | template <typename ManagedTokenSource> | |
11935 | std::unique_ptr<AST::Expr> | |
11936 | Parser<ManagedTokenSource>::parse_expr (int right_binding_power, | |
11937 | AST::AttrVec outer_attrs, | |
11938 | ParseRestrictions restrictions) | |
11939 | { | |
11940 | const_TokenPtr current_token = lexer.peek_token (); | |
11941 | // Special hack because we are allowed to return nullptr, in that case we | |
11942 | // don't want to skip the token, since we don't actually parse it. But if | |
11943 | // null isn't allowed it indicates an error, and we want to skip past that. | |
11944 | // So return early if it is one of the tokens that ends an expression | |
11945 | // (or at least cannot start a new expression). | |
11946 | if (restrictions.expr_can_be_null) | |
11947 | { | |
11948 | TokenId id = current_token->get_id (); | |
11949 | if (id == SEMICOLON || id == RIGHT_PAREN || id == RIGHT_CURLY | |
11950 | || id == RIGHT_SQUARE || id == COMMA || id == LEFT_CURLY) | |
11951 | return nullptr; | |
11952 | } | |
11953 | ||
11954 | if (current_token->get_id () == LEFT_SHIFT) | |
11955 | { | |
11956 | lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE); | |
11957 | current_token = lexer.peek_token (); | |
11958 | } | |
11959 | ||
11960 | lexer.skip_token (); | |
11961 | ||
11962 | ParseRestrictions null_denotation_restrictions = restrictions; | |
11963 | null_denotation_restrictions.expr_can_be_stmt = false; | |
11964 | ||
11965 | // parse null denotation (unary part of expression) | |
11966 | std::unique_ptr<AST::Expr> expr | |
11967 | = null_denotation (current_token, {}, null_denotation_restrictions); | |
11968 | ||
11969 | return left_denotations (std::move (expr), right_binding_power, | |
11970 | std::move (outer_attrs), restrictions); | |
11971 | } | |
11972 | ||
11973 | template <typename ManagedTokenSource> | |
11974 | std::unique_ptr<AST::Expr> | |
11975 | Parser<ManagedTokenSource>::left_denotations (std::unique_ptr<AST::Expr> expr, | |
11976 | int right_binding_power, | |
11977 | AST::AttrVec outer_attrs, | |
11978 | ParseRestrictions restrictions) | |
11979 | { | |
11980 | if (expr == nullptr) | |
11981 | { | |
11982 | // DEBUG | |
11983 | rust_debug ("null denotation is null; returning null for parse_expr"); | |
11984 | return nullptr; | |
11985 | } | |
11986 | ||
11987 | const_TokenPtr current_token = lexer.peek_token (); | |
11988 | ||
11989 | if (restrictions.expr_can_be_stmt && !expr->is_expr_without_block () | |
11990 | && current_token->get_id () != DOT | |
11991 | && current_token->get_id () != QUESTION_MARK) | |
11992 | { | |
11993 | rust_debug ("statement expression with block"); | |
11994 | expr->set_outer_attrs (std::move (outer_attrs)); | |
11995 | return expr; | |
11996 | } | |
11997 | ||
11998 | restrictions.expr_can_be_stmt = false; | |
11999 | ||
12000 | // stop parsing if find lower priority token - parse higher priority first | |
12001 | while (right_binding_power < left_binding_power (current_token)) | |
12002 | { | |
12003 | lexer.skip_token (); | |
12004 | ||
12005 | // FIXME attributes should generally be applied to the null denotation. | |
12006 | expr = left_denotation (current_token, std::move (expr), | |
12007 | std::move (outer_attrs), restrictions); | |
12008 | ||
12009 | if (expr == nullptr) | |
12010 | { | |
12011 | // DEBUG | |
12012 | rust_debug ("left denotation is null; returning null for parse_expr"); | |
12013 | ||
12014 | return nullptr; | |
12015 | } | |
12016 | ||
12017 | current_token = lexer.peek_token (); | |
12018 | } | |
12019 | ||
12020 | return expr; | |
12021 | } | |
12022 | ||
12023 | // Parse expression with lowest left binding power. | |
12024 | template <typename ManagedTokenSource> | |
12025 | std::unique_ptr<AST::Expr> | |
12026 | Parser<ManagedTokenSource>::parse_expr (AST::AttrVec outer_attrs, | |
12027 | ParseRestrictions restrictions) | |
12028 | { | |
12029 | return parse_expr (LBP_LOWEST, std::move (outer_attrs), restrictions); | |
12030 | } | |
12031 | ||
12032 | /* Determines action to take when finding token at beginning of expression. */ | |
12033 | template <typename ManagedTokenSource> | |
12034 | std::unique_ptr<AST::Expr> | |
12035 | Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok, | |
12036 | AST::AttrVec outer_attrs, | |
12037 | ParseRestrictions restrictions) | |
12038 | { | |
12039 | /* note: tok is previous character in input stream, not current one, as | |
12040 | * parse_expr skips it before passing it in */ | |
12041 | ||
12042 | /* as a Pratt parser (which works by decomposing expressions into a null | |
12043 | * denotation and then a left denotation), null denotations handle primaries | |
12044 | * and unary operands (but only prefix unary operands) */ | |
12045 | ||
12046 | switch (tok->get_id ()) | |
12047 | { | |
12048 | case IDENTIFIER: | |
12049 | case SELF: | |
12050 | case SELF_ALIAS: | |
12051 | case DOLLAR_SIGN: | |
12052 | case CRATE: | |
12053 | case SUPER: { | |
12054 | // DEBUG | |
12055 | rust_debug ("beginning null denotation identifier handling"); | |
12056 | ||
12057 | /* best option: parse as path, then extract identifier, macro, | |
12058 | * struct/enum, or just path info from it */ | |
12059 | AST::PathInExpression path = parse_path_in_expression_pratt (tok); | |
12060 | ||
12061 | return null_denotation_path (std::move (path), std::move (outer_attrs), | |
12062 | restrictions); | |
12063 | } | |
12064 | case SCOPE_RESOLUTION: { | |
12065 | // TODO: fix: this is for global paths, i.e. std::string::whatever | |
12066 | Error error (tok->get_locus (), | |
12067 | "found null denotation scope resolution operator, and " | |
12068 | "have not written handling for it"); | |
12069 | add_error (std::move (error)); | |
12070 | ||
12071 | return nullptr; | |
12072 | } | |
12073 | default: | |
12074 | return null_denotation_not_path (std::move (tok), std::move (outer_attrs), | |
12075 | restrictions); | |
12076 | } | |
12077 | } | |
12078 | ||
12079 | // Handling of expresions that start with a path for `null_denotation`. | |
12080 | template <typename ManagedTokenSource> | |
12081 | std::unique_ptr<AST::Expr> | |
12082 | Parser<ManagedTokenSource>::null_denotation_path ( | |
12083 | AST::PathInExpression path, AST::AttrVec outer_attrs, | |
12084 | ParseRestrictions restrictions) | |
12085 | { | |
12086 | rust_debug ("parsing null denotation after path"); | |
12087 | ||
12088 | // HACK: always make "self" by itself a path (regardless of next | |
12089 | // tokens) | |
12090 | if (path.is_single_segment () && path.get_segments ()[0].is_lower_self_seg ()) | |
12091 | { | |
12092 | // HACK: add outer attrs to path | |
12093 | path.set_outer_attrs (std::move (outer_attrs)); | |
12094 | return std::unique_ptr<AST::PathInExpression> ( | |
12095 | new AST::PathInExpression (std::move (path))); | |
12096 | } | |
12097 | ||
12098 | // branch on next token | |
12099 | const_TokenPtr t = lexer.peek_token (); | |
12100 | switch (t->get_id ()) | |
12101 | { | |
12102 | case EXCLAM: | |
12103 | // macro | |
12104 | return parse_macro_invocation_partial (std::move (path), | |
12105 | std::move (outer_attrs)); | |
12106 | case LEFT_CURLY: { | |
12107 | bool not_a_block = lexer.peek_token (1)->get_id () == IDENTIFIER | |
12108 | && (lexer.peek_token (2)->get_id () == COMMA | |
12109 | || (lexer.peek_token (2)->get_id () == COLON | |
12110 | && (lexer.peek_token (4)->get_id () == COMMA | |
12111 | || !can_tok_start_type ( | |
12112 | lexer.peek_token (3)->get_id ())))); | |
12113 | ||
12114 | /* definitely not a block: | |
12115 | * path '{' ident ',' | |
12116 | * path '{' ident ':' [anything] ',' | |
12117 | * path '{' ident ':' [not a type] | |
12118 | * otherwise, assume block expr and thus path */ | |
12119 | // DEBUG | |
12120 | rust_debug ("values of lookahead: '%s' '%s' '%s' '%s' ", | |
12121 | lexer.peek_token (1)->get_token_description (), | |
12122 | lexer.peek_token (2)->get_token_description (), | |
12123 | lexer.peek_token (3)->get_token_description (), | |
12124 | lexer.peek_token (4)->get_token_description ()); | |
12125 | ||
12126 | rust_debug ("can be struct expr: '%s', not a block: '%s'", | |
12127 | restrictions.can_be_struct_expr ? "true" : "false", | |
12128 | not_a_block ? "true" : "false"); | |
12129 | ||
12130 | // struct/enum expr struct | |
12131 | if (!restrictions.can_be_struct_expr && !not_a_block) | |
12132 | { | |
12133 | // HACK: add outer attrs to path | |
12134 | path.set_outer_attrs (std::move (outer_attrs)); | |
12135 | return std::unique_ptr<AST::PathInExpression> ( | |
12136 | new AST::PathInExpression (std::move (path))); | |
12137 | } | |
12138 | return parse_struct_expr_struct_partial (std::move (path), | |
12139 | std::move (outer_attrs)); | |
12140 | } | |
12141 | case LEFT_PAREN: | |
12142 | // struct/enum expr tuple | |
12143 | if (!restrictions.can_be_struct_expr) | |
12144 | { | |
12145 | // assume path is returned | |
12146 | // HACK: add outer attributes to path | |
12147 | path.set_outer_attrs (std::move (outer_attrs)); | |
12148 | return std::unique_ptr<AST::PathInExpression> ( | |
12149 | new AST::PathInExpression (std::move (path))); | |
12150 | } | |
12151 | return parse_struct_expr_tuple_partial (std::move (path), | |
12152 | std::move (outer_attrs)); | |
12153 | default: | |
12154 | // assume path is returned if not single segment | |
12155 | if (path.is_single_segment ()) | |
12156 | { | |
12157 | // FIXME: This should probably be returned as a path. | |
12158 | /* HACK: may have to become permanent, but this is my current | |
12159 | * identifier expression */ | |
12160 | return std::unique_ptr<AST::IdentifierExpr> (new AST::IdentifierExpr ( | |
12161 | path.get_segments ()[0].get_ident_segment ().as_string (), {}, | |
12162 | path.get_locus ())); | |
12163 | } | |
12164 | // HACK: add outer attrs to path | |
12165 | path.set_outer_attrs (std::move (outer_attrs)); | |
12166 | return std::unique_ptr<AST::PathInExpression> ( | |
12167 | new AST::PathInExpression (std::move (path))); | |
12168 | } | |
12169 | rust_unreachable (); | |
12170 | } | |
12171 | ||
12172 | // Handling of expresions that do not start with a path for `null_denotation`. | |
12173 | template <typename ManagedTokenSource> | |
12174 | std::unique_ptr<AST::Expr> | |
12175 | Parser<ManagedTokenSource>::null_denotation_not_path ( | |
12176 | const_TokenPtr tok, AST::AttrVec outer_attrs, ParseRestrictions restrictions) | |
12177 | { | |
12178 | switch (tok->get_id ()) | |
12179 | { | |
12180 | // FIXME: Handle in null_denotation_path? | |
12181 | case LEFT_SHIFT: | |
12182 | case LEFT_ANGLE: { | |
12183 | // qualified path | |
12184 | // HACK: add outer attrs to path | |
12185 | AST::QualifiedPathInExpression path | |
12186 | = parse_qualified_path_in_expression (tok->get_locus ()); | |
12187 | path.set_outer_attrs (std::move (outer_attrs)); | |
12188 | return std::unique_ptr<AST::QualifiedPathInExpression> ( | |
12189 | new AST::QualifiedPathInExpression (std::move (path))); | |
12190 | } | |
12191 | // FIXME: delegate to parse_literal_expr instead? would have to rejig | |
12192 | // tokens and whatever. | |
12193 | // FIXME: for literal exprs, outer attrs should be passed in, and later | |
12194 | // error if it does not make up the entire statement. | |
12195 | case INT_LITERAL: | |
12196 | // we should check the range, but ignore for now | |
12197 | // encode as int? | |
12198 | return std::unique_ptr<AST::LiteralExpr> ( | |
12199 | new AST::LiteralExpr (tok->get_str (), AST::Literal::INT, | |
12200 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12201 | case FLOAT_LITERAL: | |
12202 | // encode as float? | |
12203 | return std::unique_ptr<AST::LiteralExpr> ( | |
12204 | new AST::LiteralExpr (tok->get_str (), AST::Literal::FLOAT, | |
12205 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12206 | case STRING_LITERAL: | |
12207 | return std::unique_ptr<AST::LiteralExpr> ( | |
12208 | new AST::LiteralExpr (tok->get_str (), AST::Literal::STRING, | |
12209 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12210 | case BYTE_STRING_LITERAL: | |
12211 | return std::unique_ptr<AST::LiteralExpr> ( | |
12212 | new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE_STRING, | |
12213 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12214 | case RAW_STRING_LITERAL: | |
12215 | return std::unique_ptr<AST::LiteralExpr> ( | |
12216 | new AST::LiteralExpr (tok->get_str (), AST::Literal::RAW_STRING, | |
12217 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12218 | case CHAR_LITERAL: | |
12219 | return std::unique_ptr<AST::LiteralExpr> ( | |
12220 | new AST::LiteralExpr (tok->get_str (), AST::Literal::CHAR, | |
12221 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12222 | case BYTE_CHAR_LITERAL: | |
12223 | return std::unique_ptr<AST::LiteralExpr> ( | |
12224 | new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE, | |
12225 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12226 | case TRUE_LITERAL: | |
12227 | return std::unique_ptr<AST::LiteralExpr> ( | |
12228 | new AST::LiteralExpr (Values::Keywords::TRUE_LITERAL, | |
12229 | AST::Literal::BOOL, tok->get_type_hint (), {}, | |
12230 | tok->get_locus ())); | |
12231 | case FALSE_LITERAL: | |
12232 | return std::unique_ptr<AST::LiteralExpr> ( | |
12233 | new AST::LiteralExpr (Values::Keywords::FALSE_LITERAL, | |
12234 | AST::Literal::BOOL, tok->get_type_hint (), {}, | |
12235 | tok->get_locus ())); | |
12236 | case LEFT_PAREN: | |
12237 | return parse_grouped_or_tuple_expr (std::move (outer_attrs), | |
12238 | tok->get_locus ()); | |
12239 | ||
12240 | /*case PLUS: { // unary plus operator | |
12241 | // invoke parse_expr recursively with appropriate priority, etc. for | |
12242 | below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS); | |
12243 | ||
12244 | if (expr == nullptr) | |
12245 | return nullptr; | |
12246 | // can only apply to integer and float expressions | |
12247 | if (expr->get_type() != integer_type_node || expr->get_type() != | |
12248 | float_type_node) { rust_error_at(tok->get_locus(), "operand of unary | |
12249 | plus must be int or float but it is %s", print_type(expr->get_type())); | |
12250 | return nullptr; | |
12251 | } | |
12252 | ||
12253 | return Tree(expr, tok->get_locus()); | |
12254 | }*/ | |
12255 | // Rust has no unary plus operator | |
12256 | case MINUS: { // unary minus | |
12257 | ParseRestrictions entered_from_unary; | |
12258 | entered_from_unary.entered_from_unary = true; | |
12259 | if (!restrictions.can_be_struct_expr) | |
12260 | entered_from_unary.can_be_struct_expr = false; | |
12261 | std::unique_ptr<AST::Expr> expr | |
12262 | = parse_expr (LBP_UNARY_MINUS, {}, entered_from_unary); | |
12263 | ||
12264 | if (expr == nullptr) | |
12265 | return nullptr; | |
12266 | // can only apply to integer and float expressions | |
12267 | /*if (expr.get_type() != integer_type_node || expr.get_type() != | |
12268 | float_type_node) { rust_error_at(tok->get_locus(), "operand of unary | |
12269 | minus must be int or float but it is %s", | |
12270 | print_type(expr.get_type())); return Tree::error(); | |
12271 | }*/ | |
12272 | /* FIXME: when implemented the "get type" method on expr, ensure it is | |
12273 | * int or float type (except unsigned int). Actually, this would | |
12274 | * probably have to be done in semantic analysis (as type checking). | |
12275 | */ | |
12276 | ||
12277 | /* FIXME: allow outer attributes on these expressions by having an | |
12278 | * outer attrs parameter in function*/ | |
12279 | return std::unique_ptr<AST::NegationExpr> ( | |
12280 | new AST::NegationExpr (std::move (expr), NegationOperator::NEGATE, | |
12281 | std::move (outer_attrs), tok->get_locus ())); | |
12282 | } | |
12283 | case EXCLAM: { // logical or bitwise not | |
12284 | ParseRestrictions entered_from_unary; | |
12285 | entered_from_unary.entered_from_unary = true; | |
12286 | if (!restrictions.can_be_struct_expr) | |
12287 | entered_from_unary.can_be_struct_expr = false; | |
12288 | std::unique_ptr<AST::Expr> expr | |
12289 | = parse_expr (LBP_UNARY_EXCLAM, {}, entered_from_unary); | |
12290 | ||
12291 | if (expr == nullptr) | |
12292 | return nullptr; | |
12293 | // can only apply to boolean expressions | |
12294 | /*if (expr.get_type() != boolean_type_node) { | |
12295 | rust_error_at(tok->get_locus(), | |
12296 | "operand of logical not must be a boolean but it is %s", | |
12297 | print_type(expr.get_type())); | |
12298 | return Tree::error(); | |
12299 | }*/ | |
12300 | /* FIXME: type checking for boolean or integer expressions in semantic | |
12301 | * analysis */ | |
12302 | ||
12303 | // FIXME: allow outer attributes on these expressions | |
12304 | return std::unique_ptr<AST::NegationExpr> ( | |
12305 | new AST::NegationExpr (std::move (expr), NegationOperator::NOT, | |
12306 | std::move (outer_attrs), tok->get_locus ())); | |
12307 | } | |
12308 | case ASTERISK: { | |
12309 | /* pointer dereference only - HACK: as struct expressions should | |
12310 | * always be value expressions, cannot be dereferenced */ | |
12311 | ParseRestrictions entered_from_unary; | |
12312 | entered_from_unary.entered_from_unary = true; | |
12313 | entered_from_unary.can_be_struct_expr = false; | |
12314 | std::unique_ptr<AST::Expr> expr | |
12315 | = parse_expr (LBP_UNARY_ASTERISK, {}, entered_from_unary); | |
12316 | // FIXME: allow outer attributes on expression | |
12317 | return std::unique_ptr<AST::DereferenceExpr> ( | |
12318 | new AST::DereferenceExpr (std::move (expr), std::move (outer_attrs), | |
12319 | tok->get_locus ())); | |
12320 | } | |
12321 | case AMP: { | |
12322 | // (single) "borrow" expression - shared (mutable) or immutable | |
12323 | std::unique_ptr<AST::Expr> expr = nullptr; | |
12324 | Mutability mutability = Mutability::Imm; | |
12325 | bool raw_borrow = false; | |
12326 | ||
12327 | ParseRestrictions entered_from_unary; | |
12328 | entered_from_unary.entered_from_unary = true; | |
12329 | if (!restrictions.can_be_struct_expr) | |
12330 | entered_from_unary.can_be_struct_expr = false; | |
12331 | ||
12332 | auto is_mutability = [] (const_TokenPtr token) { | |
12333 | return token->get_id () == CONST || token->get_id () == MUT; | |
12334 | }; | |
12335 | ||
12336 | auto t = lexer.peek_token (); | |
12337 | // Weak raw keyword, we look (1) ahead and treat it as an identifier if | |
12338 | // there is no mut nor const. | |
12339 | if (t->get_id () == IDENTIFIER | |
12340 | && t->get_str () == Values::WeakKeywords::RAW | |
12341 | && is_mutability (lexer.peek_token (1))) | |
12342 | { | |
12343 | lexer.skip_token (); | |
12344 | switch (lexer.peek_token ()->get_id ()) | |
12345 | { | |
12346 | case MUT: | |
12347 | mutability = Mutability::Mut; | |
12348 | break; | |
12349 | case CONST: | |
12350 | mutability = Mutability::Imm; | |
12351 | break; | |
12352 | default: | |
12353 | rust_error_at (lexer.peek_token ()->get_locus (), | |
12354 | "raw borrow should be either const or mut"); | |
12355 | } | |
12356 | lexer.skip_token (); | |
12357 | expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary); | |
12358 | raw_borrow = true; | |
12359 | } | |
12360 | else if (t->get_id () == MUT) | |
12361 | { | |
12362 | lexer.skip_token (); | |
12363 | expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary); | |
12364 | mutability = Mutability::Mut; | |
12365 | raw_borrow = false; | |
12366 | } | |
12367 | else | |
12368 | { | |
12369 | expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary); | |
12370 | raw_borrow = false; | |
12371 | } | |
12372 | ||
12373 | // FIXME: allow outer attributes on expression | |
12374 | return std::unique_ptr<AST::BorrowExpr> ( | |
12375 | new AST::BorrowExpr (std::move (expr), mutability, raw_borrow, false, | |
12376 | std::move (outer_attrs), tok->get_locus ())); | |
12377 | } | |
12378 | case LOGICAL_AND: { | |
12379 | // (double) "borrow" expression - shared (mutable) or immutable | |
12380 | std::unique_ptr<AST::Expr> expr = nullptr; | |
12381 | Mutability mutability = Mutability::Imm; | |
12382 | ||
12383 | ParseRestrictions entered_from_unary; | |
12384 | entered_from_unary.entered_from_unary = true; | |
12385 | ||
12386 | if (lexer.peek_token ()->get_id () == MUT) | |
12387 | { | |
12388 | lexer.skip_token (); | |
12389 | expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary); | |
12390 | mutability = Mutability::Mut; | |
12391 | } | |
12392 | else | |
12393 | { | |
12394 | expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary); | |
12395 | mutability = Mutability::Imm; | |
12396 | } | |
12397 | ||
12398 | // FIXME: allow outer attributes on expression | |
12399 | return std::unique_ptr<AST::BorrowExpr> ( | |
12400 | new AST::BorrowExpr (std::move (expr), mutability, false, true, | |
12401 | std::move (outer_attrs), tok->get_locus ())); | |
12402 | } | |
12403 | case OR: | |
12404 | case PIPE: | |
12405 | case MOVE: | |
12406 | // closure expression | |
12407 | return parse_closure_expr_pratt (tok, std::move (outer_attrs)); | |
12408 | case DOT_DOT: | |
12409 | // either "range to" or "range full" expressions | |
12410 | return parse_nud_range_exclusive_expr (tok, std::move (outer_attrs)); | |
12411 | case DOT_DOT_EQ: | |
12412 | // range to inclusive expr | |
12413 | return parse_range_to_inclusive_expr (tok, std::move (outer_attrs)); | |
12414 | case RETURN_KW: | |
12415 | // FIXME: is this really a null denotation expression? | |
12416 | return parse_return_expr (std::move (outer_attrs), tok->get_locus ()); | |
12417 | case BREAK: | |
12418 | // FIXME: is this really a null denotation expression? | |
12419 | return parse_break_expr (std::move (outer_attrs), tok->get_locus ()); | |
12420 | case CONTINUE: | |
12421 | return parse_continue_expr (std::move (outer_attrs), tok->get_locus ()); | |
12422 | case LEFT_CURLY: | |
12423 | // ok - this is an expression with block for once. | |
12424 | return parse_block_expr (std::move (outer_attrs), tl::nullopt, | |
12425 | tok->get_locus ()); | |
12426 | case IF: | |
12427 | // if or if let, so more lookahead to find out | |
12428 | if (lexer.peek_token ()->get_id () == LET) | |
12429 | { | |
12430 | // if let expr | |
12431 | return parse_if_let_expr (std::move (outer_attrs), tok->get_locus ()); | |
12432 | } | |
12433 | else | |
12434 | { | |
12435 | // if expr | |
12436 | return parse_if_expr (std::move (outer_attrs), tok->get_locus ()); | |
12437 | } | |
12438 | case LIFETIME: | |
12439 | return parse_labelled_loop_expr (tok, std::move (outer_attrs)); | |
12440 | case LOOP: | |
12441 | return parse_loop_expr (std::move (outer_attrs), tl::nullopt, | |
12442 | tok->get_locus ()); | |
12443 | case WHILE: | |
12444 | if (lexer.peek_token ()->get_id () == LET) | |
12445 | { | |
12446 | return parse_while_let_loop_expr (std::move (outer_attrs)); | |
12447 | } | |
12448 | else | |
12449 | { | |
12450 | return parse_while_loop_expr (std::move (outer_attrs), tl::nullopt, | |
12451 | tok->get_locus ()); | |
12452 | } | |
12453 | case FOR: | |
12454 | return parse_for_loop_expr (std::move (outer_attrs), tl::nullopt); | |
12455 | case MATCH_KW: | |
12456 | // also an expression with block | |
12457 | return parse_match_expr (std::move (outer_attrs), tok->get_locus ()); | |
12458 | case LEFT_SQUARE: | |
12459 | // array definition expr (not indexing) | |
12460 | return parse_array_expr (std::move (outer_attrs), tok->get_locus ()); | |
12461 | case UNSAFE: | |
12462 | return parse_unsafe_block_expr (std::move (outer_attrs), | |
12463 | tok->get_locus ()); | |
12464 | case BOX: | |
12465 | return parse_box_expr (std::move (outer_attrs), tok->get_locus ()); | |
12466 | case UNDERSCORE: | |
12467 | add_error ( | |
12468 | Error (tok->get_locus (), | |
12469 | "use of %qs is not allowed on the right-side of an assignment", | |
12470 | tok->get_token_description ())); | |
12471 | return nullptr; | |
12472 | default: | |
12473 | if (!restrictions.expr_can_be_null) | |
12474 | add_error (Error (tok->get_locus (), | |
12475 | "found unexpected token %qs in null denotation", | |
12476 | tok->get_token_description ())); | |
12477 | return nullptr; | |
12478 | } | |
12479 | } | |
12480 | ||
12481 | /* Called for each token that can appear in infix (between) position. Can be | |
12482 | * operators or other punctuation. Returns a function pointer to member | |
12483 | * function that implements the left denotation for the token given. */ | |
12484 | template <typename ManagedTokenSource> | |
12485 | std::unique_ptr<AST::Expr> | |
12486 | Parser<ManagedTokenSource>::left_denotation (const_TokenPtr tok, | |
12487 | std::unique_ptr<AST::Expr> left, | |
12488 | AST::AttrVec outer_attrs, | |
12489 | ParseRestrictions restrictions) | |
12490 | { | |
12491 | // Token passed in has already been skipped, so peek gives "next" token | |
12492 | switch (tok->get_id ()) | |
12493 | { | |
12494 | // FIXME: allow for outer attributes to be applied | |
12495 | case QUESTION_MARK: { | |
12496 | location_t left_locus = left->get_locus (); | |
12497 | // error propagation expression - unary postfix | |
12498 | return std::unique_ptr<AST::ErrorPropagationExpr> ( | |
12499 | new AST::ErrorPropagationExpr (std::move (left), | |
12500 | std::move (outer_attrs), left_locus)); | |
12501 | } | |
12502 | case PLUS: | |
12503 | // sum expression - binary infix | |
12504 | /*return parse_binary_plus_expr (tok, std::move (left), | |
12505 | std::move (outer_attrs), restrictions);*/ | |
12506 | return parse_arithmetic_or_logical_expr (tok, std::move (left), | |
12507 | std::move (outer_attrs), | |
12508 | ArithmeticOrLogicalOperator::ADD, | |
12509 | restrictions); | |
12510 | case MINUS: | |
12511 | // difference expression - binary infix | |
12512 | /*return parse_binary_minus_expr (tok, std::move (left), | |
12513 | std::move (outer_attrs), | |
12514 | restrictions);*/ | |
12515 | return parse_arithmetic_or_logical_expr ( | |
12516 | tok, std::move (left), std::move (outer_attrs), | |
12517 | ArithmeticOrLogicalOperator::SUBTRACT, restrictions); | |
12518 | case ASTERISK: | |
12519 | // product expression - binary infix | |
12520 | /*return parse_binary_mult_expr (tok, std::move (left), | |
12521 | std::move (outer_attrs), restrictions);*/ | |
12522 | return parse_arithmetic_or_logical_expr ( | |
12523 | tok, std::move (left), std::move (outer_attrs), | |
12524 | ArithmeticOrLogicalOperator::MULTIPLY, restrictions); | |
12525 | case DIV: | |
12526 | // quotient expression - binary infix | |
12527 | /*return parse_binary_div_expr (tok, std::move (left), | |
12528 | std::move (outer_attrs), restrictions);*/ | |
12529 | return parse_arithmetic_or_logical_expr ( | |
12530 | tok, std::move (left), std::move (outer_attrs), | |
12531 | ArithmeticOrLogicalOperator::DIVIDE, restrictions); | |
12532 | case PERCENT: | |
12533 | // modulo expression - binary infix | |
12534 | /*return parse_binary_mod_expr (tok, std::move (left), | |
12535 | std::move (outer_attrs), restrictions);*/ | |
12536 | return parse_arithmetic_or_logical_expr ( | |
12537 | tok, std::move (left), std::move (outer_attrs), | |
12538 | ArithmeticOrLogicalOperator::MODULUS, restrictions); | |
12539 | case AMP: | |
12540 | // logical or bitwise and expression - binary infix | |
12541 | /*return parse_bitwise_and_expr (tok, std::move (left), | |
12542 | std::move (outer_attrs), restrictions);*/ | |
12543 | return parse_arithmetic_or_logical_expr ( | |
12544 | tok, std::move (left), std::move (outer_attrs), | |
12545 | ArithmeticOrLogicalOperator::BITWISE_AND, restrictions); | |
12546 | case PIPE: | |
12547 | // logical or bitwise or expression - binary infix | |
12548 | /*return parse_bitwise_or_expr (tok, std::move (left), | |
12549 | std::move (outer_attrs), restrictions);*/ | |
12550 | return parse_arithmetic_or_logical_expr ( | |
12551 | tok, std::move (left), std::move (outer_attrs), | |
12552 | ArithmeticOrLogicalOperator::BITWISE_OR, restrictions); | |
12553 | case CARET: | |
12554 | // logical or bitwise xor expression - binary infix | |
12555 | /*return parse_bitwise_xor_expr (tok, std::move (left), | |
12556 | std::move (outer_attrs), restrictions);*/ | |
12557 | return parse_arithmetic_or_logical_expr ( | |
12558 | tok, std::move (left), std::move (outer_attrs), | |
12559 | ArithmeticOrLogicalOperator::BITWISE_XOR, restrictions); | |
12560 | case LEFT_SHIFT: | |
12561 | // left shift expression - binary infix | |
12562 | /*return parse_left_shift_expr (tok, std::move (left), | |
12563 | std::move (outer_attrs), restrictions);*/ | |
12564 | return parse_arithmetic_or_logical_expr ( | |
12565 | tok, std::move (left), std::move (outer_attrs), | |
12566 | ArithmeticOrLogicalOperator::LEFT_SHIFT, restrictions); | |
12567 | case RIGHT_SHIFT: | |
12568 | // right shift expression - binary infix | |
12569 | /*return parse_right_shift_expr (tok, std::move (left), | |
12570 | std::move (outer_attrs), restrictions);*/ | |
12571 | return parse_arithmetic_or_logical_expr ( | |
12572 | tok, std::move (left), std::move (outer_attrs), | |
12573 | ArithmeticOrLogicalOperator::RIGHT_SHIFT, restrictions); | |
12574 | case EQUAL_EQUAL: | |
12575 | // equal to expression - binary infix (no associativity) | |
12576 | /*return parse_binary_equal_expr (tok, std::move (left), | |
12577 | std::move (outer_attrs), | |
12578 | restrictions);*/ | |
12579 | return parse_comparison_expr (tok, std::move (left), | |
12580 | std::move (outer_attrs), | |
12581 | ComparisonOperator::EQUAL, restrictions); | |
12582 | case NOT_EQUAL: | |
12583 | // not equal to expression - binary infix (no associativity) | |
12584 | /*return parse_binary_not_equal_expr (tok, std::move (left), | |
12585 | std::move (outer_attrs), | |
12586 | restrictions);*/ | |
12587 | return parse_comparison_expr (tok, std::move (left), | |
12588 | std::move (outer_attrs), | |
12589 | ComparisonOperator::NOT_EQUAL, | |
12590 | restrictions); | |
12591 | case RIGHT_ANGLE: | |
12592 | // greater than expression - binary infix (no associativity) | |
12593 | /*return parse_binary_greater_than_expr (tok, std::move (left), | |
12594 | std::move (outer_attrs), | |
12595 | restrictions);*/ | |
12596 | return parse_comparison_expr (tok, std::move (left), | |
12597 | std::move (outer_attrs), | |
12598 | ComparisonOperator::GREATER_THAN, | |
12599 | restrictions); | |
12600 | case LEFT_ANGLE: | |
12601 | // less than expression - binary infix (no associativity) | |
12602 | /*return parse_binary_less_than_expr (tok, std::move (left), | |
12603 | std::move (outer_attrs), | |
12604 | restrictions);*/ | |
12605 | return parse_comparison_expr (tok, std::move (left), | |
12606 | std::move (outer_attrs), | |
12607 | ComparisonOperator::LESS_THAN, | |
12608 | restrictions); | |
12609 | case GREATER_OR_EQUAL: | |
12610 | // greater than or equal to expression - binary infix (no associativity) | |
12611 | /*return parse_binary_greater_equal_expr (tok, std::move (left), | |
12612 | std::move (outer_attrs), | |
12613 | restrictions);*/ | |
12614 | return parse_comparison_expr (tok, std::move (left), | |
12615 | std::move (outer_attrs), | |
12616 | ComparisonOperator::GREATER_OR_EQUAL, | |
12617 | restrictions); | |
12618 | case LESS_OR_EQUAL: | |
12619 | // less than or equal to expression - binary infix (no associativity) | |
12620 | /*return parse_binary_less_equal_expr (tok, std::move (left), | |
12621 | std::move (outer_attrs), | |
12622 | restrictions);*/ | |
12623 | return parse_comparison_expr (tok, std::move (left), | |
12624 | std::move (outer_attrs), | |
12625 | ComparisonOperator::LESS_OR_EQUAL, | |
12626 | restrictions); | |
12627 | case OR: | |
12628 | // lazy logical or expression - binary infix | |
12629 | return parse_lazy_or_expr (tok, std::move (left), std::move (outer_attrs), | |
12630 | restrictions); | |
12631 | case LOGICAL_AND: | |
12632 | // lazy logical and expression - binary infix | |
12633 | return parse_lazy_and_expr (tok, std::move (left), | |
12634 | std::move (outer_attrs), restrictions); | |
12635 | case AS: | |
12636 | /* type cast expression - kind of binary infix (RHS is actually a | |
12637 | * TypeNoBounds) */ | |
12638 | return parse_type_cast_expr (tok, std::move (left), | |
12639 | std::move (outer_attrs), restrictions); | |
12640 | case EQUAL: | |
12641 | // assignment expression - binary infix (note right-to-left | |
12642 | // associativity) | |
12643 | return parse_assig_expr (tok, std::move (left), std::move (outer_attrs), | |
12644 | restrictions); | |
12645 | case PLUS_EQ: | |
12646 | /* plus-assignment expression - binary infix (note right-to-left | |
12647 | * associativity) */ | |
12648 | /*return parse_plus_assig_expr (tok, std::move (left), | |
12649 | std::move (outer_attrs), restrictions);*/ | |
12650 | return parse_compound_assignment_expr (tok, std::move (left), | |
12651 | std::move (outer_attrs), | |
12652 | CompoundAssignmentOperator::ADD, | |
12653 | restrictions); | |
12654 | case MINUS_EQ: | |
12655 | /* minus-assignment expression - binary infix (note right-to-left | |
12656 | * associativity) */ | |
12657 | /*return parse_minus_assig_expr (tok, std::move (left), | |
12658 | std::move (outer_attrs), restrictions);*/ | |
12659 | return parse_compound_assignment_expr ( | |
12660 | tok, std::move (left), std::move (outer_attrs), | |
12661 | CompoundAssignmentOperator::SUBTRACT, restrictions); | |
12662 | case ASTERISK_EQ: | |
12663 | /* multiply-assignment expression - binary infix (note right-to-left | |
12664 | * associativity) */ | |
12665 | /*return parse_mult_assig_expr (tok, std::move (left), | |
12666 | std::move (outer_attrs), restrictions);*/ | |
12667 | return parse_compound_assignment_expr ( | |
12668 | tok, std::move (left), std::move (outer_attrs), | |
12669 | CompoundAssignmentOperator::MULTIPLY, restrictions); | |
12670 | case DIV_EQ: | |
12671 | /* division-assignment expression - binary infix (note right-to-left | |
12672 | * associativity) */ | |
12673 | /*return parse_div_assig_expr (tok, std::move (left), | |
12674 | std::move (outer_attrs), restrictions);*/ | |
12675 | return parse_compound_assignment_expr (tok, std::move (left), | |
12676 | std::move (outer_attrs), | |
12677 | CompoundAssignmentOperator::DIVIDE, | |
12678 | restrictions); | |
12679 | case PERCENT_EQ: | |
12680 | /* modulo-assignment expression - binary infix (note right-to-left | |
12681 | * associativity) */ | |
12682 | /*return parse_mod_assig_expr (tok, std::move (left), | |
12683 | std::move (outer_attrs), restrictions);*/ | |
12684 | return parse_compound_assignment_expr ( | |
12685 | tok, std::move (left), std::move (outer_attrs), | |
12686 | CompoundAssignmentOperator::MODULUS, restrictions); | |
12687 | case AMP_EQ: | |
12688 | /* bitwise and-assignment expression - binary infix (note right-to-left | |
12689 | * associativity) */ | |
12690 | /*return parse_and_assig_expr (tok, std::move (left), | |
12691 | std::move (outer_attrs), restrictions);*/ | |
12692 | return parse_compound_assignment_expr ( | |
12693 | tok, std::move (left), std::move (outer_attrs), | |
12694 | CompoundAssignmentOperator::BITWISE_AND, restrictions); | |
12695 | case PIPE_EQ: | |
12696 | /* bitwise or-assignment expression - binary infix (note right-to-left | |
12697 | * associativity) */ | |
12698 | /*return parse_or_assig_expr (tok, std::move (left), | |
12699 | std::move (outer_attrs), restrictions);*/ | |
12700 | return parse_compound_assignment_expr ( | |
12701 | tok, std::move (left), std::move (outer_attrs), | |
12702 | CompoundAssignmentOperator::BITWISE_OR, restrictions); | |
12703 | case CARET_EQ: | |
12704 | /* bitwise xor-assignment expression - binary infix (note right-to-left | |
12705 | * associativity) */ | |
12706 | /*return parse_xor_assig_expr (tok, std::move (left), | |
12707 | std::move (outer_attrs), restrictions);*/ | |
12708 | return parse_compound_assignment_expr ( | |
12709 | tok, std::move (left), std::move (outer_attrs), | |
12710 | CompoundAssignmentOperator::BITWISE_XOR, restrictions); | |
12711 | case LEFT_SHIFT_EQ: | |
12712 | /* left shift-assignment expression - binary infix (note right-to-left | |
12713 | * associativity) */ | |
12714 | /*return parse_left_shift_assig_expr (tok, std::move (left), | |
12715 | std::move (outer_attrs), | |
12716 | restrictions);*/ | |
12717 | return parse_compound_assignment_expr ( | |
12718 | tok, std::move (left), std::move (outer_attrs), | |
12719 | CompoundAssignmentOperator::LEFT_SHIFT, restrictions); | |
12720 | case RIGHT_SHIFT_EQ: | |
12721 | /* right shift-assignment expression - binary infix (note right-to-left | |
12722 | * associativity) */ | |
12723 | /*return parse_right_shift_assig_expr (tok, std::move (left), | |
12724 | std::move (outer_attrs), | |
12725 | restrictions);*/ | |
12726 | return parse_compound_assignment_expr ( | |
12727 | tok, std::move (left), std::move (outer_attrs), | |
12728 | CompoundAssignmentOperator::RIGHT_SHIFT, restrictions); | |
12729 | case DOT_DOT: | |
12730 | /* range exclusive expression - binary infix (no associativity) | |
12731 | * either "range" or "range from" */ | |
12732 | return parse_led_range_exclusive_expr (tok, std::move (left), | |
12733 | std::move (outer_attrs), | |
12734 | restrictions); | |
12735 | case DOT_DOT_EQ: | |
12736 | /* range inclusive expression - binary infix (no associativity) | |
12737 | * unambiguously RangeInclusiveExpr */ | |
12738 | return parse_range_inclusive_expr (tok, std::move (left), | |
12739 | std::move (outer_attrs), restrictions); | |
12740 | case SCOPE_RESOLUTION: | |
12741 | // path expression - binary infix? FIXME should this even be parsed | |
12742 | // here? | |
12743 | add_error ( | |
12744 | Error (tok->get_locus (), | |
12745 | "found scope resolution operator in left denotation " | |
12746 | "function - this should probably be handled elsewhere")); | |
12747 | ||
12748 | return nullptr; | |
12749 | case DOT: { | |
12750 | /* field expression or method call - relies on parentheses after next | |
12751 | * identifier or await if token after is "await" (unary postfix) or | |
12752 | * tuple index if token after is a decimal int literal */ | |
12753 | ||
12754 | const_TokenPtr next_tok = lexer.peek_token (); | |
12755 | if (next_tok->get_id () == IDENTIFIER | |
12756 | && next_tok->get_str () == Values::Keywords::AWAIT) | |
12757 | { | |
12758 | // await expression | |
12759 | return parse_await_expr (tok, std::move (left), | |
12760 | std::move (outer_attrs)); | |
12761 | } | |
12762 | else if (next_tok->get_id () == INT_LITERAL) | |
12763 | { | |
12764 | // tuple index expression - TODO check for decimal int literal | |
12765 | return parse_tuple_index_expr (tok, std::move (left), | |
12766 | std::move (outer_attrs), | |
12767 | restrictions); | |
12768 | } | |
12769 | else if (next_tok->get_id () == FLOAT_LITERAL) | |
12770 | { | |
12771 | // Lexer has misidentified a tuple index as a float literal | |
12772 | // eg: `(x, (y, z)).1.0` -> 1.0 has been identified as a float | |
12773 | // literal. This means we should split it into three new separate | |
12774 | // tokens, the first tuple index, the dot and the second tuple | |
12775 | // index. | |
12776 | auto current_loc = next_tok->get_locus (); | |
12777 | auto str = next_tok->get_str (); | |
12778 | auto dot_pos = str.find ("."); | |
12779 | auto prefix = str.substr (0, dot_pos); | |
12780 | auto suffix = str.substr (dot_pos + 1); | |
12781 | if (dot_pos == str.size () - 1) | |
12782 | lexer.split_current_token ( | |
12783 | {Token::make_int (current_loc, std::move (prefix), | |
12784 | CORETYPE_PURE_DECIMAL), | |
12785 | Token::make (DOT, current_loc + 1)}); | |
12786 | else | |
12787 | lexer.split_current_token ( | |
12788 | {Token::make_int (current_loc, std::move (prefix), | |
12789 | CORETYPE_PURE_DECIMAL), | |
12790 | Token::make (DOT, current_loc + 1), | |
12791 | Token::make_int (current_loc + 2, std::move (suffix), | |
12792 | CORETYPE_PURE_DECIMAL)}); | |
12793 | return parse_tuple_index_expr (tok, std::move (left), | |
12794 | std::move (outer_attrs), | |
12795 | restrictions); | |
12796 | } | |
12797 | else if (next_tok->get_id () == IDENTIFIER | |
12798 | && lexer.peek_token (1)->get_id () != LEFT_PAREN | |
12799 | && lexer.peek_token (1)->get_id () != SCOPE_RESOLUTION) | |
12800 | { | |
12801 | /* field expression (or should be) - FIXME: scope resolution right | |
12802 | * after identifier should always be method, I'm pretty sure */ | |
12803 | return parse_field_access_expr (tok, std::move (left), | |
12804 | std::move (outer_attrs), | |
12805 | restrictions); | |
12806 | } | |
12807 | else | |
12808 | { | |
12809 | // method call (probably) | |
12810 | return parse_method_call_expr (tok, std::move (left), | |
12811 | std::move (outer_attrs), | |
12812 | restrictions); | |
12813 | } | |
12814 | } | |
12815 | case LEFT_PAREN: | |
12816 | // function call - method call is based on dot notation first | |
12817 | return parse_function_call_expr (tok, std::move (left), | |
12818 | std::move (outer_attrs), restrictions); | |
12819 | case LEFT_SQUARE: | |
12820 | // array or slice index expression (pseudo binary infix) | |
12821 | return parse_index_expr (tok, std::move (left), std::move (outer_attrs), | |
12822 | restrictions); | |
12823 | case FLOAT_LITERAL: | |
12824 | /* HACK: get around lexer mis-identifying '.0' or '.1' or whatever as a | |
12825 | * float literal - TODO does this happen anymore? It shouldn't. */ | |
12826 | return parse_tuple_index_expr_float (tok, std::move (left), | |
12827 | std::move (outer_attrs), | |
12828 | restrictions); | |
12829 | default: | |
12830 | add_error (Error (tok->get_locus (), | |
12831 | "found unexpected token %qs in left denotation", | |
12832 | tok->get_token_description ())); | |
12833 | ||
12834 | return nullptr; | |
12835 | } | |
12836 | } | |
12837 | ||
12838 | /* Returns the left binding power for the given ArithmeticOrLogicalExpr type. | |
12839 | * TODO make constexpr? Would that even do anything useful? */ | |
12840 | inline binding_powers | |
12841 | get_lbp_for_arithmetic_or_logical_expr ( | |
12842 | AST::ArithmeticOrLogicalExpr::ExprType expr_type) | |
12843 | { | |
12844 | switch (expr_type) | |
12845 | { | |
12846 | case ArithmeticOrLogicalOperator::ADD: | |
12847 | return LBP_PLUS; | |
12848 | case ArithmeticOrLogicalOperator::SUBTRACT: | |
12849 | return LBP_MINUS; | |
12850 | case ArithmeticOrLogicalOperator::MULTIPLY: | |
12851 | return LBP_MUL; | |
12852 | case ArithmeticOrLogicalOperator::DIVIDE: | |
12853 | return LBP_DIV; | |
12854 | case ArithmeticOrLogicalOperator::MODULUS: | |
12855 | return LBP_MOD; | |
12856 | case ArithmeticOrLogicalOperator::BITWISE_AND: | |
12857 | return LBP_AMP; | |
12858 | case ArithmeticOrLogicalOperator::BITWISE_OR: | |
12859 | return LBP_PIPE; | |
12860 | case ArithmeticOrLogicalOperator::BITWISE_XOR: | |
12861 | return LBP_CARET; | |
12862 | case ArithmeticOrLogicalOperator::LEFT_SHIFT: | |
12863 | return LBP_L_SHIFT; | |
12864 | case ArithmeticOrLogicalOperator::RIGHT_SHIFT: | |
12865 | return LBP_R_SHIFT; | |
12866 | default: | |
12867 | // WTF? should not happen, this is an error | |
12868 | rust_unreachable (); | |
12869 | ||
12870 | return LBP_PLUS; | |
12871 | } | |
12872 | } | |
12873 | ||
12874 | // Parses an arithmetic or logical expression (with Pratt parsing). | |
12875 | template <typename ManagedTokenSource> | |
12876 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
12877 | Parser<ManagedTokenSource>::parse_arithmetic_or_logical_expr ( | |
12878 | const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec, | |
12879 | AST::ArithmeticOrLogicalExpr::ExprType expr_type, | |
12880 | ParseRestrictions restrictions) | |
12881 | { | |
12882 | // parse RHS (as tok has already been consumed in parse_expression) | |
12883 | std::unique_ptr<AST::Expr> right | |
12884 | = parse_expr (get_lbp_for_arithmetic_or_logical_expr (expr_type), | |
12885 | AST::AttrVec (), restrictions); | |
12886 | if (right == nullptr) | |
12887 | return nullptr; | |
12888 | ||
12889 | // TODO: check types. actually, do so during semantic analysis | |
12890 | location_t locus = left->get_locus (); | |
12891 | ||
12892 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
12893 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
12894 | expr_type, locus)); | |
12895 | } | |
12896 | ||
12897 | // Parses a binary addition expression (with Pratt parsing). | |
12898 | template <typename ManagedTokenSource> | |
12899 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
12900 | Parser<ManagedTokenSource>::parse_binary_plus_expr ( | |
12901 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
12902 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
12903 | { | |
12904 | // parse RHS (as tok has already been consumed in parse_expression) | |
12905 | std::unique_ptr<AST::Expr> right | |
12906 | = parse_expr (LBP_PLUS, AST::AttrVec (), restrictions); | |
12907 | if (right == nullptr) | |
12908 | return nullptr; | |
12909 | ||
12910 | // TODO: check types. actually, do so during semantic analysis | |
12911 | location_t locus = left->get_locus (); | |
12912 | ||
12913 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
12914 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
12915 | ArithmeticOrLogicalOperator::ADD, locus)); | |
12916 | } | |
12917 | ||
12918 | // Parses a binary subtraction expression (with Pratt parsing). | |
12919 | template <typename ManagedTokenSource> | |
12920 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
12921 | Parser<ManagedTokenSource>::parse_binary_minus_expr ( | |
12922 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
12923 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
12924 | { | |
12925 | // parse RHS (as tok has already been consumed in parse_expression) | |
12926 | std::unique_ptr<AST::Expr> right | |
12927 | = parse_expr (LBP_MINUS, AST::AttrVec (), restrictions); | |
12928 | if (right == nullptr) | |
12929 | return nullptr; | |
12930 | ||
12931 | // TODO: check types. actually, do so during semantic analysis | |
12932 | location_t locus = left->get_locus (); | |
12933 | ||
12934 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
12935 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
12936 | ArithmeticOrLogicalOperator::SUBTRACT, | |
12937 | locus)); | |
12938 | } | |
12939 | ||
12940 | // Parses a binary multiplication expression (with Pratt parsing). | |
12941 | template <typename ManagedTokenSource> | |
12942 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
12943 | Parser<ManagedTokenSource>::parse_binary_mult_expr ( | |
12944 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
12945 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
12946 | { | |
12947 | // parse RHS (as tok has already been consumed in parse_expression) | |
12948 | std::unique_ptr<AST::Expr> right | |
12949 | = parse_expr (LBP_MUL, AST::AttrVec (), restrictions); | |
12950 | if (right == nullptr) | |
12951 | return nullptr; | |
12952 | ||
12953 | // TODO: check types. actually, do so during semantic analysis | |
12954 | location_t locus = left->get_locus (); | |
12955 | ||
12956 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
12957 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
12958 | ArithmeticOrLogicalOperator::MULTIPLY, | |
12959 | locus)); | |
12960 | } | |
12961 | ||
12962 | // Parses a binary division expression (with Pratt parsing). | |
12963 | template <typename ManagedTokenSource> | |
12964 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
12965 | Parser<ManagedTokenSource>::parse_binary_div_expr ( | |
12966 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
12967 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
12968 | { | |
12969 | // parse RHS (as tok has already been consumed in parse_expression) | |
12970 | std::unique_ptr<AST::Expr> right | |
12971 | = parse_expr (LBP_DIV, AST::AttrVec (), restrictions); | |
12972 | if (right == nullptr) | |
12973 | return nullptr; | |
12974 | ||
12975 | // TODO: check types. actually, do so during semantic analysis | |
12976 | location_t locus = left->get_locus (); | |
12977 | ||
12978 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
12979 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
12980 | ArithmeticOrLogicalOperator::DIVIDE, | |
12981 | locus)); | |
12982 | } | |
12983 | ||
12984 | // Parses a binary modulo expression (with Pratt parsing). | |
12985 | template <typename ManagedTokenSource> | |
12986 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
12987 | Parser<ManagedTokenSource>::parse_binary_mod_expr ( | |
12988 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
12989 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
12990 | { | |
12991 | // parse RHS (as tok has already been consumed in parse_expression) | |
12992 | std::unique_ptr<AST::Expr> right | |
12993 | = parse_expr (LBP_MOD, AST::AttrVec (), restrictions); | |
12994 | if (right == nullptr) | |
12995 | return nullptr; | |
12996 | ||
12997 | // TODO: check types. actually, do so during semantic analysis | |
12998 | location_t locus = left->get_locus (); | |
12999 | ||
13000 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13001 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13002 | ArithmeticOrLogicalOperator::MODULUS, | |
13003 | locus)); | |
13004 | } | |
13005 | ||
13006 | /* Parses a binary bitwise (or eager logical) and expression (with Pratt | |
13007 | * parsing). */ | |
13008 | template <typename ManagedTokenSource> | |
13009 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13010 | Parser<ManagedTokenSource>::parse_bitwise_and_expr ( | |
13011 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13012 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13013 | { | |
13014 | // parse RHS (as tok has already been consumed in parse_expression) | |
13015 | std::unique_ptr<AST::Expr> right | |
13016 | = parse_expr (LBP_AMP, AST::AttrVec (), restrictions); | |
13017 | if (right == nullptr) | |
13018 | return nullptr; | |
13019 | ||
13020 | // TODO: check types. actually, do so during semantic analysis | |
13021 | location_t locus = left->get_locus (); | |
13022 | ||
13023 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13024 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13025 | ArithmeticOrLogicalOperator::BITWISE_AND, | |
13026 | locus)); | |
13027 | } | |
13028 | ||
13029 | /* Parses a binary bitwise (or eager logical) or expression (with Pratt | |
13030 | * parsing). */ | |
13031 | template <typename ManagedTokenSource> | |
13032 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13033 | Parser<ManagedTokenSource>::parse_bitwise_or_expr ( | |
13034 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13035 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13036 | { | |
13037 | // parse RHS (as tok has already been consumed in parse_expression) | |
13038 | std::unique_ptr<AST::Expr> right | |
13039 | = parse_expr (LBP_PIPE, AST::AttrVec (), restrictions); | |
13040 | if (right == nullptr) | |
13041 | return nullptr; | |
13042 | ||
13043 | // TODO: check types. actually, do so during semantic analysis | |
13044 | location_t locus = left->get_locus (); | |
13045 | ||
13046 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13047 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13048 | ArithmeticOrLogicalOperator::BITWISE_OR, | |
13049 | locus)); | |
13050 | } | |
13051 | ||
13052 | /* Parses a binary bitwise (or eager logical) xor expression (with Pratt | |
13053 | * parsing). */ | |
13054 | template <typename ManagedTokenSource> | |
13055 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13056 | Parser<ManagedTokenSource>::parse_bitwise_xor_expr ( | |
13057 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13058 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13059 | { | |
13060 | // parse RHS (as tok has already been consumed in parse_expression) | |
13061 | std::unique_ptr<AST::Expr> right | |
13062 | = parse_expr (LBP_CARET, AST::AttrVec (), restrictions); | |
13063 | if (right == nullptr) | |
13064 | return nullptr; | |
13065 | ||
13066 | // TODO: check types. actually, do so during semantic analysis | |
13067 | location_t locus = left->get_locus (); | |
13068 | ||
13069 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13070 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13071 | ArithmeticOrLogicalOperator::BITWISE_XOR, | |
13072 | locus)); | |
13073 | } | |
13074 | ||
13075 | // Parses a binary left shift expression (with Pratt parsing). | |
13076 | template <typename ManagedTokenSource> | |
13077 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13078 | Parser<ManagedTokenSource>::parse_left_shift_expr ( | |
13079 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13080 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13081 | { | |
13082 | // parse RHS (as tok has already been consumed in parse_expression) | |
13083 | std::unique_ptr<AST::Expr> right | |
13084 | = parse_expr (LBP_L_SHIFT, AST::AttrVec (), restrictions); | |
13085 | if (right == nullptr) | |
13086 | return nullptr; | |
13087 | ||
13088 | // TODO: check types. actually, do so during semantic analysis | |
13089 | location_t locus = left->get_locus (); | |
13090 | ||
13091 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13092 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13093 | ArithmeticOrLogicalOperator::LEFT_SHIFT, | |
13094 | locus)); | |
13095 | } | |
13096 | ||
13097 | // Parses a binary right shift expression (with Pratt parsing). | |
13098 | template <typename ManagedTokenSource> | |
13099 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13100 | Parser<ManagedTokenSource>::parse_right_shift_expr ( | |
13101 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13102 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13103 | { | |
13104 | // parse RHS (as tok has already been consumed in parse_expression) | |
13105 | std::unique_ptr<AST::Expr> right | |
13106 | = parse_expr (LBP_R_SHIFT, AST::AttrVec (), restrictions); | |
13107 | if (right == nullptr) | |
13108 | return nullptr; | |
13109 | ||
13110 | // TODO: check types. actually, do so during semantic analysis | |
13111 | location_t locus = left->get_locus (); | |
13112 | ||
13113 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13114 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13115 | ArithmeticOrLogicalOperator::RIGHT_SHIFT, | |
13116 | locus)); | |
13117 | } | |
13118 | ||
13119 | /* Returns the left binding power for the given ComparisonExpr type. | |
13120 | * TODO make constexpr? Would that even do anything useful? */ | |
13121 | inline binding_powers | |
13122 | get_lbp_for_comparison_expr (AST::ComparisonExpr::ExprType expr_type) | |
13123 | { | |
13124 | switch (expr_type) | |
13125 | { | |
13126 | case ComparisonOperator::EQUAL: | |
13127 | return LBP_EQUAL; | |
13128 | case ComparisonOperator::NOT_EQUAL: | |
13129 | return LBP_NOT_EQUAL; | |
13130 | case ComparisonOperator::GREATER_THAN: | |
13131 | return LBP_GREATER_THAN; | |
13132 | case ComparisonOperator::LESS_THAN: | |
13133 | return LBP_SMALLER_THAN; | |
13134 | case ComparisonOperator::GREATER_OR_EQUAL: | |
13135 | return LBP_GREATER_EQUAL; | |
13136 | case ComparisonOperator::LESS_OR_EQUAL: | |
13137 | return LBP_SMALLER_EQUAL; | |
13138 | default: | |
13139 | // WTF? should not happen, this is an error | |
13140 | rust_unreachable (); | |
13141 | ||
13142 | return LBP_EQUAL; | |
13143 | } | |
13144 | } | |
13145 | ||
13146 | /* Parses a ComparisonExpr of given type and LBP. TODO find a way to only | |
13147 | * specify one and have the other looked up - e.g. specify ExprType and | |
13148 | * binding power is looked up? */ | |
13149 | template <typename ManagedTokenSource> | |
13150 | std::unique_ptr<AST::ComparisonExpr> | |
13151 | Parser<ManagedTokenSource>::parse_comparison_expr ( | |
13152 | const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec, | |
13153 | AST::ComparisonExpr::ExprType expr_type, ParseRestrictions restrictions) | |
13154 | { | |
13155 | // parse RHS (as tok has already been consumed in parse_expression) | |
13156 | std::unique_ptr<AST::Expr> right | |
13157 | = parse_expr (get_lbp_for_comparison_expr (expr_type), AST::AttrVec (), | |
13158 | restrictions); | |
13159 | if (right == nullptr) | |
13160 | return nullptr; | |
13161 | ||
13162 | // TODO: check types. actually, do so during semantic analysis | |
13163 | location_t locus = left->get_locus (); | |
13164 | ||
13165 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13166 | new AST::ComparisonExpr (std::move (left), std::move (right), expr_type, | |
13167 | locus)); | |
13168 | } | |
13169 | ||
13170 | // Parses a binary equal to expression (with Pratt parsing). | |
13171 | template <typename ManagedTokenSource> | |
13172 | std::unique_ptr<AST::ComparisonExpr> | |
13173 | Parser<ManagedTokenSource>::parse_binary_equal_expr ( | |
13174 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13175 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13176 | { | |
13177 | // parse RHS (as tok has already been consumed in parse_expression) | |
13178 | std::unique_ptr<AST::Expr> right | |
13179 | = parse_expr (LBP_EQUAL, AST::AttrVec (), restrictions); | |
13180 | if (right == nullptr) | |
13181 | return nullptr; | |
13182 | ||
13183 | // TODO: check types. actually, do so during semantic analysis | |
13184 | location_t locus = left->get_locus (); | |
13185 | ||
13186 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13187 | new AST::ComparisonExpr (std::move (left), std::move (right), | |
13188 | ComparisonOperator::EQUAL, locus)); | |
13189 | } | |
13190 | ||
13191 | // Parses a binary not equal to expression (with Pratt parsing). | |
13192 | template <typename ManagedTokenSource> | |
13193 | std::unique_ptr<AST::ComparisonExpr> | |
13194 | Parser<ManagedTokenSource>::parse_binary_not_equal_expr ( | |
13195 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13196 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13197 | { | |
13198 | // parse RHS (as tok has already been consumed in parse_expression) | |
13199 | std::unique_ptr<AST::Expr> right | |
13200 | = parse_expr (LBP_NOT_EQUAL, AST::AttrVec (), restrictions); | |
13201 | if (right == nullptr) | |
13202 | return nullptr; | |
13203 | ||
13204 | // TODO: check types. actually, do so during semantic analysis | |
13205 | location_t locus = left->get_locus (); | |
13206 | ||
13207 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13208 | new AST::ComparisonExpr (std::move (left), std::move (right), | |
13209 | ComparisonOperator::NOT_EQUAL, locus)); | |
13210 | } | |
13211 | ||
13212 | // Parses a binary greater than expression (with Pratt parsing). | |
13213 | template <typename ManagedTokenSource> | |
13214 | std::unique_ptr<AST::ComparisonExpr> | |
13215 | Parser<ManagedTokenSource>::parse_binary_greater_than_expr ( | |
13216 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13217 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13218 | { | |
13219 | // parse RHS (as tok has already been consumed in parse_expression) | |
13220 | std::unique_ptr<AST::Expr> right | |
13221 | = parse_expr (LBP_GREATER_THAN, AST::AttrVec (), restrictions); | |
13222 | if (right == nullptr) | |
13223 | return nullptr; | |
13224 | ||
13225 | // TODO: check types. actually, do so during semantic analysis | |
13226 | location_t locus = left->get_locus (); | |
13227 | ||
13228 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13229 | new AST::ComparisonExpr (std::move (left), std::move (right), | |
13230 | ComparisonOperator::GREATER_THAN, locus)); | |
13231 | } | |
13232 | ||
13233 | // Parses a binary less than expression (with Pratt parsing). | |
13234 | template <typename ManagedTokenSource> | |
13235 | std::unique_ptr<AST::ComparisonExpr> | |
13236 | Parser<ManagedTokenSource>::parse_binary_less_than_expr ( | |
13237 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13238 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13239 | { | |
13240 | // parse RHS (as tok has already been consumed in parse_expression) | |
13241 | std::unique_ptr<AST::Expr> right | |
13242 | = parse_expr (LBP_SMALLER_THAN, AST::AttrVec (), restrictions); | |
13243 | if (right == nullptr) | |
13244 | return nullptr; | |
13245 | ||
13246 | // TODO: check types. actually, do so during semantic analysis | |
13247 | location_t locus = left->get_locus (); | |
13248 | ||
13249 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13250 | new AST::ComparisonExpr (std::move (left), std::move (right), | |
13251 | ComparisonOperator::LESS_THAN, locus)); | |
13252 | } | |
13253 | ||
13254 | // Parses a binary greater than or equal to expression (with Pratt parsing). | |
13255 | template <typename ManagedTokenSource> | |
13256 | std::unique_ptr<AST::ComparisonExpr> | |
13257 | Parser<ManagedTokenSource>::parse_binary_greater_equal_expr ( | |
13258 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13259 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13260 | { | |
13261 | // parse RHS (as tok has already been consumed in parse_expression) | |
13262 | std::unique_ptr<AST::Expr> right | |
13263 | = parse_expr (LBP_GREATER_EQUAL, AST::AttrVec (), restrictions); | |
13264 | if (right == nullptr) | |
13265 | return nullptr; | |
13266 | ||
13267 | // TODO: check types. actually, do so during semantic analysis | |
13268 | location_t locus = left->get_locus (); | |
13269 | ||
13270 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13271 | new AST::ComparisonExpr (std::move (left), std::move (right), | |
13272 | ComparisonOperator::GREATER_OR_EQUAL, locus)); | |
13273 | } | |
13274 | ||
13275 | // Parses a binary less than or equal to expression (with Pratt parsing). | |
13276 | template <typename ManagedTokenSource> | |
13277 | std::unique_ptr<AST::ComparisonExpr> | |
13278 | Parser<ManagedTokenSource>::parse_binary_less_equal_expr ( | |
13279 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13280 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13281 | { | |
13282 | // parse RHS (as tok has already been consumed in parse_expression) | |
13283 | std::unique_ptr<AST::Expr> right | |
13284 | = parse_expr (LBP_SMALLER_EQUAL, AST::AttrVec (), restrictions); | |
13285 | if (right == nullptr) | |
13286 | return nullptr; | |
13287 | ||
13288 | // TODO: check types. actually, do so during semantic analysis | |
13289 | location_t locus = left->get_locus (); | |
13290 | ||
13291 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13292 | new AST::ComparisonExpr (std::move (left), std::move (right), | |
13293 | ComparisonOperator::LESS_OR_EQUAL, locus)); | |
13294 | } | |
13295 | ||
13296 | // Parses a binary lazy boolean or expression (with Pratt parsing). | |
13297 | template <typename ManagedTokenSource> | |
13298 | std::unique_ptr<AST::LazyBooleanExpr> | |
13299 | Parser<ManagedTokenSource>::parse_lazy_or_expr ( | |
13300 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13301 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13302 | { | |
13303 | // parse RHS (as tok has already been consumed in parse_expression) | |
13304 | std::unique_ptr<AST::Expr> right | |
13305 | = parse_expr (LBP_LOGICAL_OR, AST::AttrVec (), restrictions); | |
13306 | if (right == nullptr) | |
13307 | return nullptr; | |
13308 | ||
13309 | // TODO: check types. actually, do so during semantic analysis | |
13310 | location_t locus = left->get_locus (); | |
13311 | ||
13312 | return std::unique_ptr<AST::LazyBooleanExpr> ( | |
13313 | new AST::LazyBooleanExpr (std::move (left), std::move (right), | |
13314 | LazyBooleanOperator::LOGICAL_OR, locus)); | |
13315 | } | |
13316 | ||
13317 | // Parses a binary lazy boolean and expression (with Pratt parsing). | |
13318 | template <typename ManagedTokenSource> | |
13319 | std::unique_ptr<AST::LazyBooleanExpr> | |
13320 | Parser<ManagedTokenSource>::parse_lazy_and_expr ( | |
13321 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13322 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13323 | { | |
13324 | // parse RHS (as tok has already been consumed in parse_expression) | |
13325 | std::unique_ptr<AST::Expr> right | |
13326 | = parse_expr (LBP_LOGICAL_AND, AST::AttrVec (), restrictions); | |
13327 | if (right == nullptr) | |
13328 | return nullptr; | |
13329 | ||
13330 | // TODO: check types. actually, do so during semantic analysis | |
13331 | location_t locus = left->get_locus (); | |
13332 | ||
13333 | return std::unique_ptr<AST::LazyBooleanExpr> ( | |
13334 | new AST::LazyBooleanExpr (std::move (left), std::move (right), | |
13335 | LazyBooleanOperator::LOGICAL_AND, locus)); | |
13336 | } | |
13337 | ||
13338 | // Parses a pseudo-binary infix type cast expression (with Pratt parsing). | |
13339 | template <typename ManagedTokenSource> | |
13340 | std::unique_ptr<AST::TypeCastExpr> | |
13341 | Parser<ManagedTokenSource>::parse_type_cast_expr ( | |
13342 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> expr_to_cast, | |
13343 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, | |
13344 | ParseRestrictions restrictions ATTRIBUTE_UNUSED) | |
13345 | { | |
13346 | // parse RHS (as tok has already been consumed in parse_expression) | |
13347 | std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds (); | |
13348 | if (type == nullptr) | |
13349 | return nullptr; | |
13350 | // FIXME: how do I get precedence put in here? | |
13351 | ||
13352 | // TODO: check types. actually, do so during semantic analysis | |
13353 | location_t locus = expr_to_cast->get_locus (); | |
13354 | ||
13355 | return std::unique_ptr<AST::TypeCastExpr> ( | |
13356 | new AST::TypeCastExpr (std::move (expr_to_cast), std::move (type), locus)); | |
13357 | } | |
13358 | ||
13359 | // Parses a binary assignment expression (with Pratt parsing). | |
13360 | template <typename ManagedTokenSource> | |
13361 | std::unique_ptr<AST::AssignmentExpr> | |
13362 | Parser<ManagedTokenSource>::parse_assig_expr ( | |
13363 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13364 | AST::AttrVec outer_attrs, ParseRestrictions restrictions) | |
13365 | { | |
13366 | // parse RHS (as tok has already been consumed in parse_expression) | |
13367 | std::unique_ptr<AST::Expr> right | |
13368 | = parse_expr (LBP_ASSIG - 1, AST::AttrVec (), restrictions); | |
13369 | if (right == nullptr) | |
13370 | return nullptr; | |
13371 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13372 | ||
13373 | // TODO: check types. actually, do so during semantic analysis | |
13374 | location_t locus = left->get_locus (); | |
13375 | ||
13376 | return std::unique_ptr<AST::AssignmentExpr> ( | |
13377 | new AST::AssignmentExpr (std::move (left), std::move (right), | |
13378 | std::move (outer_attrs), locus)); | |
13379 | } | |
13380 | ||
13381 | /* Returns the left binding power for the given CompoundAssignmentExpr type. | |
13382 | * TODO make constexpr? Would that even do anything useful? */ | |
13383 | inline binding_powers | |
13384 | get_lbp_for_compound_assignment_expr ( | |
13385 | AST::CompoundAssignmentExpr::ExprType expr_type) | |
13386 | { | |
13387 | switch (expr_type) | |
13388 | { | |
13389 | case CompoundAssignmentOperator::ADD: | |
13390 | return LBP_PLUS; | |
13391 | case CompoundAssignmentOperator::SUBTRACT: | |
13392 | return LBP_MINUS; | |
13393 | case CompoundAssignmentOperator::MULTIPLY: | |
13394 | return LBP_MUL; | |
13395 | case CompoundAssignmentOperator::DIVIDE: | |
13396 | return LBP_DIV; | |
13397 | case CompoundAssignmentOperator::MODULUS: | |
13398 | return LBP_MOD; | |
13399 | case CompoundAssignmentOperator::BITWISE_AND: | |
13400 | return LBP_AMP; | |
13401 | case CompoundAssignmentOperator::BITWISE_OR: | |
13402 | return LBP_PIPE; | |
13403 | case CompoundAssignmentOperator::BITWISE_XOR: | |
13404 | return LBP_CARET; | |
13405 | case CompoundAssignmentOperator::LEFT_SHIFT: | |
13406 | return LBP_L_SHIFT; | |
13407 | case CompoundAssignmentOperator::RIGHT_SHIFT: | |
13408 | return LBP_R_SHIFT; | |
13409 | default: | |
13410 | // WTF? should not happen, this is an error | |
13411 | rust_unreachable (); | |
13412 | ||
13413 | return LBP_PLUS; | |
13414 | } | |
13415 | } | |
13416 | ||
13417 | // Parses a compound assignment expression (with Pratt parsing). | |
13418 | template <typename ManagedTokenSource> | |
13419 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13420 | Parser<ManagedTokenSource>::parse_compound_assignment_expr ( | |
13421 | const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec, | |
13422 | AST::CompoundAssignmentExpr::ExprType expr_type, | |
13423 | ParseRestrictions restrictions) | |
13424 | { | |
13425 | // parse RHS (as tok has already been consumed in parse_expression) | |
13426 | std::unique_ptr<AST::Expr> right | |
13427 | = parse_expr (get_lbp_for_compound_assignment_expr (expr_type) - 1, | |
13428 | AST::AttrVec (), restrictions); | |
13429 | if (right == nullptr) | |
13430 | return nullptr; | |
13431 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13432 | ||
13433 | // TODO: check types. actually, do so during semantic analysis | |
13434 | location_t locus = left->get_locus (); | |
13435 | ||
13436 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13437 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13438 | expr_type, locus)); | |
13439 | } | |
13440 | ||
13441 | // Parses a binary add-assignment expression (with Pratt parsing). | |
13442 | template <typename ManagedTokenSource> | |
13443 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13444 | Parser<ManagedTokenSource>::parse_plus_assig_expr ( | |
13445 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13446 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13447 | { | |
13448 | // parse RHS (as tok has already been consumed in parse_expression) | |
13449 | std::unique_ptr<AST::Expr> right | |
13450 | = parse_expr (LBP_PLUS_ASSIG - 1, AST::AttrVec (), restrictions); | |
13451 | if (right == nullptr) | |
13452 | return nullptr; | |
13453 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13454 | ||
13455 | // TODO: check types. actually, do so during semantic analysis | |
13456 | location_t locus = left->get_locus (); | |
13457 | ||
13458 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13459 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13460 | CompoundAssignmentOperator::ADD, locus)); | |
13461 | } | |
13462 | ||
13463 | // Parses a binary minus-assignment expression (with Pratt parsing). | |
13464 | template <typename ManagedTokenSource> | |
13465 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13466 | Parser<ManagedTokenSource>::parse_minus_assig_expr ( | |
13467 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13468 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13469 | { | |
13470 | // parse RHS (as tok has already been consumed in parse_expression) | |
13471 | std::unique_ptr<AST::Expr> right | |
13472 | = parse_expr (LBP_MINUS_ASSIG - 1, AST::AttrVec (), restrictions); | |
13473 | if (right == nullptr) | |
13474 | return nullptr; | |
13475 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13476 | ||
13477 | // TODO: check types. actually, do so during semantic analysis | |
13478 | location_t locus = left->get_locus (); | |
13479 | ||
13480 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13481 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13482 | CompoundAssignmentOperator::SUBTRACT, | |
13483 | locus)); | |
13484 | } | |
13485 | ||
13486 | // Parses a binary multiplication-assignment expression (with Pratt parsing). | |
13487 | template <typename ManagedTokenSource> | |
13488 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13489 | Parser<ManagedTokenSource>::parse_mult_assig_expr ( | |
13490 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13491 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13492 | { | |
13493 | // parse RHS (as tok has already been consumed in parse_expression) | |
13494 | std::unique_ptr<AST::Expr> right | |
13495 | = parse_expr (LBP_MULT_ASSIG - 1, AST::AttrVec (), restrictions); | |
13496 | if (right == nullptr) | |
13497 | return nullptr; | |
13498 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13499 | ||
13500 | // TODO: check types. actually, do so during semantic analysis | |
13501 | location_t locus = left->get_locus (); | |
13502 | ||
13503 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13504 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13505 | CompoundAssignmentOperator::MULTIPLY, | |
13506 | locus)); | |
13507 | } | |
13508 | ||
13509 | // Parses a binary division-assignment expression (with Pratt parsing). | |
13510 | template <typename ManagedTokenSource> | |
13511 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13512 | Parser<ManagedTokenSource>::parse_div_assig_expr ( | |
13513 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13514 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13515 | { | |
13516 | // parse RHS (as tok has already been consumed in parse_expression) | |
13517 | std::unique_ptr<AST::Expr> right | |
13518 | = parse_expr (LBP_DIV_ASSIG - 1, AST::AttrVec (), restrictions); | |
13519 | if (right == nullptr) | |
13520 | return nullptr; | |
13521 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13522 | ||
13523 | // TODO: check types. actually, do so during semantic analysis | |
13524 | location_t locus = left->get_locus (); | |
13525 | ||
13526 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13527 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13528 | CompoundAssignmentOperator::DIVIDE, | |
13529 | locus)); | |
13530 | } | |
13531 | ||
13532 | // Parses a binary modulo-assignment expression (with Pratt parsing). | |
13533 | template <typename ManagedTokenSource> | |
13534 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13535 | Parser<ManagedTokenSource>::parse_mod_assig_expr ( | |
13536 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13537 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13538 | { | |
13539 | // parse RHS (as tok has already been consumed in parse_expression) | |
13540 | std::unique_ptr<AST::Expr> right | |
13541 | = parse_expr (LBP_MOD_ASSIG - 1, AST::AttrVec (), restrictions); | |
13542 | if (right == nullptr) | |
13543 | return nullptr; | |
13544 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13545 | ||
13546 | // TODO: check types. actually, do so during semantic analysis | |
13547 | location_t locus = left->get_locus (); | |
13548 | ||
13549 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13550 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13551 | CompoundAssignmentOperator::MODULUS, | |
13552 | locus)); | |
13553 | } | |
13554 | ||
13555 | // Parses a binary and-assignment expression (with Pratt parsing). | |
13556 | template <typename ManagedTokenSource> | |
13557 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13558 | Parser<ManagedTokenSource>::parse_and_assig_expr ( | |
13559 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13560 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13561 | { | |
13562 | // parse RHS (as tok has already been consumed in parse_expression) | |
13563 | std::unique_ptr<AST::Expr> right | |
13564 | = parse_expr (LBP_AMP_ASSIG - 1, AST::AttrVec (), restrictions); | |
13565 | if (right == nullptr) | |
13566 | return nullptr; | |
13567 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13568 | ||
13569 | // TODO: check types. actually, do so during semantic analysis | |
13570 | location_t locus = left->get_locus (); | |
13571 | ||
13572 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13573 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13574 | CompoundAssignmentOperator::BITWISE_AND, | |
13575 | locus)); | |
13576 | } | |
13577 | ||
13578 | // Parses a binary or-assignment expression (with Pratt parsing). | |
13579 | template <typename ManagedTokenSource> | |
13580 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13581 | Parser<ManagedTokenSource>::parse_or_assig_expr ( | |
13582 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13583 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13584 | { | |
13585 | // parse RHS (as tok has already been consumed in parse_expression) | |
13586 | std::unique_ptr<AST::Expr> right | |
13587 | = parse_expr (LBP_PIPE_ASSIG - 1, AST::AttrVec (), restrictions); | |
13588 | if (right == nullptr) | |
13589 | return nullptr; | |
13590 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13591 | ||
13592 | // TODO: check types. actually, do so during semantic analysis | |
13593 | location_t locus = left->get_locus (); | |
13594 | ||
13595 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13596 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13597 | CompoundAssignmentOperator::BITWISE_OR, | |
13598 | locus)); | |
13599 | } | |
13600 | ||
13601 | // Parses a binary xor-assignment expression (with Pratt parsing). | |
13602 | template <typename ManagedTokenSource> | |
13603 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13604 | Parser<ManagedTokenSource>::parse_xor_assig_expr ( | |
13605 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13606 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13607 | { | |
13608 | // parse RHS (as tok has already been consumed in parse_expression) | |
13609 | std::unique_ptr<AST::Expr> right | |
13610 | = parse_expr (LBP_CARET_ASSIG - 1, AST::AttrVec (), restrictions); | |
13611 | if (right == nullptr) | |
13612 | return nullptr; | |
13613 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13614 | ||
13615 | // TODO: check types. actually, do so during semantic analysis | |
13616 | location_t locus = left->get_locus (); | |
13617 | ||
13618 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13619 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13620 | CompoundAssignmentOperator::BITWISE_XOR, | |
13621 | locus)); | |
13622 | } | |
13623 | ||
13624 | // Parses a binary left shift-assignment expression (with Pratt parsing). | |
13625 | template <typename ManagedTokenSource> | |
13626 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13627 | Parser<ManagedTokenSource>::parse_left_shift_assig_expr ( | |
13628 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13629 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13630 | { | |
13631 | // parse RHS (as tok has already been consumed in parse_expression) | |
13632 | std::unique_ptr<AST::Expr> right | |
13633 | = parse_expr (LBP_L_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions); | |
13634 | if (right == nullptr) | |
13635 | return nullptr; | |
13636 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13637 | ||
13638 | // TODO: check types. actually, do so during semantic analysis | |
13639 | location_t locus = left->get_locus (); | |
13640 | ||
13641 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13642 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13643 | CompoundAssignmentOperator::LEFT_SHIFT, | |
13644 | locus)); | |
13645 | } | |
13646 | ||
13647 | // Parses a binary right shift-assignment expression (with Pratt parsing). | |
13648 | template <typename ManagedTokenSource> | |
13649 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13650 | Parser<ManagedTokenSource>::parse_right_shift_assig_expr ( | |
13651 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13652 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13653 | { | |
13654 | // parse RHS (as tok has already been consumed in parse_expression) | |
13655 | std::unique_ptr<AST::Expr> right | |
13656 | = parse_expr (LBP_R_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions); | |
13657 | if (right == nullptr) | |
13658 | return nullptr; | |
13659 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13660 | ||
13661 | // TODO: check types. actually, do so during semantic analysis | |
13662 | location_t locus = left->get_locus (); | |
13663 | ||
13664 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13665 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13666 | CompoundAssignmentOperator::RIGHT_SHIFT, | |
13667 | locus)); | |
13668 | } | |
13669 | ||
13670 | // Parses a postfix unary await expression (with Pratt parsing). | |
13671 | template <typename ManagedTokenSource> | |
13672 | std::unique_ptr<AST::AwaitExpr> | |
13673 | Parser<ManagedTokenSource>::parse_await_expr ( | |
13674 | const_TokenPtr tok, std::unique_ptr<AST::Expr> expr_to_await, | |
13675 | AST::AttrVec outer_attrs) | |
13676 | { | |
13677 | /* skip "await" identifier (as "." has already been consumed in | |
13678 | * parse_expression) this assumes that the identifier was already identified | |
13679 | * as await */ | |
13680 | if (!skip_token (IDENTIFIER)) | |
13681 | { | |
13682 | Error error (tok->get_locus (), "failed to skip %<await%> in await expr " | |
13683 | "- this is probably a deep issue"); | |
13684 | add_error (std::move (error)); | |
13685 | ||
13686 | // skip somewhere? | |
13687 | return nullptr; | |
13688 | } | |
13689 | ||
13690 | // TODO: check inside async block in semantic analysis | |
13691 | location_t locus = expr_to_await->get_locus (); | |
13692 | ||
13693 | return std::unique_ptr<AST::AwaitExpr> ( | |
13694 | new AST::AwaitExpr (std::move (expr_to_await), std::move (outer_attrs), | |
13695 | locus)); | |
13696 | } | |
13697 | ||
13698 | /* Parses an exclusive range ('..') in left denotation position (i.e. | |
13699 | * RangeFromExpr or RangeFromToExpr). */ | |
13700 | template <typename ManagedTokenSource> | |
13701 | std::unique_ptr<AST::RangeExpr> | |
13702 | Parser<ManagedTokenSource>::parse_led_range_exclusive_expr ( | |
13703 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13704 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13705 | { | |
13706 | // FIXME: this probably parses expressions accidently or whatever | |
13707 | // try parsing RHS (as tok has already been consumed in parse_expression) | |
13708 | // Can be nullptr, in which case it is a RangeFromExpr, otherwise a | |
13709 | // RangeFromToExpr. | |
13710 | restrictions.expr_can_be_null = true; | |
13711 | std::unique_ptr<AST::Expr> right | |
13712 | = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions); | |
13713 | ||
13714 | location_t locus = left->get_locus (); | |
13715 | ||
13716 | if (right == nullptr) | |
13717 | { | |
13718 | // range from expr | |
13719 | return std::unique_ptr<AST::RangeFromExpr> ( | |
13720 | new AST::RangeFromExpr (std::move (left), locus)); | |
13721 | } | |
13722 | else | |
13723 | { | |
13724 | return std::unique_ptr<AST::RangeFromToExpr> ( | |
13725 | new AST::RangeFromToExpr (std::move (left), std::move (right), locus)); | |
13726 | } | |
13727 | // FIXME: make non-associative | |
13728 | } | |
13729 | ||
13730 | /* Parses an exclusive range ('..') in null denotation position (i.e. | |
13731 | * RangeToExpr or RangeFullExpr). */ | |
13732 | template <typename ManagedTokenSource> | |
13733 | std::unique_ptr<AST::RangeExpr> | |
13734 | Parser<ManagedTokenSource>::parse_nud_range_exclusive_expr ( | |
13735 | const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED) | |
13736 | { | |
13737 | auto restrictions = ParseRestrictions (); | |
13738 | restrictions.expr_can_be_null = true; | |
13739 | ||
13740 | // FIXME: this probably parses expressions accidently or whatever | |
13741 | // try parsing RHS (as tok has already been consumed in parse_expression) | |
13742 | std::unique_ptr<AST::Expr> right | |
13743 | = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions); | |
13744 | ||
13745 | location_t locus = tok->get_locus (); | |
13746 | ||
13747 | if (right == nullptr) | |
13748 | { | |
13749 | // range from expr | |
13750 | return std::unique_ptr<AST::RangeFullExpr> ( | |
13751 | new AST::RangeFullExpr (locus)); | |
13752 | } | |
13753 | else | |
13754 | { | |
13755 | return std::unique_ptr<AST::RangeToExpr> ( | |
13756 | new AST::RangeToExpr (std::move (right), locus)); | |
13757 | } | |
13758 | // FIXME: make non-associative | |
13759 | } | |
13760 | ||
13761 | // Parses a full binary range inclusive expression. | |
13762 | template <typename ManagedTokenSource> | |
13763 | std::unique_ptr<AST::RangeFromToInclExpr> | |
13764 | Parser<ManagedTokenSource>::parse_range_inclusive_expr ( | |
13765 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13766 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13767 | { | |
13768 | // parse RHS (as tok has already been consumed in parse_expression) | |
13769 | std::unique_ptr<AST::Expr> right | |
13770 | = parse_expr (LBP_DOT_DOT_EQ, AST::AttrVec (), restrictions); | |
13771 | if (right == nullptr) | |
13772 | return nullptr; | |
13773 | // FIXME: make non-associative | |
13774 | ||
13775 | // TODO: check types. actually, do so during semantic analysis | |
13776 | location_t locus = left->get_locus (); | |
13777 | ||
13778 | return std::unique_ptr<AST::RangeFromToInclExpr> ( | |
13779 | new AST::RangeFromToInclExpr (std::move (left), std::move (right), locus)); | |
13780 | } | |
13781 | ||
13782 | // Parses an inclusive range-to prefix unary expression. | |
13783 | template <typename ManagedTokenSource> | |
13784 | std::unique_ptr<AST::RangeToInclExpr> | |
13785 | Parser<ManagedTokenSource>::parse_range_to_inclusive_expr ( | |
13786 | const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED) | |
13787 | { | |
13788 | // parse RHS (as tok has already been consumed in parse_expression) | |
13789 | std::unique_ptr<AST::Expr> right = parse_expr (LBP_DOT_DOT_EQ); | |
13790 | if (right == nullptr) | |
13791 | return nullptr; | |
13792 | // FIXME: make non-associative | |
13793 | ||
13794 | // TODO: check types. actually, do so during semantic analysis | |
13795 | ||
13796 | return std::unique_ptr<AST::RangeToInclExpr> ( | |
13797 | new AST::RangeToInclExpr (std::move (right), tok->get_locus ())); | |
13798 | } | |
13799 | ||
13800 | // Parses a pseudo-binary infix tuple index expression. | |
13801 | template <typename ManagedTokenSource> | |
13802 | std::unique_ptr<AST::TupleIndexExpr> | |
13803 | Parser<ManagedTokenSource>::parse_tuple_index_expr ( | |
13804 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> tuple_expr, | |
13805 | AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED) | |
13806 | { | |
13807 | // parse int literal (as token already skipped) | |
13808 | const_TokenPtr index_tok = expect_token (INT_LITERAL); | |
13809 | if (index_tok == nullptr) | |
13810 | { | |
13811 | return nullptr; | |
13812 | } | |
13813 | std::string index = index_tok->get_str (); | |
13814 | ||
13815 | // convert to integer | |
13816 | if (!index_tok->is_pure_decimal ()) | |
13817 | { | |
13818 | Error error (index_tok->get_locus (), | |
13819 | "tuple index should be a pure decimal literal"); | |
13820 | add_error (std::move (error)); | |
13821 | } | |
13822 | int index_int = atoi (index.c_str ()); | |
13823 | ||
13824 | location_t locus = tuple_expr->get_locus (); | |
13825 | ||
13826 | return std::unique_ptr<AST::TupleIndexExpr> ( | |
13827 | new AST::TupleIndexExpr (std::move (tuple_expr), index_int, | |
13828 | std::move (outer_attrs), locus)); | |
13829 | } | |
13830 | ||
13831 | // Parses a pseudo-binary infix array (or slice) index expression. | |
13832 | template <typename ManagedTokenSource> | |
13833 | std::unique_ptr<AST::ArrayIndexExpr> | |
13834 | Parser<ManagedTokenSource>::parse_index_expr ( | |
13835 | const_TokenPtr, std::unique_ptr<AST::Expr> array_expr, | |
13836 | AST::AttrVec outer_attrs, ParseRestrictions) | |
13837 | { | |
13838 | // parse RHS (as tok has already been consumed in parse_expression) | |
13839 | /*std::unique_ptr<AST::Expr> index_expr | |
13840 | = parse_expr (LBP_ARRAY_REF, AST::AttrVec (), | |
13841 | restrictions);*/ | |
13842 | // TODO: conceptually, should treat [] as brackets, so just parse all expr | |
13843 | std::unique_ptr<AST::Expr> index_expr = parse_expr (); | |
13844 | if (index_expr == nullptr) | |
13845 | return nullptr; | |
13846 | ||
13847 | // skip ']' at end of array | |
13848 | if (!skip_token (RIGHT_SQUARE)) | |
13849 | { | |
13850 | // skip somewhere? | |
13851 | return nullptr; | |
13852 | } | |
13853 | ||
13854 | // TODO: check types. actually, do so during semantic analysis | |
13855 | location_t locus = array_expr->get_locus (); | |
13856 | ||
13857 | return std::unique_ptr<AST::ArrayIndexExpr> ( | |
13858 | new AST::ArrayIndexExpr (std::move (array_expr), std::move (index_expr), | |
13859 | std::move (outer_attrs), locus)); | |
13860 | } | |
13861 | ||
13862 | // Parses a pseudo-binary infix struct field access expression. | |
13863 | template <typename ManagedTokenSource> | |
13864 | std::unique_ptr<AST::FieldAccessExpr> | |
13865 | Parser<ManagedTokenSource>::parse_field_access_expr ( | |
13866 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> struct_expr, | |
13867 | AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED) | |
13868 | { | |
13869 | /* get field name identifier (assume that this is a field access expr and | |
13870 | * not await, for instance) */ | |
13871 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
13872 | if (ident_tok == nullptr) | |
13873 | return nullptr; | |
13874 | ||
13875 | Identifier ident{ident_tok}; | |
13876 | ||
13877 | location_t locus = struct_expr->get_locus (); | |
13878 | ||
13879 | // TODO: check types. actually, do so during semantic analysis | |
13880 | return std::unique_ptr<AST::FieldAccessExpr> ( | |
13881 | new AST::FieldAccessExpr (std::move (struct_expr), std::move (ident), | |
13882 | std::move (outer_attrs), locus)); | |
13883 | } | |
13884 | ||
13885 | // Parses a pseudo-binary infix method call expression. | |
13886 | template <typename ManagedTokenSource> | |
13887 | std::unique_ptr<AST::MethodCallExpr> | |
13888 | Parser<ManagedTokenSource>::parse_method_call_expr ( | |
13889 | const_TokenPtr tok, std::unique_ptr<AST::Expr> receiver_expr, | |
13890 | AST::AttrVec outer_attrs, ParseRestrictions) | |
13891 | { | |
13892 | // parse path expr segment | |
13893 | AST::PathExprSegment segment = parse_path_expr_segment (); | |
13894 | if (segment.is_error ()) | |
13895 | { | |
13896 | Error error (tok->get_locus (), | |
13897 | "failed to parse path expr segment of method call expr"); | |
13898 | add_error (std::move (error)); | |
13899 | ||
13900 | return nullptr; | |
13901 | } | |
13902 | ||
13903 | // skip left parentheses | |
13904 | if (!skip_token (LEFT_PAREN)) | |
13905 | { | |
13906 | return nullptr; | |
13907 | } | |
13908 | ||
13909 | // parse method params (if they exist) | |
13910 | std::vector<std::unique_ptr<AST::Expr>> params; | |
13911 | ||
13912 | const_TokenPtr t = lexer.peek_token (); | |
13913 | while (t->get_id () != RIGHT_PAREN) | |
13914 | { | |
13915 | std::unique_ptr<AST::Expr> param = parse_expr (); | |
13916 | if (param == nullptr) | |
13917 | { | |
13918 | Error error (t->get_locus (), | |
13919 | "failed to parse method param in method call"); | |
13920 | add_error (std::move (error)); | |
13921 | ||
13922 | return nullptr; | |
13923 | } | |
13924 | params.push_back (std::move (param)); | |
13925 | ||
13926 | if (lexer.peek_token ()->get_id () != COMMA) | |
13927 | break; | |
13928 | ||
13929 | lexer.skip_token (); | |
13930 | t = lexer.peek_token (); | |
13931 | } | |
13932 | ||
13933 | // skip right paren | |
13934 | if (!skip_token (RIGHT_PAREN)) | |
13935 | { | |
13936 | return nullptr; | |
13937 | } | |
13938 | ||
13939 | // TODO: check types. actually do so in semantic analysis pass. | |
13940 | location_t locus = receiver_expr->get_locus (); | |
13941 | ||
13942 | return std::unique_ptr<AST::MethodCallExpr> ( | |
13943 | new AST::MethodCallExpr (std::move (receiver_expr), std::move (segment), | |
13944 | std::move (params), std::move (outer_attrs), | |
13945 | locus)); | |
13946 | } | |
13947 | ||
13948 | // Parses a pseudo-binary infix function call expression. | |
13949 | template <typename ManagedTokenSource> | |
13950 | std::unique_ptr<AST::CallExpr> | |
13951 | Parser<ManagedTokenSource>::parse_function_call_expr ( | |
13952 | const_TokenPtr, std::unique_ptr<AST::Expr> function_expr, | |
13953 | AST::AttrVec outer_attrs, ParseRestrictions) | |
13954 | { | |
13955 | // parse function params (if they exist) | |
13956 | std::vector<std::unique_ptr<AST::Expr>> params; | |
13957 | ||
13958 | const_TokenPtr t = lexer.peek_token (); | |
13959 | while (t->get_id () != RIGHT_PAREN) | |
13960 | { | |
13961 | std::unique_ptr<AST::Expr> param = parse_expr (); | |
13962 | if (param == nullptr) | |
13963 | { | |
13964 | Error error (t->get_locus (), | |
13965 | "failed to parse function param in function call"); | |
13966 | add_error (std::move (error)); | |
13967 | ||
13968 | return nullptr; | |
13969 | } | |
13970 | params.push_back (std::move (param)); | |
13971 | ||
13972 | if (lexer.peek_token ()->get_id () != COMMA) | |
13973 | break; | |
13974 | ||
13975 | lexer.skip_token (); | |
13976 | t = lexer.peek_token (); | |
13977 | } | |
13978 | ||
13979 | // skip ')' at end of param list | |
13980 | if (!skip_token (RIGHT_PAREN)) | |
13981 | { | |
13982 | // skip somewhere? | |
13983 | return nullptr; | |
13984 | } | |
13985 | ||
13986 | // TODO: check types. actually, do so during semantic analysis | |
13987 | location_t locus = function_expr->get_locus (); | |
13988 | ||
13989 | return std::unique_ptr<AST::CallExpr> ( | |
13990 | new AST::CallExpr (std::move (function_expr), std::move (params), | |
13991 | std::move (outer_attrs), locus)); | |
13992 | } | |
13993 | ||
13994 | /* Parses a macro invocation with a path in expression already parsed (but not | |
13995 | * '!' token). */ | |
13996 | template <typename ManagedTokenSource> | |
13997 | std::unique_ptr<AST::MacroInvocation> | |
13998 | Parser<ManagedTokenSource>::parse_macro_invocation_partial ( | |
13999 | AST::PathInExpression path, AST::AttrVec outer_attrs, | |
14000 | ParseRestrictions restrictions) | |
14001 | { | |
14002 | // macro invocation | |
14003 | if (!skip_token (EXCLAM)) | |
14004 | { | |
14005 | return nullptr; | |
14006 | } | |
14007 | ||
14008 | // convert PathInExpression to SimplePath - if this isn't possible, error | |
14009 | AST::SimplePath converted_path = path.as_simple_path (); | |
14010 | if (converted_path.is_empty ()) | |
14011 | { | |
14012 | Error error (lexer.peek_token ()->get_locus (), | |
14013 | "failed to parse simple path in macro invocation"); | |
14014 | add_error (std::move (error)); | |
14015 | ||
14016 | return nullptr; | |
14017 | } | |
14018 | ||
14019 | AST::DelimTokenTree tok_tree = parse_delim_token_tree (); | |
14020 | ||
14021 | rust_debug ("successfully parsed macro invocation (via partial)"); | |
14022 | ||
14023 | location_t macro_locus = converted_path.get_locus (); | |
14024 | ||
14025 | return AST::MacroInvocation::Regular ( | |
14026 | AST::MacroInvocData (std::move (converted_path), std::move (tok_tree)), | |
14027 | std::move (outer_attrs), macro_locus); | |
14028 | } | |
14029 | ||
14030 | /* Parses a struct expr struct with a path in expression already parsed (but | |
14031 | * not | |
14032 | * '{' token). */ | |
14033 | template <typename ManagedTokenSource> | |
14034 | std::unique_ptr<AST::StructExprStruct> | |
14035 | Parser<ManagedTokenSource>::parse_struct_expr_struct_partial ( | |
14036 | AST::PathInExpression path, AST::AttrVec outer_attrs) | |
14037 | { | |
14038 | // assume struct expr struct (as struct-enum disambiguation requires name | |
14039 | // lookup) again, make statement if final ';' | |
14040 | if (!skip_token (LEFT_CURLY)) | |
14041 | { | |
14042 | return nullptr; | |
14043 | } | |
14044 | ||
14045 | // parse inner attributes | |
14046 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
14047 | ||
14048 | // branch based on next token | |
14049 | const_TokenPtr t = lexer.peek_token (); | |
14050 | location_t path_locus = path.get_locus (); | |
14051 | switch (t->get_id ()) | |
14052 | { | |
14053 | case RIGHT_CURLY: | |
14054 | // struct with no body | |
14055 | lexer.skip_token (); | |
14056 | ||
14057 | return std::unique_ptr<AST::StructExprStruct> ( | |
14058 | new AST::StructExprStruct (std::move (path), std::move (inner_attrs), | |
14059 | std::move (outer_attrs), path_locus)); | |
14060 | case DOT_DOT: | |
14061 | /* technically this would give a struct base-only struct, but this | |
14062 | * algorithm should work too. As such, AST type not happening. */ | |
14063 | case IDENTIFIER: | |
14064 | case HASH: | |
14065 | case INT_LITERAL: { | |
14066 | // struct with struct expr fields | |
14067 | ||
14068 | // parse struct expr fields | |
14069 | std::vector<std::unique_ptr<AST::StructExprField>> fields; | |
14070 | ||
14071 | while (t->get_id () != RIGHT_CURLY && t->get_id () != DOT_DOT) | |
14072 | { | |
14073 | std::unique_ptr<AST::StructExprField> field | |
14074 | = parse_struct_expr_field (); | |
14075 | if (field == nullptr) | |
14076 | { | |
14077 | Error error (t->get_locus (), | |
14078 | "failed to parse struct (or enum) expr field"); | |
14079 | add_error (std::move (error)); | |
14080 | ||
14081 | return nullptr; | |
14082 | } | |
14083 | ||
14084 | // DEBUG: | |
14085 | rust_debug ("struct/enum expr field validated to not be null"); | |
14086 | ||
14087 | fields.push_back (std::move (field)); | |
14088 | ||
14089 | // DEBUG: | |
14090 | rust_debug ("struct/enum expr field pushed back"); | |
14091 | ||
14092 | if (lexer.peek_token ()->get_id () != COMMA) | |
14093 | { | |
14094 | // DEBUG: | |
14095 | rust_debug ("lack of comma detected in struct/enum expr " | |
14096 | "fields - break"); | |
14097 | break; | |
14098 | } | |
14099 | lexer.skip_token (); | |
14100 | ||
14101 | // DEBUG: | |
14102 | rust_debug ("struct/enum expr fields comma skipped "); | |
14103 | ||
14104 | t = lexer.peek_token (); | |
14105 | } | |
14106 | ||
14107 | // DEBUG: | |
14108 | rust_debug ("struct/enum expr about to parse struct base "); | |
14109 | ||
14110 | // parse struct base if it exists | |
14111 | AST::StructBase struct_base = AST::StructBase::error (); | |
14112 | if (lexer.peek_token ()->get_id () == DOT_DOT) | |
14113 | { | |
14114 | location_t dot_dot_location = lexer.peek_token ()->get_locus (); | |
14115 | lexer.skip_token (); | |
14116 | ||
14117 | // parse required struct base expr | |
14118 | std::unique_ptr<AST::Expr> base_expr = parse_expr (); | |
14119 | if (base_expr == nullptr) | |
14120 | { | |
14121 | Error error (lexer.peek_token ()->get_locus (), | |
14122 | "failed to parse struct base expression in struct " | |
14123 | "expression"); | |
14124 | add_error (std::move (error)); | |
14125 | ||
14126 | return nullptr; | |
14127 | } | |
14128 | ||
14129 | // DEBUG: | |
14130 | rust_debug ("struct/enum expr - parsed and validated base expr"); | |
14131 | ||
14132 | struct_base | |
14133 | = AST::StructBase (std::move (base_expr), dot_dot_location); | |
14134 | ||
14135 | // DEBUG: | |
14136 | rust_debug ("assigned struct base to new struct base "); | |
14137 | } | |
14138 | ||
14139 | if (!skip_token (RIGHT_CURLY)) | |
14140 | { | |
14141 | return nullptr; | |
14142 | } | |
14143 | ||
14144 | // DEBUG: | |
14145 | rust_debug ( | |
14146 | "struct/enum expr skipped right curly - done and ready to return"); | |
14147 | ||
14148 | return std::unique_ptr<AST::StructExprStructFields> ( | |
14149 | new AST::StructExprStructFields (std::move (path), std::move (fields), | |
14150 | path_locus, std::move (struct_base), | |
14151 | std::move (inner_attrs), | |
14152 | std::move (outer_attrs))); | |
14153 | } | |
14154 | default: | |
14155 | add_error ( | |
14156 | Error (t->get_locus (), | |
14157 | "unrecognised token %qs in struct (or enum) expression - " | |
14158 | "expected %<}%>, identifier, integer literal, or %<..%>", | |
14159 | t->get_token_description ())); | |
14160 | ||
14161 | return nullptr; | |
14162 | } | |
14163 | } | |
14164 | ||
14165 | /* Parses a struct expr tuple with a path in expression already parsed (but | |
14166 | * not | |
14167 | * '(' token). | |
14168 | * FIXME: this currently outputs a call expr, as they cannot be disambiguated. | |
14169 | * A better solution would be to just get this to call that function directly. | |
14170 | * */ | |
14171 | template <typename ManagedTokenSource> | |
14172 | std::unique_ptr<AST::CallExpr> | |
14173 | Parser<ManagedTokenSource>::parse_struct_expr_tuple_partial ( | |
14174 | AST::PathInExpression path, AST::AttrVec outer_attrs) | |
14175 | { | |
14176 | if (!skip_token (LEFT_PAREN)) | |
14177 | { | |
14178 | return nullptr; | |
14179 | } | |
14180 | ||
14181 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
14182 | ||
14183 | std::vector<std::unique_ptr<AST::Expr>> exprs; | |
14184 | ||
14185 | const_TokenPtr t = lexer.peek_token (); | |
14186 | while (t->get_id () != RIGHT_PAREN) | |
14187 | { | |
14188 | // parse expression (required) | |
14189 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
14190 | if (expr == nullptr) | |
14191 | { | |
14192 | Error error (t->get_locus (), "failed to parse expression in " | |
14193 | "struct (or enum) expression tuple"); | |
14194 | add_error (std::move (error)); | |
14195 | ||
14196 | return nullptr; | |
14197 | } | |
14198 | exprs.push_back (std::move (expr)); | |
14199 | ||
14200 | if (lexer.peek_token ()->get_id () != COMMA) | |
14201 | break; | |
14202 | ||
14203 | lexer.skip_token (); | |
14204 | ||
14205 | t = lexer.peek_token (); | |
14206 | } | |
14207 | ||
14208 | if (!skip_token (RIGHT_PAREN)) | |
14209 | { | |
14210 | return nullptr; | |
14211 | } | |
14212 | ||
14213 | location_t path_locus = path.get_locus (); | |
14214 | ||
14215 | auto pathExpr = std::unique_ptr<AST::PathInExpression> ( | |
14216 | new AST::PathInExpression (std::move (path))); | |
14217 | ||
14218 | return std::unique_ptr<AST::CallExpr> ( | |
14219 | new AST::CallExpr (std::move (pathExpr), std::move (exprs), | |
14220 | std::move (outer_attrs), path_locus)); | |
14221 | } | |
14222 | ||
14223 | /* Parses a path in expression with the first token passed as a parameter (as | |
14224 | * it is skipped in token stream). Note that this only parses segment-first | |
14225 | * paths, not global ones. */ | |
14226 | template <typename ManagedTokenSource> | |
14227 | AST::PathInExpression | |
14228 | Parser<ManagedTokenSource>::parse_path_in_expression_pratt (const_TokenPtr tok) | |
14229 | { | |
14230 | // HACK-y way of making up for pratt-parsing consuming first token | |
14231 | ||
14232 | // DEBUG | |
14233 | rust_debug ("current peek token when starting path pratt parse: '%s'", | |
14234 | lexer.peek_token ()->get_token_description ()); | |
14235 | ||
14236 | // create segment vector | |
14237 | std::vector<AST::PathExprSegment> segments; | |
14238 | ||
14239 | std::string initial_str; | |
14240 | ||
14241 | switch (tok->get_id ()) | |
14242 | { | |
14243 | case IDENTIFIER: | |
14244 | initial_str = tok->get_str (); | |
14245 | break; | |
14246 | case SUPER: | |
14247 | initial_str = Values::Keywords::SUPER; | |
14248 | break; | |
14249 | case SELF: | |
14250 | initial_str = Values::Keywords::SELF; | |
14251 | break; | |
14252 | case SELF_ALIAS: | |
14253 | initial_str = Values::Keywords::SELF_ALIAS; | |
14254 | break; | |
14255 | case CRATE: | |
14256 | initial_str = Values::Keywords::CRATE; | |
14257 | break; | |
14258 | case DOLLAR_SIGN: | |
14259 | if (lexer.peek_token ()->get_id () == CRATE) | |
14260 | { | |
14261 | initial_str = "$crate"; | |
14262 | break; | |
14263 | } | |
14264 | gcc_fallthrough (); | |
14265 | default: | |
14266 | add_error (Error (tok->get_locus (), | |
14267 | "unrecognised token %qs in path in expression", | |
14268 | tok->get_token_description ())); | |
14269 | ||
14270 | return AST::PathInExpression::create_error (); | |
14271 | } | |
14272 | ||
14273 | // parse required initial segment | |
14274 | AST::PathExprSegment initial_segment (initial_str, tok->get_locus ()); | |
14275 | // parse generic args (and turbofish), if they exist | |
14276 | /* use lookahead to determine if they actually exist (don't want to | |
14277 | * accidently parse over next ident segment) */ | |
14278 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION | |
14279 | && lexer.peek_token (1)->get_id () == LEFT_ANGLE) | |
14280 | { | |
14281 | // skip scope resolution | |
14282 | lexer.skip_token (); | |
14283 | ||
14284 | AST::GenericArgs generic_args = parse_path_generic_args (); | |
14285 | ||
14286 | initial_segment | |
14287 | = AST::PathExprSegment (AST::PathIdentSegment (initial_str, | |
14288 | tok->get_locus ()), | |
14289 | tok->get_locus (), std::move (generic_args)); | |
14290 | } | |
14291 | if (initial_segment.is_error ()) | |
14292 | { | |
14293 | // skip after somewhere? | |
14294 | // don't necessarily throw error but yeah | |
14295 | ||
14296 | // DEBUG | |
14297 | rust_debug ("initial segment is error - returning null"); | |
14298 | ||
14299 | return AST::PathInExpression::create_error (); | |
14300 | } | |
14301 | segments.push_back (std::move (initial_segment)); | |
14302 | ||
14303 | // parse optional segments (as long as scope resolution operator exists) | |
14304 | const_TokenPtr t = lexer.peek_token (); | |
14305 | while (t->get_id () == SCOPE_RESOLUTION) | |
14306 | { | |
14307 | // skip scope resolution operator | |
14308 | lexer.skip_token (); | |
14309 | ||
14310 | // parse the actual segment - it is an error if it doesn't exist now | |
14311 | AST::PathExprSegment segment = parse_path_expr_segment (); | |
14312 | if (segment.is_error ()) | |
14313 | { | |
14314 | // skip after somewhere? | |
14315 | Error error (t->get_locus (), | |
14316 | "could not parse path expression segment"); | |
14317 | add_error (std::move (error)); | |
14318 | ||
14319 | return AST::PathInExpression::create_error (); | |
14320 | } | |
14321 | ||
14322 | segments.push_back (std::move (segment)); | |
14323 | ||
14324 | t = lexer.peek_token (); | |
14325 | } | |
14326 | ||
14327 | // DEBUG: | |
14328 | rust_debug ( | |
14329 | "current token (just about to return path to null denotation): '%s'", | |
14330 | lexer.peek_token ()->get_token_description ()); | |
14331 | ||
14332 | return AST::PathInExpression (std::move (segments), {}, tok->get_locus (), | |
14333 | false); | |
14334 | } | |
14335 | ||
14336 | // Parses a closure expression with pratt parsing (from null denotation). | |
14337 | template <typename ManagedTokenSource> | |
14338 | std::unique_ptr<AST::ClosureExpr> | |
14339 | Parser<ManagedTokenSource>::parse_closure_expr_pratt (const_TokenPtr tok, | |
14340 | AST::AttrVec outer_attrs) | |
14341 | { | |
14342 | // TODO: does this need pratt parsing (for precedence)? probably not, but | |
14343 | // idk | |
14344 | location_t locus = tok->get_locus (); | |
14345 | bool has_move = false; | |
14346 | if (tok->get_id () == MOVE) | |
14347 | { | |
14348 | has_move = true; | |
14349 | tok = lexer.peek_token (); | |
14350 | lexer.skip_token (); | |
14351 | // skip token and reassign | |
14352 | } | |
14353 | ||
14354 | // handle parameter list | |
14355 | std::vector<AST::ClosureParam> params; | |
14356 | ||
14357 | switch (tok->get_id ()) | |
14358 | { | |
14359 | case OR: | |
14360 | // no parameters, don't skip token | |
14361 | break; | |
14362 | case PIPE: { | |
14363 | // actually may have parameters | |
14364 | // don't skip token | |
14365 | const_TokenPtr t = lexer.peek_token (); | |
14366 | while (t->get_id () != PIPE) | |
14367 | { | |
14368 | AST::ClosureParam param = parse_closure_param (); | |
14369 | if (param.is_error ()) | |
14370 | { | |
14371 | // TODO is this really an error? | |
14372 | Error error (t->get_locus (), "could not parse closure param"); | |
14373 | add_error (std::move (error)); | |
14374 | ||
14375 | return nullptr; | |
14376 | } | |
14377 | params.push_back (std::move (param)); | |
14378 | ||
14379 | if (lexer.peek_token ()->get_id () != COMMA) | |
14380 | { | |
14381 | if (lexer.peek_token ()->get_id () == OR) | |
14382 | lexer.split_current_token (PIPE, PIPE); | |
14383 | // not an error but means param list is done | |
14384 | break; | |
14385 | } | |
14386 | // skip comma | |
14387 | lexer.skip_token (); | |
14388 | ||
14389 | if (lexer.peek_token ()->get_id () == OR) | |
14390 | lexer.split_current_token (PIPE, PIPE); | |
14391 | ||
14392 | t = lexer.peek_token (); | |
14393 | } | |
14394 | ||
14395 | if (!skip_token (PIPE)) | |
14396 | { | |
14397 | return nullptr; | |
14398 | } | |
14399 | break; | |
14400 | } | |
14401 | default: | |
14402 | add_error (Error (tok->get_locus (), | |
14403 | "unexpected token %qs in closure expression - expected " | |
14404 | "%<|%> or %<||%>", | |
14405 | tok->get_token_description ())); | |
14406 | ||
14407 | // skip somewhere? | |
14408 | return nullptr; | |
14409 | } | |
14410 | ||
14411 | // again branch based on next token | |
14412 | tok = lexer.peek_token (); | |
14413 | if (tok->get_id () == RETURN_TYPE) | |
14414 | { | |
14415 | // must be return type closure with block expr | |
14416 | ||
14417 | // skip "return type" token | |
14418 | lexer.skip_token (); | |
14419 | ||
14420 | // parse actual type, which is required | |
14421 | std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds (); | |
14422 | if (type == nullptr) | |
14423 | { | |
14424 | // error | |
14425 | Error error (tok->get_locus (), "failed to parse type for closure"); | |
14426 | add_error (std::move (error)); | |
14427 | ||
14428 | // skip somewhere? | |
14429 | return nullptr; | |
14430 | } | |
14431 | ||
14432 | // parse block expr, which is required | |
14433 | std::unique_ptr<AST::BlockExpr> block = parse_block_expr (); | |
14434 | if (block == nullptr) | |
14435 | { | |
14436 | // error | |
14437 | Error error (lexer.peek_token ()->get_locus (), | |
14438 | "failed to parse block expr in closure"); | |
14439 | add_error (std::move (error)); | |
14440 | ||
14441 | // skip somewhere? | |
14442 | return nullptr; | |
14443 | } | |
14444 | ||
14445 | return std::unique_ptr<AST::ClosureExprInnerTyped> ( | |
14446 | new AST::ClosureExprInnerTyped (std::move (type), std::move (block), | |
14447 | std::move (params), locus, has_move, | |
14448 | std::move (outer_attrs))); | |
14449 | } | |
14450 | else | |
14451 | { | |
14452 | // must be expr-only closure | |
14453 | ||
14454 | // parse expr, which is required | |
14455 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
14456 | if (expr == nullptr) | |
14457 | { | |
14458 | Error error (tok->get_locus (), | |
14459 | "failed to parse expression in closure"); | |
14460 | add_error (std::move (error)); | |
14461 | ||
14462 | // skip somewhere? | |
14463 | return nullptr; | |
14464 | } | |
14465 | ||
14466 | return std::unique_ptr<AST::ClosureExprInner> ( | |
14467 | new AST::ClosureExprInner (std::move (expr), std::move (params), locus, | |
14468 | has_move, std::move (outer_attrs))); | |
14469 | } | |
14470 | } | |
14471 | ||
14472 | /* Parses a tuple index expression (pratt-parsed) from a 'float' token as a | |
14473 | * result of lexer misidentification. */ | |
14474 | template <typename ManagedTokenSource> | |
14475 | std::unique_ptr<AST::TupleIndexExpr> | |
14476 | Parser<ManagedTokenSource>::parse_tuple_index_expr_float ( | |
14477 | const_TokenPtr tok, std::unique_ptr<AST::Expr> tuple_expr, | |
14478 | AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED) | |
14479 | { | |
14480 | // only works on float literals | |
14481 | if (tok->get_id () != FLOAT_LITERAL) | |
14482 | return nullptr; | |
14483 | ||
14484 | // DEBUG: | |
14485 | rust_debug ("exact string form of float: '%s'", tok->get_str ().c_str ()); | |
14486 | ||
14487 | // get float string and remove dot and initial 0 | |
14488 | std::string index_str = tok->get_str (); | |
14489 | index_str.erase (index_str.begin ()); | |
14490 | ||
14491 | // get int from string | |
14492 | int index = atoi (index_str.c_str ()); | |
14493 | ||
14494 | location_t locus = tuple_expr->get_locus (); | |
14495 | ||
14496 | return std::unique_ptr<AST::TupleIndexExpr> ( | |
14497 | new AST::TupleIndexExpr (std::move (tuple_expr), index, | |
14498 | std::move (outer_attrs), locus)); | |
14499 | } | |
14500 | ||
14501 | // Returns true if the next token is END, ELSE, or EOF; | |
14502 | template <typename ManagedTokenSource> | |
14503 | bool | |
14504 | Parser<ManagedTokenSource>::done_end_or_else () | |
14505 | { | |
14506 | const_TokenPtr t = lexer.peek_token (); | |
14507 | return (t->get_id () == RIGHT_CURLY || t->get_id () == ELSE | |
14508 | || t->get_id () == END_OF_FILE); | |
14509 | } | |
14510 | ||
14511 | // Returns true if the next token is END or EOF. | |
14512 | template <typename ManagedTokenSource> | |
14513 | bool | |
14514 | Parser<ManagedTokenSource>::done_end () | |
14515 | { | |
14516 | const_TokenPtr t = lexer.peek_token (); | |
14517 | return (t->get_id () == RIGHT_CURLY || t->get_id () == END_OF_FILE); | |
14518 | } | |
14519 | } // namespace Rust |