]>
Commit | Line | Data |
---|---|---|
83ffe9cd | 1 | // Copyright (C) 2020-2023 Free Software Foundation, Inc. |
35e4f3b4 JP |
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 | #define INCLUDE_ALGORITHM | |
26 | #include "rust-diagnostics.h" | |
27 | #include "rust-make-unique.h" | |
28 | ||
29 | namespace Rust { | |
30 | // Left binding powers of operations. | |
31 | enum binding_powers | |
32 | { | |
33 | // Highest priority | |
34 | LBP_HIGHEST = 100, | |
35 | ||
36 | LBP_PATH = 95, | |
37 | ||
38 | LBP_METHOD_CALL = 90, | |
39 | ||
40 | LBP_FIELD_EXPR = 85, | |
41 | ||
42 | LBP_FUNCTION_CALL = 80, | |
43 | LBP_ARRAY_REF = LBP_FUNCTION_CALL, | |
44 | ||
45 | LBP_QUESTION_MARK = 75, // unary postfix - counts as left | |
46 | ||
47 | LBP_UNARY_PLUS = 70, // Used only when the null denotation is + | |
48 | LBP_UNARY_MINUS = LBP_UNARY_PLUS, // Used only when the null denotation is - | |
49 | LBP_UNARY_ASTERISK = LBP_UNARY_PLUS, // deref operator - unary prefix | |
50 | LBP_UNARY_EXCLAM = LBP_UNARY_PLUS, | |
51 | LBP_UNARY_AMP = LBP_UNARY_PLUS, | |
52 | LBP_UNARY_AMP_MUT = LBP_UNARY_PLUS, | |
53 | ||
54 | LBP_AS = 65, | |
55 | ||
56 | LBP_MUL = 60, | |
57 | LBP_DIV = LBP_MUL, | |
58 | LBP_MOD = LBP_MUL, | |
59 | ||
60 | LBP_PLUS = 55, | |
61 | LBP_MINUS = LBP_PLUS, | |
62 | ||
63 | LBP_L_SHIFT = 50, | |
64 | LBP_R_SHIFT = LBP_L_SHIFT, | |
65 | ||
66 | LBP_AMP = 45, | |
67 | ||
68 | LBP_CARET = 40, | |
69 | ||
70 | LBP_PIPE = 35, | |
71 | ||
72 | LBP_EQUAL = 30, | |
73 | LBP_NOT_EQUAL = LBP_EQUAL, | |
74 | LBP_SMALLER_THAN = LBP_EQUAL, | |
75 | LBP_SMALLER_EQUAL = LBP_EQUAL, | |
76 | LBP_GREATER_THAN = LBP_EQUAL, | |
77 | LBP_GREATER_EQUAL = LBP_EQUAL, | |
78 | ||
79 | LBP_LOGICAL_AND = 25, | |
80 | ||
81 | LBP_LOGICAL_OR = 20, | |
82 | ||
83 | LBP_DOT_DOT = 15, | |
84 | LBP_DOT_DOT_EQ = LBP_DOT_DOT, | |
85 | ||
86 | // TODO: note all these assig operators are RIGHT associative! | |
87 | LBP_ASSIG = 10, | |
88 | LBP_PLUS_ASSIG = LBP_ASSIG, | |
89 | LBP_MINUS_ASSIG = LBP_ASSIG, | |
90 | LBP_MULT_ASSIG = LBP_ASSIG, | |
91 | LBP_DIV_ASSIG = LBP_ASSIG, | |
92 | LBP_MOD_ASSIG = LBP_ASSIG, | |
93 | LBP_AMP_ASSIG = LBP_ASSIG, | |
94 | LBP_PIPE_ASSIG = LBP_ASSIG, | |
95 | LBP_CARET_ASSIG = LBP_ASSIG, | |
96 | LBP_L_SHIFT_ASSIG = LBP_ASSIG, | |
97 | LBP_R_SHIFT_ASSIG = LBP_ASSIG, | |
98 | ||
99 | // return, break, and closures as lowest priority? | |
100 | LBP_RETURN = 5, | |
101 | LBP_BREAK = LBP_RETURN, | |
102 | LBP_CLOSURE = LBP_RETURN, // unary prefix operators | |
103 | ||
104 | #if 0 | |
105 | // rust precedences | |
106 | // used for closures | |
107 | PREC_CLOSURE = -40, | |
108 | // used for break, continue, return, and yield | |
109 | PREC_JUMP = -30, | |
110 | // used for range (although weird comment in rustc about this) | |
111 | PREC_RANGE = -10, | |
112 | // used for binary operators mentioned below - also cast, colon (type), | |
113 | // assign, assign_op | |
114 | PREC_BINOP = FROM_ASSOC_OP, | |
115 | // used for box, address_of, let, unary (again, weird comment on let) | |
116 | PREC_PREFIX = 50, | |
117 | // used for await, call, method call, field, index, try, | |
118 | // inline asm, macro invocation | |
119 | PREC_POSTFIX = 60, | |
120 | // used for array, repeat, tuple, literal, path, paren, if, | |
121 | // while, for, 'loop', match, block, try block, async, struct | |
122 | PREC_PAREN = 99, | |
123 | PREC_FORCE_PAREN = 100, | |
124 | #endif | |
125 | ||
126 | // lowest priority | |
127 | LBP_LOWEST = 0 | |
128 | }; | |
129 | ||
130 | /* Returns whether the token can start a type (i.e. there is a valid type | |
131 | * beginning with the token). */ | |
132 | inline bool | |
133 | can_tok_start_type (TokenId id) | |
134 | { | |
135 | switch (id) | |
136 | { | |
137 | case EXCLAM: | |
138 | case LEFT_SQUARE: | |
139 | case LEFT_ANGLE: | |
140 | case UNDERSCORE: | |
141 | case ASTERISK: | |
142 | case AMP: | |
143 | case LIFETIME: | |
144 | case IDENTIFIER: | |
145 | case SUPER: | |
146 | case SELF: | |
147 | case SELF_ALIAS: | |
148 | case CRATE: | |
149 | case DOLLAR_SIGN: | |
150 | case SCOPE_RESOLUTION: | |
151 | case LEFT_PAREN: | |
152 | case FOR: | |
153 | case ASYNC: | |
154 | case CONST: | |
155 | case UNSAFE: | |
156 | case EXTERN_TOK: | |
157 | case FN_TOK: | |
158 | case IMPL: | |
159 | case DYN: | |
160 | case QUESTION_MARK: | |
161 | return true; | |
162 | default: | |
163 | return false; | |
164 | } | |
165 | } | |
166 | ||
167 | /* Returns whether the token id is (or is likely to be) a right angle bracket. | |
168 | * i.e. '>', '>>', '>=' and '>>=' tokens. */ | |
169 | inline bool | |
170 | is_right_angle_tok (TokenId id) | |
171 | { | |
172 | switch (id) | |
173 | { | |
174 | case RIGHT_ANGLE: | |
175 | case RIGHT_SHIFT: | |
176 | case GREATER_OR_EQUAL: | |
177 | case RIGHT_SHIFT_EQ: | |
178 | return true; | |
179 | default: | |
180 | return false; | |
181 | } | |
182 | } | |
183 | ||
184 | /* HACK-y special handling for skipping a right angle token at the end of | |
185 | * generic arguments. | |
186 | * Currently, this replaces the "current token" with one that is identical | |
187 | * except has the leading '>' removed (e.g. '>>' becomes '>'). This is bad | |
188 | * for several reasons - it modifies the token stream to something that | |
189 | * actually doesn't make syntactic sense, it may not worked if the token | |
190 | * has already been skipped, etc. It was done because it would not | |
191 | * actually require inserting new items into the token stream (which I | |
192 | * thought would take more work to not mess up) and because I wasn't sure | |
193 | * if the "already seen right angle" flag in the parser would work | |
194 | * correctly. | |
195 | * Those two other approaches listed are in my opinion actually better | |
196 | * long-term - insertion is probably best as it reflects syntactically | |
197 | * what occurs. On the other hand, I need to do a code audit to make sure | |
198 | * that insertion doesn't mess anything up. So that's a FIXME. */ | |
199 | template <typename ManagedTokenSource> | |
200 | bool | |
201 | Parser<ManagedTokenSource>::skip_generics_right_angle () | |
202 | { | |
203 | /* OK, new great idea. Have a lexer method called | |
204 | * "split_current_token(TokenType newLeft, TokenType newRight)", which is | |
205 | * called here with whatever arguments are appropriate. That lexer method | |
206 | * handles "replacing" the current token with the "newLeft" and "inserting" | |
207 | * the next token with the "newRight" (and creating a location, etc. for it) | |
208 | */ | |
209 | ||
210 | /* HACK: special handling for right shift '>>', greater or equal '>=', and | |
211 | * right shift assig */ | |
212 | // '>>=' | |
213 | const_TokenPtr tok = lexer.peek_token (); | |
214 | switch (tok->get_id ()) | |
215 | { | |
216 | case RIGHT_ANGLE: | |
217 | // this is good - skip token | |
218 | lexer.skip_token (); | |
219 | return true; | |
220 | case RIGHT_SHIFT: { | |
221 | // new implementation that should be better | |
222 | lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE); | |
223 | lexer.skip_token (); | |
224 | return true; | |
225 | } | |
226 | case GREATER_OR_EQUAL: { | |
227 | // new implementation that should be better | |
228 | lexer.split_current_token (RIGHT_ANGLE, EQUAL); | |
229 | lexer.skip_token (); | |
230 | return true; | |
231 | } | |
232 | case RIGHT_SHIFT_EQ: { | |
233 | // new implementation that should be better | |
234 | lexer.split_current_token (RIGHT_ANGLE, GREATER_OR_EQUAL); | |
235 | lexer.skip_token (); | |
236 | return true; | |
237 | } | |
238 | default: | |
239 | add_error (Error (tok->get_locus (), | |
240 | "expected %<>%> at end of generic argument - found %qs", | |
241 | tok->get_token_description ())); | |
242 | return false; | |
243 | } | |
244 | } | |
245 | ||
246 | /* Gets left binding power for specified token. | |
247 | * Not suitable for use at the moment or possibly ever because binding power | |
248 | * cannot be purely determined from operator token with Rust grammar - e.g. | |
249 | * method call and field access have | |
250 | * different left binding powers but the same operator token. */ | |
251 | template <typename ManagedTokenSource> | |
252 | int | |
253 | Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token) | |
254 | { | |
255 | // HACK: called with "peek_token()", so lookahead is "peek_token(1)" | |
256 | switch (token->get_id ()) | |
257 | { | |
258 | /* TODO: issue here - distinguish between method calls and field access | |
259 | * somehow? Also would have to distinguish between paths and function | |
260 | * calls (:: operator), maybe more stuff. */ | |
261 | /* Current plan for tackling LBP - don't do it based on token, use | |
262 | * lookahead. Or alternatively, only use Pratt parsing for OperatorExpr | |
263 | * and handle other expressions without it. rustc only considers | |
264 | * arithmetic, logical/relational, 'as', | |
265 | * '?=', ranges, colons, and assignment to have operator precedence and | |
266 | * associativity rules applicable. It then has | |
267 | * a separate "ExprPrecedence" that also includes binary operators. */ | |
268 | ||
269 | // TODO: handle operator overloading - have a function replace the | |
270 | // operator? | |
271 | ||
272 | /*case DOT: | |
273 | return LBP_DOT;*/ | |
274 | ||
275 | case SCOPE_RESOLUTION: | |
276 | rust_debug ( | |
277 | "possible error - looked up LBP of scope resolution operator. should " | |
278 | "be handled elsewhere."); | |
279 | return LBP_PATH; | |
280 | ||
281 | /* Resolved by lookahead HACK that should work with current code. If next | |
282 | * token is identifier and token after that isn't parenthesised expression | |
283 | * list, it is a field reference. */ | |
284 | case DOT: | |
285 | if (lexer.peek_token (1)->get_id () == IDENTIFIER | |
286 | && lexer.peek_token (2)->get_id () != LEFT_PAREN) | |
287 | { | |
288 | return LBP_FIELD_EXPR; | |
289 | } | |
290 | return LBP_METHOD_CALL; | |
291 | ||
292 | case LEFT_PAREN: | |
293 | return LBP_FUNCTION_CALL; | |
294 | ||
295 | case LEFT_SQUARE: | |
296 | return LBP_ARRAY_REF; | |
297 | ||
298 | // postfix question mark (i.e. error propagation expression) | |
299 | case QUESTION_MARK: | |
300 | return LBP_QUESTION_MARK; | |
301 | ||
302 | case AS: | |
303 | return LBP_AS; | |
304 | ||
305 | case ASTERISK: | |
306 | return LBP_MUL; | |
307 | case DIV: | |
308 | return LBP_DIV; | |
309 | case PERCENT: | |
310 | return LBP_MOD; | |
311 | ||
312 | case PLUS: | |
313 | return LBP_PLUS; | |
314 | case MINUS: | |
315 | return LBP_MINUS; | |
316 | ||
317 | case LEFT_SHIFT: | |
318 | return LBP_L_SHIFT; | |
319 | case RIGHT_SHIFT: | |
320 | return LBP_R_SHIFT; | |
321 | ||
322 | // binary & operator | |
323 | case AMP: | |
324 | return LBP_AMP; | |
325 | ||
326 | // binary ^ operator | |
327 | case CARET: | |
328 | return LBP_CARET; | |
329 | ||
330 | // binary | operator | |
331 | case PIPE: | |
332 | return LBP_PIPE; | |
333 | ||
334 | case EQUAL_EQUAL: | |
335 | return LBP_EQUAL; | |
336 | case NOT_EQUAL: | |
337 | return LBP_NOT_EQUAL; | |
338 | case RIGHT_ANGLE: | |
339 | return LBP_GREATER_THAN; | |
340 | case GREATER_OR_EQUAL: | |
341 | return LBP_GREATER_EQUAL; | |
342 | case LEFT_ANGLE: | |
343 | return LBP_SMALLER_THAN; | |
344 | case LESS_OR_EQUAL: | |
345 | return LBP_SMALLER_EQUAL; | |
346 | ||
347 | case LOGICAL_AND: | |
348 | return LBP_LOGICAL_AND; | |
349 | ||
350 | case OR: | |
351 | return LBP_LOGICAL_OR; | |
352 | ||
353 | case DOT_DOT: | |
354 | return LBP_DOT_DOT; | |
355 | ||
356 | case DOT_DOT_EQ: | |
357 | return LBP_DOT_DOT_EQ; | |
358 | ||
359 | case EQUAL: | |
360 | return LBP_ASSIG; | |
361 | case PLUS_EQ: | |
362 | return LBP_PLUS_ASSIG; | |
363 | case MINUS_EQ: | |
364 | return LBP_MINUS_ASSIG; | |
365 | case ASTERISK_EQ: | |
366 | return LBP_MULT_ASSIG; | |
367 | case DIV_EQ: | |
368 | return LBP_DIV_ASSIG; | |
369 | case PERCENT_EQ: | |
370 | return LBP_MOD_ASSIG; | |
371 | case AMP_EQ: | |
372 | return LBP_AMP_ASSIG; | |
373 | case PIPE_EQ: | |
374 | return LBP_PIPE_ASSIG; | |
375 | case CARET_EQ: | |
376 | return LBP_CARET_ASSIG; | |
377 | case LEFT_SHIFT_EQ: | |
378 | return LBP_L_SHIFT_ASSIG; | |
379 | case RIGHT_SHIFT_EQ: | |
380 | return LBP_R_SHIFT_ASSIG; | |
381 | ||
382 | /* HACK: float literal due to lexer misidentifying a dot then an integer as | |
383 | * a float */ | |
384 | case FLOAT_LITERAL: | |
385 | return LBP_FIELD_EXPR; | |
386 | // field expr is same as tuple expr in precedence, i imagine | |
387 | // TODO: is this needed anymore? lexer shouldn't do that anymore | |
388 | ||
389 | // anything that can't appear in an infix position is given lowest priority | |
390 | default: | |
391 | return LBP_LOWEST; | |
392 | } | |
393 | } | |
394 | ||
395 | // Returns true when current token is EOF. | |
396 | template <typename ManagedTokenSource> | |
397 | bool | |
398 | Parser<ManagedTokenSource>::done_end_of_file () | |
399 | { | |
400 | return lexer.peek_token ()->get_id () == END_OF_FILE; | |
401 | } | |
402 | ||
403 | // Parses a sequence of items within a module or the implicit top-level module | |
404 | // in a crate | |
405 | template <typename ManagedTokenSource> | |
406 | std::vector<std::unique_ptr<AST::Item>> | |
407 | Parser<ManagedTokenSource>::parse_items () | |
408 | { | |
409 | std::vector<std::unique_ptr<AST::Item>> items; | |
410 | ||
411 | const_TokenPtr t = lexer.peek_token (); | |
412 | while (t->get_id () != END_OF_FILE) | |
413 | { | |
414 | std::unique_ptr<AST::Item> item = parse_item (false); | |
415 | if (item == nullptr) | |
416 | { | |
417 | Error error (lexer.peek_token ()->get_locus (), | |
418 | "failed to parse item in crate"); | |
419 | add_error (std::move (error)); | |
420 | ||
421 | // TODO: should all items be cleared? | |
422 | items = std::vector<std::unique_ptr<AST::Item>> (); | |
423 | break; | |
424 | } | |
425 | ||
426 | items.push_back (std::move (item)); | |
427 | ||
428 | t = lexer.peek_token (); | |
429 | } | |
430 | ||
431 | return items; | |
432 | } | |
433 | ||
434 | // Parses a crate (compilation unit) - entry point | |
435 | template <typename ManagedTokenSource> | |
436 | std::unique_ptr<AST::Crate> | |
437 | Parser<ManagedTokenSource>::parse_crate () | |
438 | { | |
439 | // parse inner attributes | |
440 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
441 | ||
442 | // parse items | |
443 | std::vector<std::unique_ptr<AST::Item>> items = parse_items (); | |
444 | ||
445 | // emit all errors | |
446 | for (const auto &error : error_table) | |
447 | error.emit_error (); | |
448 | ||
449 | return std::unique_ptr<AST::Crate> ( | |
450 | new AST::Crate (std::move (items), std::move (inner_attrs))); | |
451 | } | |
452 | ||
453 | // Parse a contiguous block of inner attributes. | |
454 | template <typename ManagedTokenSource> | |
455 | AST::AttrVec | |
456 | Parser<ManagedTokenSource>::parse_inner_attributes () | |
457 | { | |
458 | AST::AttrVec inner_attributes; | |
459 | ||
460 | // only try to parse it if it starts with "#!" not only "#" | |
461 | while ((lexer.peek_token ()->get_id () == HASH | |
462 | && lexer.peek_token (1)->get_id () == EXCLAM) | |
463 | || lexer.peek_token ()->get_id () == INNER_DOC_COMMENT) | |
464 | { | |
465 | AST::Attribute inner_attr = parse_inner_attribute (); | |
466 | ||
467 | /* Ensure only valid inner attributes are added to the inner_attributes | |
468 | * list */ | |
469 | if (!inner_attr.is_empty ()) | |
470 | { | |
471 | inner_attributes.push_back (std::move (inner_attr)); | |
472 | } | |
473 | else | |
474 | { | |
475 | /* If no more valid inner attributes, break out of loop (only | |
476 | * contiguous inner attributes parsed). */ | |
477 | break; | |
478 | } | |
479 | } | |
480 | ||
481 | inner_attributes.shrink_to_fit (); | |
482 | return inner_attributes; | |
483 | } | |
484 | ||
485 | // Parse a inner or outer doc comment into an doc attribute | |
486 | template <typename ManagedTokenSource> | |
487 | AST::Attribute | |
488 | Parser<ManagedTokenSource>::parse_doc_comment () | |
489 | { | |
490 | const_TokenPtr token = lexer.peek_token (); | |
491 | Location locus = token->get_locus (); | |
492 | AST::SimplePathSegment segment ("doc", locus); | |
493 | std::vector<AST::SimplePathSegment> segments; | |
494 | segments.push_back (std::move (segment)); | |
495 | AST::SimplePath attr_path (std::move (segments), false, locus); | |
496 | AST::LiteralExpr lit_expr (token->get_str (), AST::Literal::STRING, | |
497 | PrimitiveCoreType::CORETYPE_STR, {}, locus); | |
498 | std::unique_ptr<AST::AttrInput> attr_input ( | |
499 | new AST::AttrInputLiteral (std::move (lit_expr))); | |
500 | lexer.skip_token (); | |
501 | return AST::Attribute (std::move (attr_path), std::move (attr_input), locus); | |
502 | } | |
503 | ||
504 | // Parse a single inner attribute. | |
505 | template <typename ManagedTokenSource> | |
506 | AST::Attribute | |
507 | Parser<ManagedTokenSource>::parse_inner_attribute () | |
508 | { | |
509 | if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT) | |
510 | return parse_doc_comment (); | |
511 | ||
512 | if (lexer.peek_token ()->get_id () != HASH) | |
513 | { | |
514 | Error error (lexer.peek_token ()->get_locus (), | |
515 | "BUG: token %<#%> is missing, but %<parse_inner_attribute%> " | |
516 | "was invoked"); | |
517 | add_error (std::move (error)); | |
518 | ||
519 | return AST::Attribute::create_empty (); | |
520 | } | |
521 | lexer.skip_token (); | |
522 | ||
523 | if (lexer.peek_token ()->get_id () != EXCLAM) | |
524 | { | |
525 | Error error (lexer.peek_token ()->get_locus (), | |
526 | "expected %<!%> or %<[%> for inner attribute"); | |
527 | add_error (std::move (error)); | |
528 | ||
529 | return AST::Attribute::create_empty (); | |
530 | } | |
531 | lexer.skip_token (); | |
532 | ||
533 | if (!skip_token (LEFT_SQUARE)) | |
534 | return AST::Attribute::create_empty (); | |
535 | ||
536 | AST::Attribute actual_attribute = parse_attribute_body (); | |
537 | ||
538 | if (!skip_token (RIGHT_SQUARE)) | |
539 | return AST::Attribute::create_empty (); | |
540 | ||
541 | return actual_attribute; | |
542 | } | |
543 | ||
544 | // Parses the body of an attribute (inner or outer). | |
545 | template <typename ManagedTokenSource> | |
546 | AST::Attribute | |
547 | Parser<ManagedTokenSource>::parse_attribute_body () | |
548 | { | |
549 | Location locus = lexer.peek_token ()->get_locus (); | |
550 | ||
551 | AST::SimplePath attr_path = parse_simple_path (); | |
552 | // ensure path is valid to parse attribute input | |
553 | if (attr_path.is_empty ()) | |
554 | { | |
555 | Error error (lexer.peek_token ()->get_locus (), | |
556 | "empty simple path in attribute"); | |
557 | add_error (std::move (error)); | |
558 | ||
559 | // Skip past potential further info in attribute (i.e. attr_input) | |
560 | skip_after_end_attribute (); | |
561 | return AST::Attribute::create_empty (); | |
562 | } | |
563 | ||
564 | std::unique_ptr<AST::AttrInput> attr_input = parse_attr_input (); | |
565 | // AttrInput is allowed to be null, so no checks here | |
566 | ||
567 | return AST::Attribute (std::move (attr_path), std::move (attr_input), locus); | |
568 | } | |
569 | ||
570 | /* Determines whether token is a valid simple path segment. This does not | |
571 | * include scope resolution operators. */ | |
572 | inline bool | |
573 | is_simple_path_segment (TokenId id) | |
574 | { | |
575 | switch (id) | |
576 | { | |
577 | case IDENTIFIER: | |
578 | case SUPER: | |
579 | case SELF: | |
580 | case CRATE: | |
581 | return true; | |
582 | case DOLLAR_SIGN: | |
583 | // assume that dollar sign leads to $crate | |
584 | return true; | |
585 | default: | |
586 | return false; | |
587 | } | |
588 | } | |
589 | ||
590 | // Parses a SimplePath AST node, if it exists. Does nothing otherwise. | |
591 | template <typename ManagedTokenSource> | |
592 | AST::SimplePath | |
593 | Parser<ManagedTokenSource>::parse_simple_path () | |
594 | { | |
595 | bool has_opening_scope_resolution = false; | |
596 | Location locus = Linemap::unknown_location (); | |
597 | ||
598 | // don't parse anything if not a path upfront | |
599 | if (!is_simple_path_segment (lexer.peek_token ()->get_id ()) | |
600 | && !is_simple_path_segment (lexer.peek_token (1)->get_id ())) | |
601 | return AST::SimplePath::create_empty (); | |
602 | ||
603 | /* Checks for opening scope resolution (i.e. global scope fully-qualified | |
604 | * path) */ | |
605 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION) | |
606 | { | |
607 | has_opening_scope_resolution = true; | |
608 | ||
609 | locus = lexer.peek_token ()->get_locus (); | |
610 | ||
611 | lexer.skip_token (); | |
612 | } | |
613 | ||
614 | // Parse single required simple path segment | |
615 | AST::SimplePathSegment segment = parse_simple_path_segment (); | |
616 | ||
617 | // get location if not gotten already | |
618 | if (locus == Linemap::unknown_location ()) | |
619 | locus = segment.get_locus (); | |
620 | ||
621 | std::vector<AST::SimplePathSegment> segments; | |
622 | ||
623 | // Return empty vector if first, actually required segment is an error | |
624 | if (segment.is_error ()) | |
625 | return AST::SimplePath::create_empty (); | |
626 | ||
627 | segments.push_back (std::move (segment)); | |
628 | ||
629 | // Parse all other simple path segments | |
630 | while (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION) | |
631 | { | |
632 | // Skip scope resolution operator | |
633 | lexer.skip_token (); | |
634 | ||
635 | AST::SimplePathSegment new_segment = parse_simple_path_segment (); | |
636 | ||
637 | // Return path as currently constructed if segment in error state. | |
638 | if (new_segment.is_error ()) | |
639 | break; | |
640 | ||
641 | segments.push_back (std::move (new_segment)); | |
642 | } | |
643 | ||
644 | // DEBUG: check for any empty segments | |
645 | for (const auto &seg : segments) | |
646 | { | |
647 | if (seg.is_error ()) | |
648 | { | |
649 | rust_debug ( | |
650 | "when parsing simple path, somehow empty path segment was " | |
651 | "not filtered out. Path begins with '%s'", | |
652 | segments.at (0).as_string ().c_str ()); | |
653 | } | |
654 | } | |
655 | ||
656 | return AST::SimplePath (std::move (segments), has_opening_scope_resolution, | |
657 | locus); | |
658 | /* TODO: now that is_simple_path_segment exists, could probably start | |
659 | * actually making errors upon parse failure of segments and whatever */ | |
660 | } | |
661 | ||
662 | /* Parses a single SimplePathSegment (does not handle the scope resolution | |
663 | * operators) */ | |
664 | template <typename ManagedTokenSource> | |
665 | AST::SimplePathSegment | |
666 | Parser<ManagedTokenSource>::parse_simple_path_segment () | |
667 | { | |
668 | const_TokenPtr t = lexer.peek_token (); | |
669 | switch (t->get_id ()) | |
670 | { | |
671 | case IDENTIFIER: | |
672 | lexer.skip_token (); | |
673 | ||
674 | return AST::SimplePathSegment (t->get_str (), t->get_locus ()); | |
675 | case SUPER: | |
676 | lexer.skip_token (); | |
677 | ||
678 | return AST::SimplePathSegment ("super", t->get_locus ()); | |
679 | case SELF: | |
680 | lexer.skip_token (); | |
681 | ||
682 | return AST::SimplePathSegment ("self", t->get_locus ()); | |
683 | case CRATE: | |
684 | lexer.skip_token (); | |
685 | ||
686 | return AST::SimplePathSegment ("crate", t->get_locus ()); | |
687 | case DOLLAR_SIGN: | |
688 | if (lexer.peek_token (1)->get_id () == CRATE) | |
689 | { | |
690 | lexer.skip_token (1); | |
691 | ||
692 | return AST::SimplePathSegment ("$crate", t->get_locus ()); | |
693 | } | |
694 | gcc_fallthrough (); | |
695 | default: | |
696 | // do nothing but inactivates warning from gcc when compiling | |
697 | /* could put the rust_error_at thing here but fallthrough (from failing | |
698 | * $crate condition) isn't completely obvious if it is. */ | |
699 | ||
700 | // test prevent error | |
701 | return AST::SimplePathSegment::create_error (); | |
702 | } | |
703 | gcc_unreachable (); | |
704 | /*rust_error_at( | |
705 | t->get_locus(), "invalid token '%s' in simple path segment", | |
706 | t->get_token_description());*/ | |
707 | // this is not necessarily an error, e.g. end of path | |
708 | // return AST::SimplePathSegment::create_error(); | |
709 | } | |
710 | ||
711 | // Parses a PathIdentSegment - an identifier segment of a non-SimplePath path. | |
712 | template <typename ManagedTokenSource> | |
713 | AST::PathIdentSegment | |
714 | Parser<ManagedTokenSource>::parse_path_ident_segment () | |
715 | { | |
716 | const_TokenPtr t = lexer.peek_token (); | |
717 | switch (t->get_id ()) | |
718 | { | |
719 | case IDENTIFIER: | |
720 | lexer.skip_token (); | |
721 | ||
722 | return AST::PathIdentSegment (t->get_str (), t->get_locus ()); | |
723 | case SUPER: | |
724 | lexer.skip_token (); | |
725 | ||
726 | return AST::PathIdentSegment ("super", t->get_locus ()); | |
727 | case SELF: | |
728 | lexer.skip_token (); | |
729 | ||
730 | return AST::PathIdentSegment ("self", t->get_locus ()); | |
731 | case SELF_ALIAS: | |
732 | lexer.skip_token (); | |
733 | ||
734 | return AST::PathIdentSegment ("Self", t->get_locus ()); | |
735 | case CRATE: | |
736 | lexer.skip_token (); | |
737 | ||
738 | return AST::PathIdentSegment ("crate", t->get_locus ()); | |
739 | case DOLLAR_SIGN: | |
740 | if (lexer.peek_token (1)->get_id () == CRATE) | |
741 | { | |
742 | lexer.skip_token (1); | |
743 | ||
744 | return AST::PathIdentSegment ("$crate", t->get_locus ()); | |
745 | } | |
746 | gcc_fallthrough (); | |
747 | default: | |
748 | /* do nothing but inactivates warning from gcc when compiling | |
749 | * could put the error_at thing here but fallthrough (from failing $crate | |
750 | * condition) isn't completely obvious if it is. */ | |
751 | ||
752 | // test prevent error | |
753 | return AST::PathIdentSegment::create_error (); | |
754 | } | |
755 | gcc_unreachable (); | |
756 | // not necessarily an error | |
757 | } | |
758 | ||
759 | // Parses an AttrInput AST node (polymorphic, as AttrInput is abstract) | |
760 | template <typename ManagedTokenSource> | |
761 | std::unique_ptr<AST::AttrInput> | |
762 | Parser<ManagedTokenSource>::parse_attr_input () | |
763 | { | |
764 | const_TokenPtr t = lexer.peek_token (); | |
765 | switch (t->get_id ()) | |
766 | { | |
767 | case LEFT_PAREN: | |
768 | case LEFT_SQUARE: | |
769 | case LEFT_CURLY: { | |
770 | // must be a delimited token tree, so parse that | |
771 | std::unique_ptr<AST::AttrInput> input_tree ( | |
772 | new AST::DelimTokenTree (parse_delim_token_tree ())); | |
773 | ||
774 | // TODO: potential checks on DelimTokenTree before returning | |
775 | ||
776 | return input_tree; | |
777 | } | |
778 | case EQUAL: { | |
779 | // = LiteralExpr | |
780 | lexer.skip_token (); | |
781 | ||
782 | t = lexer.peek_token (); | |
783 | ||
784 | /* Ensure token is a "literal expression" (literally only a literal | |
785 | * token of any type) */ | |
786 | if (!t->is_literal ()) | |
787 | { | |
788 | Error error ( | |
789 | t->get_locus (), | |
790 | "unknown token %qs in attribute body - literal expected", | |
791 | t->get_token_description ()); | |
792 | add_error (std::move (error)); | |
793 | ||
794 | skip_after_end_attribute (); | |
795 | return nullptr; | |
796 | } | |
797 | ||
798 | AST::Literal::LitType lit_type = AST::Literal::STRING; | |
799 | // Crappy mapping of token type to literal type | |
800 | switch (t->get_id ()) | |
801 | { | |
802 | case INT_LITERAL: | |
803 | lit_type = AST::Literal::INT; | |
804 | break; | |
805 | case FLOAT_LITERAL: | |
806 | lit_type = AST::Literal::FLOAT; | |
807 | break; | |
808 | case CHAR_LITERAL: | |
809 | lit_type = AST::Literal::CHAR; | |
810 | break; | |
811 | case BYTE_CHAR_LITERAL: | |
812 | lit_type = AST::Literal::BYTE; | |
813 | break; | |
814 | case BYTE_STRING_LITERAL: | |
815 | lit_type = AST::Literal::BYTE_STRING; | |
816 | break; | |
817 | case STRING_LITERAL: | |
818 | default: | |
819 | lit_type = AST::Literal::STRING; | |
820 | break; // TODO: raw string? don't eliminate it from lexer? | |
821 | } | |
822 | ||
823 | // create actual LiteralExpr | |
824 | AST::LiteralExpr lit_expr (t->get_str (), lit_type, t->get_type_hint (), | |
825 | {}, t->get_locus ()); | |
826 | lexer.skip_token (); | |
827 | ||
828 | std::unique_ptr<AST::AttrInput> attr_input_lit ( | |
829 | new AST::AttrInputLiteral (std::move (lit_expr))); | |
830 | ||
831 | // do checks or whatever? none required, really | |
832 | ||
833 | // FIXME: shouldn't a skip token be required here? | |
834 | ||
835 | return attr_input_lit; | |
836 | } | |
837 | break; | |
838 | case RIGHT_SQUARE: | |
839 | // means AttrInput is missing, which is allowed | |
840 | return nullptr; | |
841 | default: | |
842 | add_error ( | |
843 | Error (t->get_locus (), | |
844 | "unknown token %qs in attribute body - attribute input or " | |
845 | "none expected", | |
846 | t->get_token_description ())); | |
847 | ||
848 | skip_after_end_attribute (); | |
849 | return nullptr; | |
850 | } | |
851 | gcc_unreachable (); | |
852 | // TODO: find out how to stop gcc error on "no return value" | |
853 | } | |
854 | ||
855 | /* Returns true if the token id matches the delimiter type. Note that this only | |
856 | * operates for END delimiter tokens. */ | |
857 | inline bool | |
858 | token_id_matches_delims (TokenId token_id, AST::DelimType delim_type) | |
859 | { | |
860 | return ((token_id == RIGHT_PAREN && delim_type == AST::PARENS) | |
861 | || (token_id == RIGHT_SQUARE && delim_type == AST::SQUARE) | |
862 | || (token_id == RIGHT_CURLY && delim_type == AST::CURLY)); | |
863 | } | |
864 | ||
865 | /* Returns true if the likely result of parsing the next few tokens is a path. | |
866 | * Not guaranteed, though, especially in the case of syntax errors. */ | |
867 | inline bool | |
868 | is_likely_path_next (TokenId next_token_id) | |
869 | { | |
870 | switch (next_token_id) | |
871 | { | |
872 | case IDENTIFIER: | |
873 | case SUPER: | |
874 | case SELF: | |
875 | case SELF_ALIAS: | |
876 | case CRATE: | |
877 | // maybe - maybe do extra check. But then requires another TokenId. | |
878 | case DOLLAR_SIGN: | |
879 | case SCOPE_RESOLUTION: | |
880 | return true; | |
881 | default: | |
882 | return false; | |
883 | } | |
884 | } | |
885 | ||
886 | // Parses a delimited token tree | |
887 | template <typename ManagedTokenSource> | |
888 | AST::DelimTokenTree | |
889 | Parser<ManagedTokenSource>::parse_delim_token_tree () | |
890 | { | |
891 | const_TokenPtr t = lexer.peek_token (); | |
892 | lexer.skip_token (); | |
893 | Location initial_loc = t->get_locus (); | |
894 | ||
895 | // save delim type to ensure it is reused later | |
896 | AST::DelimType delim_type = AST::PARENS; | |
897 | ||
898 | // Map tokens to DelimType | |
899 | switch (t->get_id ()) | |
900 | { | |
901 | case LEFT_PAREN: | |
902 | delim_type = AST::PARENS; | |
903 | break; | |
904 | case LEFT_SQUARE: | |
905 | delim_type = AST::SQUARE; | |
906 | break; | |
907 | case LEFT_CURLY: | |
908 | delim_type = AST::CURLY; | |
909 | break; | |
910 | default: | |
911 | add_error (Error (t->get_locus (), | |
912 | "unexpected token %qs - expecting delimiters (for a " | |
913 | "delimited token tree)", | |
914 | t->get_token_description ())); | |
915 | ||
916 | return AST::DelimTokenTree::create_empty (); | |
917 | } | |
918 | ||
919 | // parse actual token tree vector - 0 or more | |
920 | std::vector<std::unique_ptr<AST::TokenTree>> token_trees_in_tree; | |
921 | auto delim_open | |
922 | = std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
923 | token_trees_in_tree.push_back (std::move (delim_open)); | |
924 | ||
925 | // repeat loop until finding the matching delimiter | |
926 | t = lexer.peek_token (); | |
927 | while (!token_id_matches_delims (t->get_id (), delim_type) | |
928 | && t->get_id () != END_OF_FILE) | |
929 | { | |
930 | std::unique_ptr<AST::TokenTree> tok_tree = parse_token_tree (); | |
931 | ||
932 | if (tok_tree == nullptr) | |
933 | { | |
934 | // TODO: is this error handling appropriate? | |
935 | Error error ( | |
936 | t->get_locus (), | |
937 | "failed to parse token tree in delimited token tree - found %qs", | |
938 | t->get_token_description ()); | |
939 | add_error (std::move (error)); | |
940 | ||
941 | return AST::DelimTokenTree::create_empty (); | |
942 | } | |
943 | ||
944 | token_trees_in_tree.push_back (std::move (tok_tree)); | |
945 | ||
946 | // lexer.skip_token(); | |
947 | t = lexer.peek_token (); | |
948 | } | |
949 | auto delim_close | |
950 | = std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
951 | token_trees_in_tree.push_back (std::move (delim_close)); | |
952 | ||
953 | AST::DelimTokenTree token_tree (delim_type, std::move (token_trees_in_tree), | |
954 | initial_loc); | |
955 | ||
956 | // parse end delimiters | |
957 | t = lexer.peek_token (); | |
958 | ||
959 | if (token_id_matches_delims (t->get_id (), delim_type)) | |
960 | { | |
961 | // tokens match opening delimiter, so skip. | |
962 | lexer.skip_token (); | |
963 | ||
964 | // DEBUG | |
965 | rust_debug ("finished parsing new delim token tree - peeked token is now " | |
966 | "'%s' while t is '%s'", | |
967 | lexer.peek_token ()->get_token_description (), | |
968 | t->get_token_description ()); | |
969 | ||
970 | return token_tree; | |
971 | } | |
972 | else | |
973 | { | |
974 | // tokens don't match opening delimiters, so produce error | |
975 | Error error (t->get_locus (), | |
976 | "unexpected token %qs - expecting closing delimiter %qs " | |
977 | "(for a delimited token tree)", | |
978 | t->get_token_description (), | |
979 | (delim_type == AST::PARENS | |
980 | ? ")" | |
981 | : (delim_type == AST::SQUARE ? "]" : "}"))); | |
982 | add_error (std::move (error)); | |
983 | ||
984 | /* return empty token tree despite possibly parsing valid token tree - | |
985 | * TODO is this a good idea? */ | |
986 | return AST::DelimTokenTree::create_empty (); | |
987 | } | |
988 | } | |
989 | ||
990 | /* Parses a TokenTree syntactical production. This is either a delimited token | |
991 | * tree or a non-delimiter token. */ | |
992 | template <typename ManagedTokenSource> | |
993 | std::unique_ptr<AST::TokenTree> | |
994 | Parser<ManagedTokenSource>::parse_token_tree () | |
995 | { | |
996 | const_TokenPtr t = lexer.peek_token (); | |
997 | ||
998 | switch (t->get_id ()) | |
999 | { | |
1000 | case LEFT_PAREN: | |
1001 | case LEFT_SQUARE: | |
1002 | case LEFT_CURLY: | |
1003 | // Parse delimited token tree | |
1004 | // TODO: use move rather than copy constructor | |
1005 | return std::unique_ptr<AST::DelimTokenTree> ( | |
1006 | new AST::DelimTokenTree (parse_delim_token_tree ())); | |
1007 | case RIGHT_PAREN: | |
1008 | case RIGHT_SQUARE: | |
1009 | case RIGHT_CURLY: | |
1010 | // error - should not be called when this a token | |
1011 | add_error ( | |
1012 | Error (t->get_locus (), | |
1013 | "unexpected closing delimiter %qs - token tree requires " | |
1014 | "either paired delimiters or non-delimiter tokens", | |
1015 | t->get_token_description ())); | |
1016 | ||
1017 | lexer.skip_token (); | |
1018 | return nullptr; | |
1019 | default: | |
1020 | // parse token itself as TokenTree | |
1021 | lexer.skip_token (); | |
1022 | return std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
1023 | } | |
1024 | } | |
1025 | ||
1026 | // Parses a single item | |
1027 | template <typename ManagedTokenSource> | |
1028 | std::unique_ptr<AST::Item> | |
1029 | Parser<ManagedTokenSource>::parse_item (bool called_from_statement) | |
1030 | { | |
1031 | // has a "called_from_statement" parameter for better error message handling | |
1032 | ||
1033 | // parse outer attributes for item | |
1034 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
1035 | ||
1036 | // TODO: decide how to deal with VisItem vs MacroItem dichotomy | |
1037 | /* best current solution: catch all keywords that would imply a VisItem in a | |
1038 | * switch and have MacroItem as a last resort */ | |
1039 | ||
1040 | const_TokenPtr t = lexer.peek_token (); | |
1041 | ||
1042 | switch (t->get_id ()) | |
1043 | { | |
1044 | case END_OF_FILE: | |
1045 | // not necessarily an error, unless we just read outer | |
1046 | // attributes which needs to be attached | |
1047 | if (!outer_attrs.empty ()) | |
1048 | { | |
1049 | Rust::AST::Attribute attr = outer_attrs.back (); | |
1050 | Error error (attr.get_locus (), | |
1051 | "expected item after outer attribute or doc comment"); | |
1052 | add_error (std::move (error)); | |
1053 | } | |
1054 | return nullptr; | |
1055 | case PUB: | |
1056 | case MOD: | |
1057 | case EXTERN_TOK: | |
1058 | case USE: | |
1059 | case FN_TOK: | |
1060 | case TYPE: | |
1061 | case STRUCT_TOK: | |
1062 | case ENUM_TOK: | |
1063 | case CONST: | |
1064 | case STATIC_TOK: | |
1065 | case TRAIT: | |
1066 | case IMPL: | |
1067 | /* TODO: implement union keyword but not really because of | |
1068 | * context-dependence crappy hack way to parse a union written below to | |
1069 | * separate it from the good code. */ | |
1070 | // case UNION: | |
1071 | case UNSAFE: // maybe - unsafe traits are a thing | |
1072 | // if any of these (should be all possible VisItem prefixes), parse a | |
1073 | // VisItem | |
1074 | return parse_vis_item (std::move (outer_attrs)); | |
1075 | break; | |
1076 | case SUPER: | |
1077 | case SELF: | |
1078 | case CRATE: | |
1079 | case DOLLAR_SIGN: | |
1080 | // almost certainly macro invocation semi | |
1081 | return parse_macro_item (std::move (outer_attrs)); | |
1082 | break; | |
1083 | // crappy hack to do union "keyword" | |
1084 | case IDENTIFIER: | |
1085 | // TODO: ensure std::string and literal comparison works | |
1086 | if (t->get_str () == "union" | |
1087 | && lexer.peek_token (1)->get_id () == IDENTIFIER) | |
1088 | { | |
1089 | return parse_vis_item (std::move (outer_attrs)); | |
1090 | // or should this go straight to parsing union? | |
1091 | } | |
1092 | else if (t->get_str () == "macro_rules") | |
1093 | { | |
1094 | // macro_rules! macro item | |
1095 | return parse_macro_item (std::move (outer_attrs)); | |
1096 | } | |
1097 | else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION | |
1098 | || lexer.peek_token (1)->get_id () == EXCLAM) | |
1099 | { | |
1100 | /* path (probably) or macro invocation, so probably a macro invocation | |
1101 | * semi */ | |
1102 | return parse_macro_item (std::move (outer_attrs)); | |
1103 | } | |
1104 | gcc_fallthrough (); | |
1105 | default: | |
1106 | // otherwise unrecognised | |
1107 | // return parse_macro_item(std::move(outer_attrs)); | |
1108 | add_error (Error (t->get_locus (), | |
1109 | "unrecognised token %qs for start of %s", | |
1110 | t->get_token_description (), | |
1111 | called_from_statement ? "statement" : "item")); | |
1112 | ||
1113 | // skip somewhere? | |
1114 | return nullptr; | |
1115 | break; | |
1116 | } | |
1117 | } | |
1118 | ||
1119 | // Parses a contiguous block of outer attributes. | |
1120 | template <typename ManagedTokenSource> | |
1121 | AST::AttrVec | |
1122 | Parser<ManagedTokenSource>::parse_outer_attributes () | |
1123 | { | |
1124 | AST::AttrVec outer_attributes; | |
1125 | ||
1126 | while (lexer.peek_token ()->get_id () | |
1127 | == HASH /* Can also be #!, which catches errors. */ | |
1128 | || lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT | |
1129 | || lexer.peek_token ()->get_id () | |
1130 | == INNER_DOC_COMMENT) /* For error handling. */ | |
1131 | { | |
1132 | AST::Attribute outer_attr = parse_outer_attribute (); | |
1133 | ||
1134 | /* Ensure only valid outer attributes are added to the outer_attributes | |
1135 | * list */ | |
1136 | if (!outer_attr.is_empty ()) | |
1137 | { | |
1138 | outer_attributes.push_back (std::move (outer_attr)); | |
1139 | } | |
1140 | else | |
1141 | { | |
1142 | /* If no more valid outer attributes, break out of loop (only | |
1143 | * contiguous outer attributes parsed). */ | |
1144 | break; | |
1145 | } | |
1146 | } | |
1147 | ||
1148 | outer_attributes.shrink_to_fit (); | |
1149 | return outer_attributes; | |
1150 | ||
1151 | /* TODO: this shares basically all code with parse_inner_attributes except | |
1152 | * function call - find way of making it more modular? function pointer? */ | |
1153 | } | |
1154 | ||
1155 | // Parse a single outer attribute. | |
1156 | template <typename ManagedTokenSource> | |
1157 | AST::Attribute | |
1158 | Parser<ManagedTokenSource>::parse_outer_attribute () | |
1159 | { | |
1160 | if (lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT) | |
1161 | return parse_doc_comment (); | |
1162 | ||
1163 | if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT) | |
1164 | { | |
1165 | Error error ( | |
1166 | lexer.peek_token ()->get_locus (), | |
1167 | "inner doc (%<//!%> or %</*!%>) only allowed at start of item " | |
1168 | "and before any outer attribute or doc (%<#[%>, %<///%> or %</**%>)"); | |
1169 | add_error (std::move (error)); | |
1170 | lexer.skip_token (); | |
1171 | return AST::Attribute::create_empty (); | |
1172 | } | |
1173 | ||
1174 | /* OuterAttribute -> '#' '[' Attr ']' */ | |
1175 | ||
1176 | if (lexer.peek_token ()->get_id () != HASH) | |
1177 | return AST::Attribute::create_empty (); | |
1178 | ||
1179 | lexer.skip_token (); | |
1180 | ||
1181 | TokenId id = lexer.peek_token ()->get_id (); | |
1182 | if (id != LEFT_SQUARE) | |
1183 | { | |
1184 | if (id == EXCLAM) | |
1185 | { | |
1186 | // this is inner attribute syntax, so throw error | |
1187 | // inner attributes were either already parsed or not allowed here. | |
1188 | Error error ( | |
1189 | lexer.peek_token ()->get_locus (), | |
1190 | "token %<!%> found, indicating inner attribute definition. Inner " | |
1191 | "attributes are not possible at this location"); | |
1192 | add_error (std::move (error)); | |
1193 | } | |
1194 | return AST::Attribute::create_empty (); | |
1195 | } | |
1196 | ||
1197 | lexer.skip_token (); | |
1198 | ||
1199 | AST::Attribute actual_attribute = parse_attribute_body (); | |
1200 | ||
1201 | if (lexer.peek_token ()->get_id () != RIGHT_SQUARE) | |
1202 | return AST::Attribute::create_empty (); | |
1203 | ||
1204 | lexer.skip_token (); | |
1205 | ||
1206 | return actual_attribute; | |
1207 | } | |
1208 | ||
1209 | // Parses a VisItem (item that can have non-default visibility). | |
1210 | template <typename ManagedTokenSource> | |
1211 | std::unique_ptr<AST::VisItem> | |
1212 | Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs) | |
1213 | { | |
1214 | // parse visibility, which may or may not exist | |
1215 | AST::Visibility vis = parse_visibility (); | |
1216 | ||
1217 | // select VisItem to create depending on keyword | |
1218 | const_TokenPtr t = lexer.peek_token (); | |
1219 | ||
1220 | switch (t->get_id ()) | |
1221 | { | |
1222 | case MOD: | |
1223 | return parse_module (std::move (vis), std::move (outer_attrs)); | |
1224 | case EXTERN_TOK: | |
1225 | // lookahead to resolve syntactical production | |
1226 | t = lexer.peek_token (1); | |
1227 | ||
1228 | switch (t->get_id ()) | |
1229 | { | |
1230 | case CRATE: | |
1231 | return parse_extern_crate (std::move (vis), std::move (outer_attrs)); | |
1232 | case FN_TOK: // extern function | |
1233 | return parse_function (std::move (vis), std::move (outer_attrs)); | |
1234 | case LEFT_CURLY: // extern block | |
1235 | return parse_extern_block (std::move (vis), std::move (outer_attrs)); | |
1236 | case STRING_LITERAL: // for specifying extern ABI | |
1237 | // could be extern block or extern function, so more lookahead | |
1238 | t = lexer.peek_token (2); | |
1239 | ||
1240 | switch (t->get_id ()) | |
1241 | { | |
1242 | case FN_TOK: | |
1243 | return parse_function (std::move (vis), std::move (outer_attrs)); | |
1244 | case LEFT_CURLY: | |
1245 | return parse_extern_block (std::move (vis), | |
1246 | std::move (outer_attrs)); | |
1247 | default: | |
1248 | add_error ( | |
1249 | Error (t->get_locus (), | |
1250 | "unexpected token %qs in some sort of extern production", | |
1251 | t->get_token_description ())); | |
1252 | ||
1253 | lexer.skip_token (2); // TODO: is this right thing to do? | |
1254 | return nullptr; | |
1255 | } | |
1256 | default: | |
1257 | add_error ( | |
1258 | Error (t->get_locus (), | |
1259 | "unexpected token %qs in some sort of extern production", | |
1260 | t->get_token_description ())); | |
1261 | ||
1262 | lexer.skip_token (1); // TODO: is this right thing to do? | |
1263 | return nullptr; | |
1264 | } | |
1265 | case USE: | |
1266 | return parse_use_decl (std::move (vis), std::move (outer_attrs)); | |
1267 | case FN_TOK: | |
1268 | return parse_function (std::move (vis), std::move (outer_attrs)); | |
1269 | case TYPE: | |
1270 | return parse_type_alias (std::move (vis), std::move (outer_attrs)); | |
1271 | case STRUCT_TOK: | |
1272 | return parse_struct (std::move (vis), std::move (outer_attrs)); | |
1273 | case ENUM_TOK: | |
1274 | return parse_enum (std::move (vis), std::move (outer_attrs)); | |
1275 | // TODO: implement union keyword but not really because of | |
1276 | // context-dependence case UNION: crappy hack to do union "keyword" | |
1277 | case IDENTIFIER: | |
1278 | if (t->get_str () == "union" | |
1279 | && lexer.peek_token (1)->get_id () == IDENTIFIER) | |
1280 | { | |
1281 | return parse_union (std::move (vis), std::move (outer_attrs)); | |
1282 | // or should item switch go straight to parsing union? | |
1283 | } | |
1284 | else | |
1285 | { | |
1286 | break; | |
1287 | } | |
1288 | case CONST: | |
1289 | // lookahead to resolve syntactical production | |
1290 | t = lexer.peek_token (1); | |
1291 | ||
1292 | switch (t->get_id ()) | |
1293 | { | |
1294 | case IDENTIFIER: | |
1295 | case UNDERSCORE: | |
1296 | return parse_const_item (std::move (vis), std::move (outer_attrs)); | |
1297 | case UNSAFE: | |
1298 | case EXTERN_TOK: | |
1299 | case FN_TOK: | |
1300 | return parse_function (std::move (vis), std::move (outer_attrs)); | |
1301 | default: | |
1302 | add_error ( | |
1303 | Error (t->get_locus (), | |
1304 | "unexpected token %qs in some sort of const production", | |
1305 | t->get_token_description ())); | |
1306 | ||
1307 | lexer.skip_token (1); // TODO: is this right thing to do? | |
1308 | return nullptr; | |
1309 | } | |
1310 | case STATIC_TOK: | |
1311 | return parse_static_item (std::move (vis), std::move (outer_attrs)); | |
1312 | case TRAIT: | |
1313 | return parse_trait (std::move (vis), std::move (outer_attrs)); | |
1314 | case IMPL: | |
1315 | return parse_impl (std::move (vis), std::move (outer_attrs)); | |
1316 | case UNSAFE: // unsafe traits, unsafe functions, unsafe impls (trait impls), | |
1317 | // lookahead to resolve syntactical production | |
1318 | t = lexer.peek_token (1); | |
1319 | ||
1320 | switch (t->get_id ()) | |
1321 | { | |
1322 | case TRAIT: | |
1323 | return parse_trait (std::move (vis), std::move (outer_attrs)); | |
1324 | case EXTERN_TOK: | |
1325 | case FN_TOK: | |
1326 | return parse_function (std::move (vis), std::move (outer_attrs)); | |
1327 | case IMPL: | |
1328 | return parse_impl (std::move (vis), std::move (outer_attrs)); | |
1329 | default: | |
1330 | add_error ( | |
1331 | Error (t->get_locus (), | |
1332 | "unexpected token %qs in some sort of unsafe production", | |
1333 | t->get_token_description ())); | |
1334 | ||
1335 | lexer.skip_token (1); // TODO: is this right thing to do? | |
1336 | return nullptr; | |
1337 | } | |
1338 | default: | |
1339 | // otherwise vis item clearly doesn't exist, which is not an error | |
1340 | // has a catch-all post-switch return to allow other breaks to occur | |
1341 | break; | |
1342 | } | |
1343 | return nullptr; | |
1344 | } | |
1345 | ||
1346 | // Parses a MacroItem (either a MacroInvocationSemi or MacroRulesDefinition). | |
1347 | template <typename ManagedTokenSource> | |
1348 | std::unique_ptr<AST::MacroItem> | |
1349 | Parser<ManagedTokenSource>::parse_macro_item (AST::AttrVec outer_attrs) | |
1350 | { | |
1351 | const_TokenPtr t = lexer.peek_token (); | |
1352 | ||
1353 | /* dodgy way of detecting macro due to weird context-dependence thing. | |
1354 | * probably can be improved */ | |
1355 | // TODO: ensure that string compare works properly | |
1356 | if (t->get_id () == IDENTIFIER && t->get_str () == "macro_rules") | |
1357 | { | |
1358 | return parse_macro_rules_def (std::move (outer_attrs)); | |
1359 | } | |
1360 | else | |
1361 | { | |
1362 | // DEBUG: TODO: remove | |
1363 | rust_debug ( | |
1364 | "DEBUG - parse_macro_item called and token is not macro_rules"); | |
1365 | if (t->get_id () == IDENTIFIER) | |
1366 | { | |
1367 | rust_debug ("just add to last error: token is not macro_rules and is " | |
1368 | "instead '%s'", | |
1369 | t->get_str ().c_str ()); | |
1370 | } | |
1371 | else | |
1372 | { | |
1373 | rust_debug ("just add to last error: token is not macro_rules and is " | |
1374 | "not an identifier either - it is '%s'", | |
1375 | t->get_token_description ()); | |
1376 | } | |
1377 | ||
1378 | return parse_macro_invocation_semi (std::move (outer_attrs)); | |
1379 | } | |
1380 | } | |
1381 | ||
1382 | // Parses a macro rules definition syntax extension whatever thing. | |
1383 | template <typename ManagedTokenSource> | |
1384 | std::unique_ptr<AST::MacroRulesDefinition> | |
1385 | Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs) | |
1386 | { | |
1387 | // ensure that first token is identifier saying "macro_rules" | |
1388 | const_TokenPtr t = lexer.peek_token (); | |
1389 | if (t->get_id () != IDENTIFIER || t->get_str () != "macro_rules") | |
1390 | { | |
1391 | Error error ( | |
1392 | t->get_locus (), | |
1393 | "macro rules definition does not start with %<macro_rules%>"); | |
1394 | add_error (std::move (error)); | |
1395 | ||
1396 | // skip after somewhere? | |
1397 | return nullptr; | |
1398 | } | |
1399 | lexer.skip_token (); | |
1400 | Location macro_locus = t->get_locus (); | |
1401 | ||
1402 | if (!skip_token (EXCLAM)) | |
1403 | { | |
1404 | // skip after somewhere? | |
1405 | return nullptr; | |
1406 | } | |
1407 | ||
1408 | // parse macro name | |
1409 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
1410 | if (ident_tok == nullptr) | |
1411 | { | |
1412 | return nullptr; | |
1413 | } | |
1414 | Identifier rule_name = ident_tok->get_str (); | |
1415 | ||
1416 | // DEBUG | |
1417 | rust_debug ("in macro rules def, about to parse parens."); | |
1418 | ||
1419 | // save delim type to ensure it is reused later | |
1420 | AST::DelimType delim_type = AST::PARENS; | |
1421 | ||
1422 | // Map tokens to DelimType | |
1423 | t = lexer.peek_token (); | |
1424 | switch (t->get_id ()) | |
1425 | { | |
1426 | case LEFT_PAREN: | |
1427 | delim_type = AST::PARENS; | |
1428 | break; | |
1429 | case LEFT_SQUARE: | |
1430 | delim_type = AST::SQUARE; | |
1431 | break; | |
1432 | case LEFT_CURLY: | |
1433 | delim_type = AST::CURLY; | |
1434 | break; | |
1435 | default: | |
1436 | add_error (Error (t->get_locus (), | |
1437 | "unexpected token %qs - expecting delimiters (for a " | |
1438 | "macro rules definition)", | |
1439 | t->get_token_description ())); | |
1440 | ||
1441 | return nullptr; | |
1442 | } | |
1443 | lexer.skip_token (); | |
1444 | ||
1445 | // parse actual macro rules | |
1446 | std::vector<AST::MacroRule> macro_rules; | |
1447 | ||
1448 | // must be at least one macro rule, so parse it | |
1449 | AST::MacroRule initial_rule = parse_macro_rule (); | |
1450 | if (initial_rule.is_error ()) | |
1451 | { | |
1452 | Error error (lexer.peek_token ()->get_locus (), | |
1453 | "required first macro rule in macro rules definition " | |
1454 | "could not be parsed"); | |
1455 | add_error (std::move (error)); | |
1456 | ||
1457 | // skip after somewhere? | |
1458 | return nullptr; | |
1459 | } | |
1460 | macro_rules.push_back (std::move (initial_rule)); | |
1461 | ||
1462 | // DEBUG | |
1463 | rust_debug ("successfully pushed back initial macro rule"); | |
1464 | ||
1465 | t = lexer.peek_token (); | |
1466 | // parse macro rules | |
1467 | while (t->get_id () == SEMICOLON) | |
1468 | { | |
1469 | // skip semicolon | |
1470 | lexer.skip_token (); | |
1471 | ||
1472 | // don't parse if end of macro rules | |
1473 | if (token_id_matches_delims (lexer.peek_token ()->get_id (), delim_type)) | |
1474 | { | |
1475 | // DEBUG | |
1476 | rust_debug ( | |
1477 | "broke out of parsing macro rules loop due to finding delim"); | |
1478 | ||
1479 | break; | |
1480 | } | |
1481 | ||
1482 | // try to parse next rule | |
1483 | AST::MacroRule rule = parse_macro_rule (); | |
1484 | if (rule.is_error ()) | |
1485 | { | |
1486 | Error error (lexer.peek_token ()->get_locus (), | |
1487 | "failed to parse macro rule in macro rules definition"); | |
1488 | add_error (std::move (error)); | |
1489 | ||
1490 | return nullptr; | |
1491 | } | |
1492 | ||
1493 | macro_rules.push_back (std::move (rule)); | |
1494 | ||
1495 | // DEBUG | |
1496 | rust_debug ("successfully pushed back another macro rule"); | |
1497 | ||
1498 | t = lexer.peek_token (); | |
1499 | } | |
1500 | ||
1501 | // parse end delimiters | |
1502 | t = lexer.peek_token (); | |
1503 | if (token_id_matches_delims (t->get_id (), delim_type)) | |
1504 | { | |
1505 | // tokens match opening delimiter, so skip. | |
1506 | lexer.skip_token (); | |
1507 | ||
1508 | if (delim_type != AST::CURLY) | |
1509 | { | |
1510 | // skip semicolon at end of non-curly macro definitions | |
1511 | if (!skip_token (SEMICOLON)) | |
1512 | { | |
1513 | // as this is the end, allow recovery (probably) - may change | |
1514 | return std::unique_ptr<AST::MacroRulesDefinition> ( | |
1515 | new AST::MacroRulesDefinition ( | |
1516 | std::move (rule_name), delim_type, std::move (macro_rules), | |
1517 | std::move (outer_attrs), macro_locus)); | |
1518 | } | |
1519 | } | |
1520 | ||
1521 | return std::unique_ptr<AST::MacroRulesDefinition> ( | |
1522 | new AST::MacroRulesDefinition (std::move (rule_name), delim_type, | |
1523 | std::move (macro_rules), | |
1524 | std::move (outer_attrs), macro_locus)); | |
1525 | } | |
1526 | else | |
1527 | { | |
1528 | // tokens don't match opening delimiters, so produce error | |
1529 | Error error (t->get_locus (), | |
1530 | "unexpected token %qs - expecting closing delimiter %qs " | |
1531 | "(for a macro rules definition)", | |
1532 | t->get_token_description (), | |
1533 | (delim_type == AST::PARENS | |
1534 | ? ")" | |
1535 | : (delim_type == AST::SQUARE ? "]" : "}"))); | |
1536 | add_error (std::move (error)); | |
1537 | ||
1538 | /* return empty macro definiton despite possibly parsing mostly valid one | |
1539 | * - TODO is this a good idea? */ | |
1540 | return nullptr; | |
1541 | } | |
1542 | } | |
1543 | ||
1544 | // Parses a semi-coloned (except for full block) macro invocation item. | |
1545 | template <typename ManagedTokenSource> | |
1546 | std::unique_ptr<AST::MacroInvocation> | |
1547 | Parser<ManagedTokenSource>::parse_macro_invocation_semi ( | |
1548 | AST::AttrVec outer_attrs) | |
1549 | { | |
1550 | Location macro_locus = lexer.peek_token ()->get_locus (); | |
1551 | AST::SimplePath path = parse_simple_path (); | |
1552 | ||
1553 | if (!skip_token (EXCLAM)) | |
1554 | { | |
1555 | // skip after somewhere? | |
1556 | return nullptr; | |
1557 | } | |
1558 | ||
1559 | // save delim type to ensure it is reused later | |
1560 | AST::DelimType delim_type = AST::PARENS; | |
1561 | ||
1562 | // Map tokens to DelimType | |
1563 | const_TokenPtr t = lexer.peek_token (); | |
1564 | switch (t->get_id ()) | |
1565 | { | |
1566 | case LEFT_PAREN: | |
1567 | delim_type = AST::PARENS; | |
1568 | break; | |
1569 | case LEFT_SQUARE: | |
1570 | delim_type = AST::SQUARE; | |
1571 | break; | |
1572 | case LEFT_CURLY: | |
1573 | delim_type = AST::CURLY; | |
1574 | break; | |
1575 | default: | |
1576 | add_error (Error (t->get_locus (), | |
1577 | "unexpected token %qs - expecting delimiters (for a " | |
1578 | "macro invocation semi body)", | |
1579 | t->get_token_description ())); | |
1580 | ||
1581 | return nullptr; | |
1582 | } | |
1583 | Location tok_tree_locus = t->get_locus (); | |
1584 | lexer.skip_token (); | |
1585 | ||
1586 | // parse actual token trees | |
1587 | std::vector<std::unique_ptr<AST::TokenTree>> token_trees; | |
1588 | auto delim_open | |
1589 | = std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
1590 | token_trees.push_back (std::move (delim_open)); | |
1591 | ||
1592 | t = lexer.peek_token (); | |
1593 | // parse token trees until the initial delimiter token is found again | |
1594 | while (!token_id_matches_delims (t->get_id (), delim_type)) | |
1595 | { | |
1596 | std::unique_ptr<AST::TokenTree> tree = parse_token_tree (); | |
1597 | ||
1598 | if (tree == nullptr) | |
1599 | { | |
1600 | Error error (t->get_locus (), | |
1601 | "failed to parse token tree for macro invocation semi " | |
1602 | "- found %qs", | |
1603 | t->get_token_description ()); | |
1604 | add_error (std::move (error)); | |
1605 | ||
1606 | return nullptr; | |
1607 | } | |
1608 | ||
1609 | token_trees.push_back (std::move (tree)); | |
1610 | ||
1611 | t = lexer.peek_token (); | |
1612 | } | |
1613 | auto delim_close | |
1614 | = std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
1615 | token_trees.push_back (std::move (delim_close)); | |
1616 | ||
1617 | AST::DelimTokenTree delim_tok_tree (delim_type, std::move (token_trees), | |
1618 | tok_tree_locus); | |
1619 | AST::MacroInvocData invoc_data (std::move (path), std::move (delim_tok_tree)); | |
1620 | ||
1621 | // parse end delimiters | |
1622 | t = lexer.peek_token (); | |
1623 | if (token_id_matches_delims (t->get_id (), delim_type)) | |
1624 | { | |
1625 | // tokens match opening delimiter, so skip. | |
1626 | lexer.skip_token (); | |
1627 | ||
1628 | if (delim_type != AST::CURLY) | |
1629 | { | |
1630 | // skip semicolon at end of non-curly macro invocation semis | |
1631 | if (!skip_token (SEMICOLON)) | |
1632 | { | |
1633 | // as this is the end, allow recovery (probably) - may change | |
1634 | ||
1635 | return std::unique_ptr<AST::MacroInvocation> ( | |
1636 | new AST::MacroInvocation (std::move (invoc_data), | |
1637 | std::move (outer_attrs), macro_locus, | |
1638 | true)); | |
1639 | } | |
1640 | } | |
1641 | ||
1642 | // DEBUG: | |
1643 | rust_debug ("skipped token is '%s', next token (current peek) is '%s'", | |
1644 | t->get_token_description (), | |
1645 | lexer.peek_token ()->get_token_description ()); | |
1646 | ||
1647 | return std::unique_ptr<AST::MacroInvocation> ( | |
1648 | new AST::MacroInvocation (std::move (invoc_data), | |
1649 | std::move (outer_attrs), macro_locus, true)); | |
1650 | } | |
1651 | else | |
1652 | { | |
1653 | // tokens don't match opening delimiters, so produce error | |
1654 | Error error (t->get_locus (), | |
1655 | "unexpected token %qs - expecting closing delimiter %qs " | |
1656 | "(for a macro invocation semi)", | |
1657 | t->get_token_description (), | |
1658 | (delim_type == AST::PARENS | |
1659 | ? ")" | |
1660 | : (delim_type == AST::SQUARE ? "]" : "}"))); | |
1661 | add_error (std::move (error)); | |
1662 | ||
1663 | /* return empty macro invocation despite possibly parsing mostly valid one | |
1664 | * - TODO is this a good idea? */ | |
1665 | return nullptr; | |
1666 | } | |
1667 | } | |
1668 | ||
1669 | // Parses a non-semicoloned macro invocation (i.e. as pattern or expression). | |
1670 | template <typename ManagedTokenSource> | |
1671 | std::unique_ptr<AST::MacroInvocation> | |
1672 | Parser<ManagedTokenSource>::parse_macro_invocation (AST::AttrVec outer_attrs) | |
1673 | { | |
1674 | // parse macro path | |
1675 | AST::SimplePath macro_path = parse_simple_path (); | |
1676 | if (macro_path.is_empty ()) | |
1677 | { | |
1678 | Error error (lexer.peek_token ()->get_locus (), | |
1679 | "failed to parse macro invocation path"); | |
1680 | add_error (std::move (error)); | |
1681 | ||
1682 | // skip? | |
1683 | return nullptr; | |
1684 | } | |
1685 | ||
1686 | if (!skip_token (EXCLAM)) | |
1687 | { | |
1688 | // skip after somewhere? | |
1689 | return nullptr; | |
1690 | } | |
1691 | ||
1692 | // parse internal delim token tree | |
1693 | AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree (); | |
1694 | ||
1695 | Location macro_locus = macro_path.get_locus (); | |
1696 | ||
1697 | return std::unique_ptr<AST::MacroInvocation> ( | |
1698 | new AST::MacroInvocation (AST::MacroInvocData (std::move (macro_path), | |
1699 | std::move (delim_tok_tree)), | |
1700 | std::move (outer_attrs), macro_locus)); | |
1701 | } | |
1702 | ||
1703 | // Parses a macro rule definition - does not parse semicolons. | |
1704 | template <typename ManagedTokenSource> | |
1705 | AST::MacroRule | |
1706 | Parser<ManagedTokenSource>::parse_macro_rule () | |
1707 | { | |
1708 | Location locus = lexer.peek_token ()->get_locus (); | |
1709 | ||
1710 | // parse macro matcher | |
1711 | AST::MacroMatcher matcher = parse_macro_matcher (); | |
1712 | ||
1713 | if (matcher.is_error ()) | |
1714 | return AST::MacroRule::create_error (locus); | |
1715 | ||
1716 | if (!skip_token (MATCH_ARROW)) | |
1717 | { | |
1718 | // skip after somewhere? | |
1719 | return AST::MacroRule::create_error (locus); | |
1720 | } | |
1721 | ||
1722 | // parse transcriber (this is just a delim token tree) | |
1723 | Location token_tree_loc = lexer.peek_token ()->get_locus (); | |
1724 | AST::MacroTranscriber transcriber (parse_delim_token_tree (), token_tree_loc); | |
1725 | ||
1726 | return AST::MacroRule (std::move (matcher), std::move (transcriber), locus); | |
1727 | } | |
1728 | ||
1729 | // Parses a macro matcher (part of a macro rule definition). | |
1730 | template <typename ManagedTokenSource> | |
1731 | AST::MacroMatcher | |
1732 | Parser<ManagedTokenSource>::parse_macro_matcher () | |
1733 | { | |
1734 | // save delim type to ensure it is reused later | |
1735 | AST::DelimType delim_type = AST::PARENS; | |
1736 | ||
1737 | // DEBUG | |
1738 | rust_debug ("begun parsing macro matcher"); | |
1739 | ||
1740 | // Map tokens to DelimType | |
1741 | const_TokenPtr t = lexer.peek_token (); | |
1742 | Location locus = t->get_locus (); | |
1743 | switch (t->get_id ()) | |
1744 | { | |
1745 | case LEFT_PAREN: | |
1746 | delim_type = AST::PARENS; | |
1747 | break; | |
1748 | case LEFT_SQUARE: | |
1749 | delim_type = AST::SQUARE; | |
1750 | break; | |
1751 | case LEFT_CURLY: | |
1752 | delim_type = AST::CURLY; | |
1753 | break; | |
1754 | default: | |
1755 | add_error (Error ( | |
1756 | t->get_locus (), | |
1757 | "unexpected token %qs - expecting delimiters (for a macro matcher)", | |
1758 | t->get_token_description ())); | |
1759 | ||
1760 | return AST::MacroMatcher::create_error (t->get_locus ()); | |
1761 | } | |
1762 | lexer.skip_token (); | |
1763 | ||
1764 | // parse actual macro matches | |
1765 | std::vector<std::unique_ptr<AST::MacroMatch>> matches; | |
1766 | // Set of possible preceding macro matches to make sure follow-set | |
1767 | // restrictions are respected. | |
1768 | // TODO: Consider using std::reference_wrapper instead of raw pointers? | |
1769 | std::vector<const AST::MacroMatch *> last_matches; | |
1770 | ||
1771 | t = lexer.peek_token (); | |
1772 | // parse token trees until the initial delimiter token is found again | |
1773 | while (!token_id_matches_delims (t->get_id (), delim_type)) | |
1774 | { | |
1775 | std::unique_ptr<AST::MacroMatch> match = parse_macro_match (); | |
1776 | ||
1777 | if (match == nullptr) | |
1778 | { | |
1779 | Error error ( | |
1780 | t->get_locus (), | |
1781 | "failed to parse macro match for macro matcher - found %qs", | |
1782 | t->get_token_description ()); | |
1783 | add_error (std::move (error)); | |
1784 | ||
1785 | return AST::MacroMatcher::create_error (t->get_locus ()); | |
1786 | } | |
1787 | ||
1788 | if (matches.size () > 0) | |
1789 | { | |
1790 | const auto *last_match = matches.back ().get (); | |
1791 | ||
1792 | // We want to check if we are dealing with a zeroable repetition | |
1793 | bool zeroable = false; | |
1794 | if (last_match->get_macro_match_type () | |
1795 | == AST::MacroMatch::MacroMatchType::Repetition) | |
1796 | { | |
1797 | auto repetition | |
1798 | = static_cast<const AST::MacroMatchRepetition *> (last_match); | |
1799 | ||
1800 | if (repetition->get_op () | |
1801 | != AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE) | |
1802 | zeroable = true; | |
1803 | } | |
1804 | ||
1805 | if (!zeroable) | |
1806 | last_matches.clear (); | |
1807 | ||
1808 | last_matches.emplace_back (last_match); | |
1809 | ||
1810 | for (auto last : last_matches) | |
1811 | if (!is_match_compatible (*last, *match)) | |
1812 | return AST::MacroMatcher::create_error ( | |
1813 | match->get_match_locus ()); | |
1814 | } | |
1815 | ||
1816 | matches.push_back (std::move (match)); | |
1817 | ||
1818 | // DEBUG | |
1819 | rust_debug ("pushed back a match in macro matcher"); | |
1820 | ||
1821 | t = lexer.peek_token (); | |
1822 | } | |
1823 | ||
1824 | // parse end delimiters | |
1825 | t = lexer.peek_token (); | |
1826 | if (token_id_matches_delims (t->get_id (), delim_type)) | |
1827 | { | |
1828 | // tokens match opening delimiter, so skip. | |
1829 | lexer.skip_token (); | |
1830 | ||
1831 | return AST::MacroMatcher (delim_type, std::move (matches), locus); | |
1832 | } | |
1833 | else | |
1834 | { | |
1835 | // tokens don't match opening delimiters, so produce error | |
1836 | Error error (t->get_locus (), | |
1837 | "unexpected token %qs - expecting closing delimiter %qs " | |
1838 | "(for a macro matcher)", | |
1839 | t->get_token_description (), | |
1840 | (delim_type == AST::PARENS | |
1841 | ? ")" | |
1842 | : (delim_type == AST::SQUARE ? "]" : "}"))); | |
1843 | add_error (std::move (error)); | |
1844 | ||
1845 | /* return error macro matcher despite possibly parsing mostly correct one? | |
1846 | * TODO is this the best idea? */ | |
1847 | return AST::MacroMatcher::create_error (t->get_locus ()); | |
1848 | } | |
1849 | } | |
1850 | ||
1851 | // Parses a macro match (syntax match inside a matcher in a macro rule). | |
1852 | template <typename ManagedTokenSource> | |
1853 | std::unique_ptr<AST::MacroMatch> | |
1854 | Parser<ManagedTokenSource>::parse_macro_match () | |
1855 | { | |
1856 | // branch based on token available | |
1857 | const_TokenPtr t = lexer.peek_token (); | |
1858 | switch (t->get_id ()) | |
1859 | { | |
1860 | case LEFT_PAREN: | |
1861 | case LEFT_SQUARE: | |
1862 | case LEFT_CURLY: { | |
1863 | // must be macro matcher as delimited | |
1864 | AST::MacroMatcher matcher = parse_macro_matcher (); | |
1865 | if (matcher.is_error ()) | |
1866 | { | |
1867 | Error error (lexer.peek_token ()->get_locus (), | |
1868 | "failed to parse macro matcher in macro match"); | |
1869 | add_error (std::move (error)); | |
1870 | ||
1871 | return nullptr; | |
1872 | } | |
1873 | return std::unique_ptr<AST::MacroMatcher> ( | |
1874 | new AST::MacroMatcher (std::move (matcher))); | |
1875 | } | |
1876 | case DOLLAR_SIGN: { | |
1877 | // have to do more lookahead to determine if fragment or repetition | |
1878 | const_TokenPtr t2 = lexer.peek_token (1); | |
1879 | switch (t2->get_id ()) | |
1880 | { | |
1881 | case ABSTRACT: | |
1882 | case AS: | |
1883 | case ASYNC: | |
1884 | case BECOME: | |
1885 | case BOX: | |
1886 | case BREAK: | |
1887 | case CONST: | |
1888 | case CONTINUE: | |
1889 | case CRATE: | |
1890 | case DO: | |
1891 | case DYN: | |
1892 | case ELSE: | |
1893 | case ENUM_TOK: | |
1894 | case EXTERN_TOK: | |
1895 | case FALSE_LITERAL: | |
1896 | case FINAL_TOK: | |
1897 | case FN_TOK: | |
1898 | case FOR: | |
1899 | case IF: | |
1900 | case IMPL: | |
1901 | case IN: | |
1902 | case LET: | |
1903 | case LOOP: | |
1904 | case MACRO: | |
1905 | case MATCH_TOK: | |
1906 | case MOD: | |
1907 | case MOVE: | |
1908 | case MUT: | |
1909 | case OVERRIDE_TOK: | |
1910 | case PRIV: | |
1911 | case PUB: | |
1912 | case REF: | |
1913 | case RETURN_TOK: | |
1914 | case SELF_ALIAS: | |
1915 | case SELF: | |
1916 | case STATIC_TOK: | |
1917 | case STRUCT_TOK: | |
1918 | case SUPER: | |
1919 | case TRAIT: | |
1920 | case TRUE_LITERAL: | |
1921 | case TRY: | |
1922 | case TYPE: | |
1923 | case TYPEOF: | |
1924 | case UNSAFE: | |
1925 | case UNSIZED: | |
1926 | case USE: | |
1927 | case VIRTUAL: | |
1928 | case WHERE: | |
1929 | case WHILE: | |
1930 | case YIELD: | |
1931 | case IDENTIFIER: | |
1932 | // macro fragment | |
1933 | return parse_macro_match_fragment (); | |
1934 | case LEFT_PAREN: | |
1935 | // macro repetition | |
1936 | return parse_macro_match_repetition (); | |
1937 | default: | |
1938 | // error: unrecognised | |
1939 | add_error ( | |
1940 | Error (t2->get_locus (), | |
1941 | "unrecognised token combination %<$%s%> at start of " | |
1942 | "macro match - did you mean %<$identifier%> or %<$(%>?", | |
1943 | t2->get_token_description ())); | |
1944 | ||
1945 | // skip somewhere? | |
1946 | return nullptr; | |
1947 | } | |
1948 | } | |
1949 | case RIGHT_PAREN: | |
1950 | case RIGHT_SQUARE: | |
1951 | case RIGHT_CURLY: | |
1952 | // not allowed | |
1953 | add_error (Error ( | |
1954 | t->get_locus (), | |
1955 | "closing delimiters like %qs are not allowed at the start of a macro " | |
1956 | "match", | |
1957 | t->get_token_description ())); | |
1958 | ||
1959 | // skip somewhere? | |
1960 | return nullptr; | |
1961 | default: | |
1962 | // just the token | |
1963 | lexer.skip_token (); | |
1964 | return std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
1965 | } | |
1966 | } | |
1967 | ||
1968 | // Parses a fragment macro match. | |
1969 | template <typename ManagedTokenSource> | |
1970 | std::unique_ptr<AST::MacroMatchFragment> | |
1971 | Parser<ManagedTokenSource>::parse_macro_match_fragment () | |
1972 | { | |
1973 | Location fragment_locus = lexer.peek_token ()->get_locus (); | |
1974 | skip_token (DOLLAR_SIGN); | |
1975 | ||
1976 | Identifier ident = ""; | |
1977 | auto identifier = lexer.peek_token (); | |
1978 | if (identifier->has_str ()) | |
1979 | ident = identifier->get_str (); | |
1980 | else | |
1981 | ident = std::string (token_id_to_str (identifier->get_id ())); | |
1982 | ||
1983 | if (ident.empty ()) | |
1984 | { | |
1985 | Error error (lexer.peek_token ()->get_locus (), | |
1986 | "missing identifier in macro match fragment"); | |
1987 | add_error (std::move (error)); | |
1988 | ||
1989 | return nullptr; | |
1990 | } | |
1991 | skip_token (identifier->get_id ()); | |
1992 | ||
1993 | if (!skip_token (COLON)) | |
1994 | { | |
1995 | // skip after somewhere? | |
1996 | return nullptr; | |
1997 | } | |
1998 | ||
1999 | // get MacroFragSpec for macro | |
2000 | const_TokenPtr t = expect_token (IDENTIFIER); | |
2001 | if (t == nullptr) | |
2002 | return nullptr; | |
2003 | ||
2004 | AST::MacroFragSpec frag | |
2005 | = AST::MacroFragSpec::get_frag_spec_from_str (t->get_str ()); | |
2006 | if (frag.is_error ()) | |
2007 | { | |
2008 | Error error (t->get_locus (), | |
2009 | "invalid fragment specifier %qs in fragment macro match", | |
2010 | t->get_str ().c_str ()); | |
2011 | add_error (std::move (error)); | |
2012 | ||
2013 | return nullptr; | |
2014 | } | |
2015 | ||
2016 | return std::unique_ptr<AST::MacroMatchFragment> ( | |
2017 | new AST::MacroMatchFragment (std::move (ident), frag, fragment_locus)); | |
2018 | } | |
2019 | ||
2020 | // Parses a repetition macro match. | |
2021 | template <typename ManagedTokenSource> | |
2022 | std::unique_ptr<AST::MacroMatchRepetition> | |
2023 | Parser<ManagedTokenSource>::parse_macro_match_repetition () | |
2024 | { | |
2025 | skip_token (DOLLAR_SIGN); | |
2026 | skip_token (LEFT_PAREN); | |
2027 | ||
2028 | std::vector<std::unique_ptr<AST::MacroMatch>> matches; | |
2029 | ||
2030 | // parse required first macro match | |
2031 | std::unique_ptr<AST::MacroMatch> initial_match = parse_macro_match (); | |
2032 | if (initial_match == nullptr) | |
2033 | { | |
2034 | Error error ( | |
2035 | lexer.peek_token ()->get_locus (), | |
2036 | "could not parse required first macro match in macro match repetition"); | |
2037 | add_error (std::move (error)); | |
2038 | ||
2039 | // skip after somewhere? | |
2040 | return nullptr; | |
2041 | } | |
2042 | matches.push_back (std::move (initial_match)); | |
2043 | ||
2044 | // parse optional later macro matches | |
2045 | const_TokenPtr t = lexer.peek_token (); | |
2046 | while (t->get_id () != RIGHT_PAREN) | |
2047 | { | |
2048 | std::unique_ptr<AST::MacroMatch> match = parse_macro_match (); | |
2049 | ||
2050 | if (match == nullptr) | |
2051 | { | |
2052 | Error error (lexer.peek_token ()->get_locus (), | |
2053 | "failed to parse macro match in macro match repetition"); | |
2054 | add_error (std::move (error)); | |
2055 | ||
2056 | return nullptr; | |
2057 | } | |
2058 | ||
2059 | matches.push_back (std::move (match)); | |
2060 | ||
2061 | t = lexer.peek_token (); | |
2062 | } | |
2063 | ||
2064 | if (!skip_token (RIGHT_PAREN)) | |
2065 | { | |
2066 | // skip after somewhere? | |
2067 | return nullptr; | |
2068 | } | |
2069 | ||
2070 | t = lexer.peek_token (); | |
2071 | // see if separator token exists | |
2072 | std::unique_ptr<AST::Token> separator = nullptr; | |
2073 | switch (t->get_id ()) | |
2074 | { | |
2075 | // repetition operators | |
2076 | case ASTERISK: | |
2077 | case PLUS: | |
2078 | case QUESTION_MARK: | |
2079 | // delimiters | |
2080 | case LEFT_PAREN: | |
2081 | case LEFT_CURLY: | |
2082 | case LEFT_SQUARE: | |
2083 | case RIGHT_PAREN: | |
2084 | case RIGHT_CURLY: | |
2085 | case RIGHT_SQUARE: | |
2086 | // separator does not exist, so still null and don't skip token | |
2087 | break; | |
2088 | default: | |
2089 | // separator does exist | |
2090 | separator = std::unique_ptr<AST::Token> (new AST::Token (std::move (t))); | |
2091 | lexer.skip_token (); | |
2092 | break; | |
2093 | } | |
2094 | ||
2095 | // parse repetition operator | |
2096 | t = lexer.peek_token (); | |
2097 | AST::MacroMatchRepetition::MacroRepOp op = AST::MacroMatchRepetition::NONE; | |
2098 | switch (t->get_id ()) | |
2099 | { | |
2100 | case ASTERISK: | |
2101 | op = AST::MacroMatchRepetition::ANY; | |
2102 | lexer.skip_token (); | |
2103 | break; | |
2104 | case PLUS: | |
2105 | op = AST::MacroMatchRepetition::ONE_OR_MORE; | |
2106 | lexer.skip_token (); | |
2107 | break; | |
2108 | case QUESTION_MARK: | |
2109 | op = AST::MacroMatchRepetition::ZERO_OR_ONE; | |
2110 | lexer.skip_token (); | |
2111 | break; | |
2112 | default: | |
2113 | add_error ( | |
2114 | Error (t->get_locus (), | |
2115 | "expected macro repetition operator (%<*%>, %<+%>, or %<?%>) in " | |
2116 | "macro match - found %qs", | |
2117 | t->get_token_description ())); | |
2118 | ||
2119 | // skip after somewhere? | |
2120 | return nullptr; | |
2121 | } | |
2122 | ||
2123 | return std::unique_ptr<AST::MacroMatchRepetition> ( | |
2124 | new AST::MacroMatchRepetition (std::move (matches), op, | |
2125 | std::move (separator), t->get_locus ())); | |
2126 | } | |
2127 | ||
2128 | /* Parses a visibility syntactical production (i.e. creating a non-default | |
2129 | * visibility) */ | |
2130 | template <typename ManagedTokenSource> | |
2131 | AST::Visibility | |
2132 | Parser<ManagedTokenSource>::parse_visibility () | |
2133 | { | |
2134 | // check for no visibility | |
2135 | if (lexer.peek_token ()->get_id () != PUB) | |
2136 | { | |
2137 | return AST::Visibility::create_private (); | |
2138 | } | |
2139 | ||
2140 | lexer.skip_token (); | |
2141 | ||
2142 | // create simple pub visibility if no parentheses | |
2143 | if (lexer.peek_token ()->get_id () != LEFT_PAREN) | |
2144 | { | |
2145 | return AST::Visibility::create_public (); | |
2146 | // or whatever | |
2147 | } | |
2148 | ||
2149 | lexer.skip_token (); | |
2150 | ||
2151 | const_TokenPtr t = lexer.peek_token (); | |
2152 | auto path_loc = t->get_locus (); | |
2153 | ||
2154 | switch (t->get_id ()) | |
2155 | { | |
2156 | case CRATE: | |
2157 | lexer.skip_token (); | |
2158 | ||
2159 | skip_token (RIGHT_PAREN); | |
2160 | ||
2161 | return AST::Visibility::create_crate (path_loc); | |
2162 | case SELF: | |
2163 | lexer.skip_token (); | |
2164 | ||
2165 | skip_token (RIGHT_PAREN); | |
2166 | ||
2167 | return AST::Visibility::create_self (path_loc); | |
2168 | case SUPER: | |
2169 | lexer.skip_token (); | |
2170 | ||
2171 | skip_token (RIGHT_PAREN); | |
2172 | ||
2173 | return AST::Visibility::create_super (path_loc); | |
2174 | case IN: { | |
2175 | lexer.skip_token (); | |
2176 | ||
2177 | // parse the "in" path as well | |
2178 | AST::SimplePath path = parse_simple_path (); | |
2179 | if (path.is_empty ()) | |
2180 | { | |
2181 | Error error (lexer.peek_token ()->get_locus (), | |
2182 | "missing path in pub(in path) visibility"); | |
2183 | add_error (std::move (error)); | |
2184 | ||
2185 | // skip after somewhere? | |
2186 | return AST::Visibility::create_error (); | |
2187 | } | |
2188 | ||
2189 | skip_token (RIGHT_PAREN); | |
2190 | ||
2191 | return AST::Visibility::create_in_path (std::move (path)); | |
2192 | } | |
2193 | default: | |
2194 | add_error (Error (t->get_locus (), "unexpected token %qs in visibility", | |
2195 | t->get_token_description ())); | |
2196 | ||
2197 | lexer.skip_token (); | |
2198 | return AST::Visibility::create_error (); | |
2199 | } | |
2200 | } | |
2201 | ||
2202 | // Parses a module - either a bodied module or a module defined in another file. | |
2203 | template <typename ManagedTokenSource> | |
2204 | std::unique_ptr<AST::Module> | |
2205 | Parser<ManagedTokenSource>::parse_module (AST::Visibility vis, | |
2206 | AST::AttrVec outer_attrs) | |
2207 | { | |
2208 | Location locus = lexer.peek_token ()->get_locus (); | |
2209 | skip_token (MOD); | |
2210 | ||
2211 | const_TokenPtr module_name = expect_token (IDENTIFIER); | |
2212 | if (module_name == nullptr) | |
2213 | { | |
2214 | return nullptr; | |
2215 | } | |
2216 | Identifier name = module_name->get_str (); | |
2217 | ||
2218 | const_TokenPtr t = lexer.peek_token (); | |
2219 | ||
2220 | switch (t->get_id ()) | |
2221 | { | |
2222 | case SEMICOLON: | |
2223 | lexer.skip_token (); | |
2224 | ||
2225 | // Construct an external module | |
2226 | return std::unique_ptr<AST::Module> ( | |
2227 | new AST::Module (std::move (name), std::move (vis), | |
2228 | std::move (outer_attrs), locus, lexer.get_filename (), | |
2229 | inline_module_stack)); | |
2230 | case LEFT_CURLY: { | |
2231 | lexer.skip_token (); | |
2232 | ||
2233 | // parse inner attributes | |
2234 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
2235 | ||
2236 | std::string module_path_name | |
2237 | = extract_module_path (inner_attrs, outer_attrs, name); | |
2238 | InlineModuleStackScope scope (*this, std::move (module_path_name)); | |
2239 | ||
2240 | // parse items | |
2241 | std::vector<std::unique_ptr<AST::Item>> items; | |
2242 | const_TokenPtr tok = lexer.peek_token (); | |
2243 | while (tok->get_id () != RIGHT_CURLY) | |
2244 | { | |
2245 | std::unique_ptr<AST::Item> item = parse_item (false); | |
2246 | if (item == nullptr) | |
2247 | { | |
2248 | Error error (tok->get_locus (), | |
2249 | "failed to parse item in module"); | |
2250 | add_error (std::move (error)); | |
2251 | ||
2252 | return nullptr; | |
2253 | } | |
2254 | ||
2255 | items.push_back (std::move (item)); | |
2256 | ||
2257 | tok = lexer.peek_token (); | |
2258 | } | |
2259 | ||
2260 | if (!skip_token (RIGHT_CURLY)) | |
2261 | { | |
2262 | // skip somewhere? | |
2263 | return nullptr; | |
2264 | } | |
2265 | ||
2266 | return std::unique_ptr<AST::Module> ( | |
2267 | new AST::Module (std::move (name), locus, std::move (items), | |
2268 | std::move (vis), std::move (inner_attrs), | |
2269 | std::move (outer_attrs))); // module name? | |
2270 | } | |
2271 | default: | |
2272 | add_error ( | |
2273 | Error (t->get_locus (), | |
2274 | "unexpected token %qs in module declaration/definition item", | |
2275 | t->get_token_description ())); | |
2276 | ||
2277 | lexer.skip_token (); | |
2278 | return nullptr; | |
2279 | } | |
2280 | } | |
2281 | ||
2282 | // Parses an extern crate declaration (dependency on external crate) | |
2283 | template <typename ManagedTokenSource> | |
2284 | std::unique_ptr<AST::ExternCrate> | |
2285 | Parser<ManagedTokenSource>::parse_extern_crate (AST::Visibility vis, | |
2286 | AST::AttrVec outer_attrs) | |
2287 | { | |
2288 | Location locus = lexer.peek_token ()->get_locus (); | |
2289 | if (!skip_token (EXTERN_TOK)) | |
2290 | { | |
2291 | skip_after_semicolon (); | |
2292 | return nullptr; | |
2293 | } | |
2294 | ||
2295 | if (!skip_token (CRATE)) | |
2296 | { | |
2297 | skip_after_semicolon (); | |
2298 | return nullptr; | |
2299 | } | |
2300 | ||
2301 | /* parse crate reference name - this has its own syntactical rule in reference | |
2302 | * but seems to not be used elsewhere, so i'm putting it here */ | |
2303 | const_TokenPtr crate_name_tok = lexer.peek_token (); | |
2304 | std::string crate_name; | |
2305 | ||
2306 | switch (crate_name_tok->get_id ()) | |
2307 | { | |
2308 | case IDENTIFIER: | |
2309 | crate_name = crate_name_tok->get_str (); | |
2310 | lexer.skip_token (); | |
2311 | break; | |
2312 | case SELF: | |
2313 | crate_name = "self"; | |
2314 | lexer.skip_token (); | |
2315 | break; | |
2316 | default: | |
2317 | add_error ( | |
2318 | Error (crate_name_tok->get_locus (), | |
2319 | "expecting crate name (identifier or %<self%>), found %qs", | |
2320 | crate_name_tok->get_token_description ())); | |
2321 | ||
2322 | skip_after_semicolon (); | |
2323 | return nullptr; | |
2324 | } | |
2325 | ||
2326 | // don't parse as clause if it doesn't exist | |
2327 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
2328 | { | |
2329 | lexer.skip_token (); | |
2330 | ||
2331 | return std::unique_ptr<AST::ExternCrate> ( | |
2332 | new AST::ExternCrate (std::move (crate_name), std::move (vis), | |
2333 | std::move (outer_attrs), locus)); | |
2334 | } | |
2335 | ||
2336 | /* parse as clause - this also has its own syntactical rule in reference and | |
2337 | * also seems to not be used elsewhere, so including here again. */ | |
2338 | if (!skip_token (AS)) | |
2339 | { | |
2340 | skip_after_semicolon (); | |
2341 | return nullptr; | |
2342 | } | |
2343 | ||
2344 | const_TokenPtr as_name_tok = lexer.peek_token (); | |
2345 | std::string as_name; | |
2346 | ||
2347 | switch (as_name_tok->get_id ()) | |
2348 | { | |
2349 | case IDENTIFIER: | |
2350 | as_name = as_name_tok->get_str (); | |
2351 | lexer.skip_token (); | |
2352 | break; | |
2353 | case UNDERSCORE: | |
2354 | as_name = "_"; | |
2355 | lexer.skip_token (); | |
2356 | break; | |
2357 | default: | |
2358 | add_error ( | |
2359 | Error (as_name_tok->get_locus (), | |
2360 | "expecting as clause name (identifier or %<_%>), found %qs", | |
2361 | as_name_tok->get_token_description ())); | |
2362 | ||
2363 | skip_after_semicolon (); | |
2364 | return nullptr; | |
2365 | } | |
2366 | ||
2367 | if (!skip_token (SEMICOLON)) | |
2368 | { | |
2369 | skip_after_semicolon (); | |
2370 | return nullptr; | |
2371 | } | |
2372 | ||
2373 | return std::unique_ptr<AST::ExternCrate> ( | |
2374 | new AST::ExternCrate (std::move (crate_name), std::move (vis), | |
2375 | std::move (outer_attrs), locus, std::move (as_name))); | |
2376 | } | |
2377 | ||
2378 | // Parses a use declaration. | |
2379 | template <typename ManagedTokenSource> | |
2380 | std::unique_ptr<AST::UseDeclaration> | |
2381 | Parser<ManagedTokenSource>::parse_use_decl (AST::Visibility vis, | |
2382 | AST::AttrVec outer_attrs) | |
2383 | { | |
2384 | Location locus = lexer.peek_token ()->get_locus (); | |
2385 | if (!skip_token (USE)) | |
2386 | { | |
2387 | skip_after_semicolon (); | |
2388 | return nullptr; | |
2389 | } | |
2390 | ||
2391 | // parse use tree, which is required | |
2392 | std::unique_ptr<AST::UseTree> use_tree = parse_use_tree (); | |
2393 | if (use_tree == nullptr) | |
2394 | { | |
2395 | Error error (lexer.peek_token ()->get_locus (), | |
2396 | "could not parse use tree in use declaration"); | |
2397 | add_error (std::move (error)); | |
2398 | ||
2399 | skip_after_semicolon (); | |
2400 | return nullptr; | |
2401 | } | |
2402 | ||
2403 | if (!skip_token (SEMICOLON)) | |
2404 | { | |
2405 | skip_after_semicolon (); | |
2406 | return nullptr; | |
2407 | } | |
2408 | ||
2409 | return std::unique_ptr<AST::UseDeclaration> ( | |
2410 | new AST::UseDeclaration (std::move (use_tree), std::move (vis), | |
2411 | std::move (outer_attrs), locus)); | |
2412 | } | |
2413 | ||
2414 | // Parses a use tree (which can be recursive and is actually a base class). | |
2415 | template <typename ManagedTokenSource> | |
2416 | std::unique_ptr<AST::UseTree> | |
2417 | Parser<ManagedTokenSource>::parse_use_tree () | |
2418 | { | |
2419 | /* potential syntax definitions in attempt to get algorithm: | |
2420 | * Glob: | |
2421 | * <- SimplePath :: * | |
2422 | * <- :: * | |
2423 | * <- * | |
2424 | * Nested tree thing: | |
2425 | * <- SimplePath :: { COMPLICATED_INNER_TREE_THING } | |
2426 | * <- :: COMPLICATED_INNER_TREE_THING } | |
2427 | * <- { COMPLICATED_INNER_TREE_THING } | |
2428 | * Rebind thing: | |
2429 | * <- SimplePath as IDENTIFIER | |
2430 | * <- SimplePath as _ | |
2431 | * <- SimplePath | |
2432 | */ | |
2433 | ||
2434 | /* current plan of attack: try to parse SimplePath first - if fails, one of | |
2435 | * top two then try parse :: - if fails, one of top two. Next is deciding | |
2436 | * character for top two. */ | |
2437 | ||
2438 | /* Thus, parsing smaller parts of use tree may require feeding into function | |
2439 | * via parameters (or could handle all in this single function because other | |
2440 | * use tree types aren't recognised as separate in the spec) */ | |
2441 | ||
2442 | // TODO: I think this function is too complex, probably should split it | |
2443 | ||
2444 | Location locus = lexer.peek_token ()->get_locus (); | |
2445 | ||
2446 | // bool has_path = false; | |
2447 | AST::SimplePath path = parse_simple_path (); | |
2448 | ||
2449 | if (path.is_empty ()) | |
2450 | { | |
2451 | // has no path, so must be glob or nested tree UseTree type | |
2452 | ||
2453 | bool is_global = false; | |
2454 | ||
2455 | // check for global scope resolution operator | |
2456 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION) | |
2457 | { | |
2458 | lexer.skip_token (); | |
2459 | is_global = true; | |
2460 | } | |
2461 | ||
2462 | const_TokenPtr t = lexer.peek_token (); | |
2463 | switch (t->get_id ()) | |
2464 | { | |
2465 | case ASTERISK: | |
2466 | // glob UseTree type | |
2467 | lexer.skip_token (); | |
2468 | ||
2469 | if (is_global) | |
2470 | return std::unique_ptr<AST::UseTreeGlob> ( | |
2471 | new AST::UseTreeGlob (AST::UseTreeGlob::GLOBAL, | |
2472 | AST::SimplePath::create_empty (), locus)); | |
2473 | else | |
2474 | return std::unique_ptr<AST::UseTreeGlob> ( | |
2475 | new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH, | |
2476 | AST::SimplePath::create_empty (), locus)); | |
2477 | case LEFT_CURLY: { | |
2478 | // nested tree UseTree type | |
2479 | lexer.skip_token (); | |
2480 | ||
2481 | std::vector<std::unique_ptr<AST::UseTree>> use_trees; | |
2482 | ||
2483 | const_TokenPtr t = lexer.peek_token (); | |
2484 | while (t->get_id () != RIGHT_CURLY) | |
2485 | { | |
2486 | std::unique_ptr<AST::UseTree> use_tree = parse_use_tree (); | |
2487 | if (use_tree == nullptr) | |
2488 | { | |
2489 | break; | |
2490 | } | |
2491 | ||
2492 | use_trees.push_back (std::move (use_tree)); | |
2493 | ||
2494 | if (lexer.peek_token ()->get_id () != COMMA) | |
2495 | break; | |
2496 | ||
2497 | lexer.skip_token (); | |
2498 | t = lexer.peek_token (); | |
2499 | } | |
2500 | ||
2501 | // skip end curly delimiter | |
2502 | if (!skip_token (RIGHT_CURLY)) | |
2503 | { | |
2504 | // skip after somewhere? | |
2505 | return nullptr; | |
2506 | } | |
2507 | ||
2508 | if (is_global) | |
2509 | return std::unique_ptr<AST::UseTreeList> ( | |
2510 | new AST::UseTreeList (AST::UseTreeList::GLOBAL, | |
2511 | AST::SimplePath::create_empty (), | |
2512 | std::move (use_trees), locus)); | |
2513 | else | |
2514 | return std::unique_ptr<AST::UseTreeList> ( | |
2515 | new AST::UseTreeList (AST::UseTreeList::NO_PATH, | |
2516 | AST::SimplePath::create_empty (), | |
2517 | std::move (use_trees), locus)); | |
2518 | } | |
2519 | case AS: | |
2520 | // this is not allowed | |
2521 | add_error (Error ( | |
2522 | t->get_locus (), | |
2523 | "use declaration with rebind %<as%> requires a valid simple path - " | |
2524 | "none found")); | |
2525 | ||
2526 | skip_after_semicolon (); | |
2527 | return nullptr; | |
2528 | default: | |
2529 | add_error (Error (t->get_locus (), | |
2530 | "unexpected token %qs in use tree with " | |
2531 | "no valid simple path (i.e. list" | |
2532 | " or glob use tree)", | |
2533 | t->get_token_description ())); | |
2534 | ||
2535 | skip_after_semicolon (); | |
2536 | return nullptr; | |
2537 | } | |
2538 | } | |
2539 | else | |
2540 | { | |
2541 | /* Due to aforementioned implementation issues, the trailing :: token is | |
2542 | * consumed by the path, so it can not be used as a disambiguator. | |
2543 | * NOPE, not true anymore - TODO what are the consequences of this? */ | |
2544 | ||
2545 | const_TokenPtr t = lexer.peek_token (); | |
2546 | switch (t->get_id ()) | |
2547 | { | |
2548 | case ASTERISK: | |
2549 | // glob UseTree type | |
2550 | lexer.skip_token (); | |
2551 | ||
2552 | return std::unique_ptr<AST::UseTreeGlob> ( | |
2553 | new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED, | |
2554 | std::move (path), locus)); | |
2555 | case LEFT_CURLY: { | |
2556 | // nested tree UseTree type | |
2557 | lexer.skip_token (); | |
2558 | ||
2559 | std::vector<std::unique_ptr<AST::UseTree>> use_trees; | |
2560 | ||
2561 | // TODO: think of better control structure | |
2562 | const_TokenPtr t = lexer.peek_token (); | |
2563 | while (t->get_id () != RIGHT_CURLY) | |
2564 | { | |
2565 | std::unique_ptr<AST::UseTree> use_tree = parse_use_tree (); | |
2566 | if (use_tree == nullptr) | |
2567 | { | |
2568 | break; | |
2569 | } | |
2570 | ||
2571 | use_trees.push_back (std::move (use_tree)); | |
2572 | ||
2573 | if (lexer.peek_token ()->get_id () != COMMA) | |
2574 | break; | |
2575 | ||
2576 | lexer.skip_token (); | |
2577 | t = lexer.peek_token (); | |
2578 | } | |
2579 | ||
2580 | // skip end curly delimiter | |
2581 | if (!skip_token (RIGHT_CURLY)) | |
2582 | { | |
2583 | // skip after somewhere? | |
2584 | return nullptr; | |
2585 | } | |
2586 | ||
2587 | return std::unique_ptr<AST::UseTreeList> ( | |
2588 | new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED, | |
2589 | std::move (path), std::move (use_trees), | |
2590 | locus)); | |
2591 | } | |
2592 | case AS: { | |
2593 | // rebind UseTree type | |
2594 | lexer.skip_token (); | |
2595 | ||
2596 | const_TokenPtr t = lexer.peek_token (); | |
2597 | switch (t->get_id ()) | |
2598 | { | |
2599 | case IDENTIFIER: | |
2600 | // skip lexer token | |
2601 | lexer.skip_token (); | |
2602 | ||
2603 | return std::unique_ptr<AST::UseTreeRebind> ( | |
2604 | new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER, | |
2605 | std::move (path), locus, | |
2606 | t->get_str ())); | |
2607 | case UNDERSCORE: | |
2608 | // skip lexer token | |
2609 | lexer.skip_token (); | |
2610 | ||
2611 | return std::unique_ptr<AST::UseTreeRebind> ( | |
2612 | new AST::UseTreeRebind (AST::UseTreeRebind::WILDCARD, | |
2613 | std::move (path), locus, "_")); | |
2614 | default: | |
2615 | add_error (Error ( | |
2616 | t->get_locus (), | |
2617 | "unexpected token %qs in use tree with as clause - expected " | |
2618 | "identifier or %<_%>", | |
2619 | t->get_token_description ())); | |
2620 | ||
2621 | skip_after_semicolon (); | |
2622 | return nullptr; | |
2623 | } | |
2624 | } | |
2625 | case SEMICOLON: | |
2626 | // rebind UseTree type without rebinding - path only | |
2627 | ||
2628 | // don't skip semicolon - handled in parse_use_tree | |
2629 | // lexer.skip_token(); | |
2630 | ||
2631 | return std::unique_ptr<AST::UseTreeRebind> ( | |
2632 | new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path), | |
2633 | locus)); | |
2634 | case COMMA: | |
2635 | case RIGHT_CURLY: | |
2636 | // this may occur in recursive calls - assume it is ok and ignore it | |
2637 | return std::unique_ptr<AST::UseTreeRebind> ( | |
2638 | new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path), | |
2639 | locus)); | |
2640 | default: | |
2641 | add_error (Error (t->get_locus (), | |
2642 | "unexpected token %qs in use tree with valid path", | |
2643 | t->get_token_description ())); | |
2644 | ||
2645 | // skip_after_semicolon(); | |
2646 | return nullptr; | |
2647 | } | |
2648 | } | |
2649 | } | |
2650 | ||
2651 | // Parses a function (not a method). | |
2652 | template <typename ManagedTokenSource> | |
2653 | std::unique_ptr<AST::Function> | |
2654 | Parser<ManagedTokenSource>::parse_function (AST::Visibility vis, | |
2655 | AST::AttrVec outer_attrs) | |
2656 | { | |
2657 | Location locus = lexer.peek_token ()->get_locus (); | |
2658 | // Get qualifiers for function if they exist | |
2659 | AST::FunctionQualifiers qualifiers = parse_function_qualifiers (); | |
2660 | ||
2661 | skip_token (FN_TOK); | |
2662 | ||
2663 | // Save function name token | |
2664 | const_TokenPtr function_name_tok = expect_token (IDENTIFIER); | |
2665 | if (function_name_tok == nullptr) | |
2666 | { | |
2667 | skip_after_next_block (); | |
2668 | return nullptr; | |
2669 | } | |
2670 | Identifier function_name = function_name_tok->get_str (); | |
2671 | ||
2672 | // parse generic params - if exist | |
2673 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
2674 | = parse_generic_params_in_angles (); | |
2675 | ||
2676 | if (!skip_token (LEFT_PAREN)) | |
2677 | { | |
2678 | Error error (lexer.peek_token ()->get_locus (), | |
2679 | "function declaration missing opening parentheses before " | |
2680 | "parameter list"); | |
2681 | add_error (std::move (error)); | |
2682 | ||
2683 | skip_after_next_block (); | |
2684 | return nullptr; | |
2685 | } | |
2686 | ||
2687 | // parse function parameters (only if next token isn't right paren) | |
2688 | std::vector<AST::FunctionParam> function_params; | |
2689 | if (lexer.peek_token ()->get_id () != RIGHT_PAREN) | |
2690 | function_params | |
2691 | = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; }); | |
2692 | ||
2693 | if (!skip_token (RIGHT_PAREN)) | |
2694 | { | |
2695 | Error error (lexer.peek_token ()->get_locus (), | |
2696 | "function declaration missing closing parentheses after " | |
2697 | "parameter list"); | |
2698 | add_error (std::move (error)); | |
2699 | ||
2700 | skip_after_next_block (); | |
2701 | return nullptr; | |
2702 | } | |
2703 | ||
2704 | // parse function return type - if exists | |
2705 | std::unique_ptr<AST::Type> return_type = parse_function_return_type (); | |
2706 | ||
2707 | // parse where clause - if exists | |
2708 | AST::WhereClause where_clause = parse_where_clause (); | |
2709 | ||
2710 | // parse block expression | |
2711 | std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr (); | |
2712 | ||
2713 | return std::unique_ptr<AST::Function> ( | |
2714 | new AST::Function (std::move (function_name), std::move (qualifiers), | |
2715 | std::move (generic_params), std::move (function_params), | |
2716 | std::move (return_type), std::move (where_clause), | |
2717 | std::move (block_expr), std::move (vis), | |
2718 | std::move (outer_attrs), locus)); | |
2719 | } | |
2720 | ||
2721 | // Parses function or method qualifiers (i.e. const, unsafe, and extern). | |
2722 | template <typename ManagedTokenSource> | |
2723 | AST::FunctionQualifiers | |
2724 | Parser<ManagedTokenSource>::parse_function_qualifiers () | |
2725 | { | |
2726 | AsyncConstStatus const_status = NONE; | |
2727 | bool has_unsafe = false; | |
2728 | bool has_extern = false; | |
2729 | std::string abi; | |
2730 | ||
2731 | // Check in order of const, unsafe, then extern | |
2732 | const_TokenPtr t = lexer.peek_token (); | |
2733 | Location locus = t->get_locus (); | |
2734 | switch (t->get_id ()) | |
2735 | { | |
2736 | case CONST: | |
2737 | lexer.skip_token (); | |
2738 | const_status = CONST_FN; | |
2739 | break; | |
2740 | case ASYNC: | |
2741 | lexer.skip_token (); | |
2742 | const_status = ASYNC_FN; | |
2743 | break; | |
2744 | default: | |
2745 | // const status is still none | |
2746 | break; | |
2747 | } | |
2748 | ||
2749 | if (lexer.peek_token ()->get_id () == UNSAFE) | |
2750 | { | |
2751 | lexer.skip_token (); | |
2752 | has_unsafe = true; | |
2753 | } | |
2754 | ||
2755 | if (lexer.peek_token ()->get_id () == EXTERN_TOK) | |
2756 | { | |
2757 | lexer.skip_token (); | |
2758 | has_extern = true; | |
2759 | ||
2760 | // detect optional abi name | |
2761 | const_TokenPtr next_tok = lexer.peek_token (); | |
2762 | if (next_tok->get_id () == STRING_LITERAL) | |
2763 | { | |
2764 | lexer.skip_token (); | |
2765 | abi = next_tok->get_str (); | |
2766 | } | |
2767 | } | |
2768 | ||
2769 | return AST::FunctionQualifiers (locus, const_status, has_unsafe, has_extern, | |
2770 | std::move (abi)); | |
2771 | } | |
2772 | ||
2773 | // Parses generic (lifetime or type) params inside angle brackets (optional). | |
2774 | template <typename ManagedTokenSource> | |
2775 | std::vector<std::unique_ptr<AST::GenericParam>> | |
2776 | Parser<ManagedTokenSource>::parse_generic_params_in_angles () | |
2777 | { | |
2778 | if (lexer.peek_token ()->get_id () != LEFT_ANGLE) | |
2779 | { | |
2780 | // seems to be no generic params, so exit with empty vector | |
2781 | return std::vector<std::unique_ptr<AST::GenericParam>> (); | |
2782 | } | |
2783 | lexer.skip_token (); | |
2784 | ||
2785 | // DEBUG: | |
2786 | rust_debug ("skipped left angle in generic param"); | |
2787 | ||
2788 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
2789 | = parse_generic_params (is_right_angle_tok); | |
2790 | ||
2791 | // DEBUG: | |
2792 | rust_debug ("finished parsing actual generic params (i.e. inside angles)"); | |
2793 | ||
2794 | if (!skip_generics_right_angle ()) | |
2795 | { | |
2796 | // DEBUG | |
2797 | rust_debug ("failed to skip generics right angle - returning empty " | |
2798 | "generic params"); | |
2799 | ||
2800 | return std::vector<std::unique_ptr<AST::GenericParam>> (); | |
2801 | } | |
2802 | ||
2803 | return generic_params; | |
2804 | } | |
2805 | ||
2806 | template <typename ManagedTokenSource> | |
2807 | template <typename EndTokenPred> | |
2808 | std::unique_ptr<AST::GenericParam> | |
2809 | Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) | |
2810 | { | |
2811 | auto token = lexer.peek_token (); | |
2812 | auto outer_attrs = parse_outer_attribute (); | |
2813 | std::unique_ptr<AST::GenericParam> param; | |
2814 | ||
2815 | switch (token->get_id ()) | |
2816 | { | |
2817 | case LIFETIME: { | |
2818 | auto lifetime = parse_lifetime (); | |
2819 | if (lifetime.is_error ()) | |
2820 | { | |
2821 | rust_error_at ( | |
2822 | token->get_locus (), | |
2823 | "failed to parse lifetime in generic parameter list"); | |
2824 | return nullptr; | |
2825 | } | |
2826 | ||
2827 | std::vector<AST::Lifetime> lifetime_bounds; | |
2828 | if (lexer.peek_token ()->get_id () == COLON) | |
2829 | { | |
2830 | lexer.skip_token (); | |
2831 | // parse required bounds | |
2832 | lifetime_bounds | |
2833 | = parse_lifetime_bounds ([is_end_token] (TokenId id) { | |
2834 | return is_end_token (id) || id == COMMA; | |
2835 | }); | |
2836 | } | |
2837 | ||
2838 | param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam ( | |
2839 | std::move (lifetime), std::move (lifetime_bounds), | |
2840 | std::move (outer_attrs), token->get_locus ())); | |
2841 | break; | |
2842 | } | |
2843 | case IDENTIFIER: { | |
2844 | auto type_ident = token->get_str (); | |
2845 | lexer.skip_token (); | |
2846 | ||
2847 | std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds; | |
2848 | if (lexer.peek_token ()->get_id () == COLON) | |
2849 | { | |
2850 | lexer.skip_token (); | |
2851 | ||
2852 | // parse optional type param bounds | |
2853 | type_param_bounds = parse_type_param_bounds (); | |
2854 | } | |
2855 | ||
2856 | std::unique_ptr<AST::Type> type = nullptr; | |
2857 | if (lexer.peek_token ()->get_id () == EQUAL) | |
2858 | { | |
2859 | lexer.skip_token (); | |
2860 | ||
2861 | // parse required type | |
2862 | type = parse_type (); | |
2863 | if (!type) | |
2864 | { | |
2865 | rust_error_at ( | |
2866 | lexer.peek_token ()->get_locus (), | |
2867 | "failed to parse type in type param in generic params"); | |
2868 | return nullptr; | |
2869 | } | |
2870 | } | |
2871 | ||
2872 | param = std::unique_ptr<AST::TypeParam> ( | |
2873 | new AST::TypeParam (std::move (type_ident), token->get_locus (), | |
2874 | std::move (type_param_bounds), std::move (type), | |
2875 | std::move (outer_attrs))); | |
2876 | break; | |
2877 | } | |
2878 | case CONST: { | |
2879 | lexer.skip_token (); | |
2880 | ||
2881 | auto name_token = expect_token (IDENTIFIER); | |
2882 | ||
2883 | if (!name_token || !expect_token (COLON)) | |
2884 | return nullptr; | |
2885 | ||
2886 | auto type = parse_type (); | |
2887 | if (!type) | |
2888 | return nullptr; | |
2889 | ||
2890 | // optional default value | |
2891 | auto default_expr = AST::GenericArg::create_error (); | |
2892 | if (lexer.peek_token ()->get_id () == EQUAL) | |
2893 | { | |
2894 | lexer.skip_token (); | |
2895 | auto tok = lexer.peek_token (); | |
2896 | default_expr = parse_generic_arg (); | |
2897 | ||
2898 | if (default_expr.is_error ()) | |
2899 | rust_error_at (tok->get_locus (), | |
2900 | "invalid token for start of default value for " | |
2901 | "const generic parameter: expected %<block%>, " | |
2902 | "%<identifier%> or %<literal%>, got %qs", | |
2903 | token_id_to_str (tok->get_id ())); | |
2904 | ||
2905 | // At this point, we *know* that we are parsing a const | |
2906 | // expression | |
2907 | if (default_expr.get_kind () == AST::GenericArg::Kind::Either) | |
2908 | default_expr = default_expr.disambiguate_to_const (); | |
2909 | } | |
2910 | ||
2911 | param = std::unique_ptr<AST::ConstGenericParam> ( | |
2912 | new AST::ConstGenericParam (name_token->get_str (), std::move (type), | |
2913 | default_expr, std::move (outer_attrs), | |
2914 | token->get_locus ())); | |
2915 | ||
2916 | break; | |
2917 | } | |
2918 | default: | |
2919 | // FIXME: Can we clean this last call with a method call? | |
2920 | rust_error_at (token->get_locus (), | |
2921 | "unexpected token when parsing generic parameters: %qs", | |
2922 | token->get_str ().c_str ()); | |
2923 | return nullptr; | |
2924 | } | |
2925 | ||
2926 | return param; | |
2927 | } | |
2928 | ||
2929 | /* Parse generic (lifetime or type) params NOT INSIDE ANGLE BRACKETS!!! Almost | |
2930 | * always parse_generic_params_in_angles is what is wanted. */ | |
2931 | template <typename ManagedTokenSource> | |
2932 | template <typename EndTokenPred> | |
2933 | std::vector<std::unique_ptr<AST::GenericParam>> | |
2934 | Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token) | |
2935 | { | |
2936 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params; | |
2937 | ||
2938 | /* can't parse lifetime and type params separately due to lookahead issues | |
2939 | * thus, parse them all here */ | |
2940 | ||
2941 | /* HACK: used to retain attribute data if a lifetime param is tentatively | |
2942 | * parsed but it turns out to be type param */ | |
2943 | AST::Attribute parsed_outer_attr = AST::Attribute::create_empty (); | |
2944 | ||
2945 | // Did we parse a generic type param yet | |
2946 | auto type_seen = false; | |
2947 | // Did the user write a lifetime parameter after a type one | |
2948 | auto order_error = false; | |
2949 | ||
2950 | // parse lifetime params | |
2951 | while (!is_end_token (lexer.peek_token ()->get_id ())) | |
2952 | { | |
2953 | auto param = parse_generic_param (is_end_token); | |
2954 | if (param) | |
2955 | { | |
2956 | // TODO: Handle `Const` here as well if necessary | |
2957 | if (param->get_kind () == AST::GenericParam::Kind::Type) | |
2958 | type_seen = true; | |
2959 | else if (param->get_kind () == AST::GenericParam::Kind::Lifetime | |
2960 | && type_seen) | |
2961 | order_error = true; | |
2962 | ||
2963 | generic_params.emplace_back (std::move (param)); | |
2964 | maybe_skip_token (COMMA); | |
2965 | } | |
2966 | } | |
2967 | ||
2968 | // FIXME: Add reordering hint | |
2969 | if (order_error) | |
2970 | rust_error_at (generic_params.front ()->get_locus (), | |
2971 | "invalid order for generic parameters: lifetimes should " | |
2972 | "always come before types"); | |
2973 | ||
2974 | generic_params.shrink_to_fit (); | |
2975 | return generic_params; | |
2976 | } | |
2977 | ||
2978 | /* Parses lifetime generic parameters (pointers). Will also consume any | |
2979 | * trailing comma. No extra checks for end token. */ | |
2980 | template <typename ManagedTokenSource> | |
2981 | std::vector<std::unique_ptr<AST::LifetimeParam>> | |
2982 | Parser<ManagedTokenSource>::parse_lifetime_params () | |
2983 | { | |
2984 | std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params; | |
2985 | ||
2986 | while (lexer.peek_token ()->get_id () != END_OF_FILE) | |
2987 | { | |
2988 | AST::LifetimeParam lifetime_param = parse_lifetime_param (); | |
2989 | ||
2990 | if (lifetime_param.is_error ()) | |
2991 | { | |
2992 | // can't treat as error as only way to get out with trailing comma | |
2993 | break; | |
2994 | } | |
2995 | ||
2996 | lifetime_params.push_back (std::unique_ptr<AST::LifetimeParam> ( | |
2997 | new AST::LifetimeParam (std::move (lifetime_param)))); | |
2998 | ||
2999 | if (lexer.peek_token ()->get_id () != COMMA) | |
3000 | break; | |
3001 | ||
3002 | // skip commas, including trailing commas | |
3003 | lexer.skip_token (); | |
3004 | } | |
3005 | ||
3006 | lifetime_params.shrink_to_fit (); | |
3007 | ||
3008 | return lifetime_params; | |
3009 | } | |
3010 | ||
3011 | /* Parses lifetime generic parameters (pointers). Will also consume any | |
3012 | * trailing comma. Has extra is_end_token predicate checking. */ | |
3013 | template <typename ManagedTokenSource> | |
3014 | template <typename EndTokenPred> | |
3015 | std::vector<std::unique_ptr<AST::LifetimeParam>> | |
3016 | Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token) | |
3017 | { | |
3018 | std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params; | |
3019 | ||
3020 | // if end_token is not specified, it defaults to EOF, so should work fine | |
3021 | while (!is_end_token (lexer.peek_token ()->get_id ())) | |
3022 | { | |
3023 | AST::LifetimeParam lifetime_param = parse_lifetime_param (); | |
3024 | ||
3025 | if (lifetime_param.is_error ()) | |
3026 | { | |
3027 | /* TODO: is it worth throwing away all lifetime params just because | |
3028 | * one failed? */ | |
3029 | Error error (lexer.peek_token ()->get_locus (), | |
3030 | "failed to parse lifetime param in lifetime params"); | |
3031 | add_error (std::move (error)); | |
3032 | ||
3033 | return {}; | |
3034 | } | |
3035 | ||
3036 | lifetime_params.push_back (std::unique_ptr<AST::LifetimeParam> ( | |
3037 | new AST::LifetimeParam (std::move (lifetime_param)))); | |
3038 | ||
3039 | if (lexer.peek_token ()->get_id () != COMMA) | |
3040 | break; | |
3041 | ||
3042 | // skip commas, including trailing commas | |
3043 | lexer.skip_token (); | |
3044 | } | |
3045 | ||
3046 | lifetime_params.shrink_to_fit (); | |
3047 | ||
3048 | return lifetime_params; | |
3049 | } | |
3050 | ||
3051 | /* Parses lifetime generic parameters (objects). Will also consume any | |
3052 | * trailing comma. No extra checks for end token. | |
3053 | * TODO: is this best solution? implements most of the same algorithm. */ | |
3054 | template <typename ManagedTokenSource> | |
3055 | std::vector<AST::LifetimeParam> | |
3056 | Parser<ManagedTokenSource>::parse_lifetime_params_objs () | |
3057 | { | |
3058 | std::vector<AST::LifetimeParam> lifetime_params; | |
3059 | ||
3060 | // bad control structure as end token cannot be guaranteed | |
3061 | while (true) | |
3062 | { | |
3063 | AST::LifetimeParam lifetime_param = parse_lifetime_param (); | |
3064 | ||
3065 | if (lifetime_param.is_error ()) | |
3066 | { | |
3067 | // not an error as only way to exit if trailing comma | |
3068 | break; | |
3069 | } | |
3070 | ||
3071 | lifetime_params.push_back (std::move (lifetime_param)); | |
3072 | ||
3073 | if (lexer.peek_token ()->get_id () != COMMA) | |
3074 | break; | |
3075 | ||
3076 | // skip commas, including trailing commas | |
3077 | lexer.skip_token (); | |
3078 | } | |
3079 | ||
3080 | lifetime_params.shrink_to_fit (); | |
3081 | ||
3082 | return lifetime_params; | |
3083 | } | |
3084 | ||
3085 | /* Parses lifetime generic parameters (objects). Will also consume any | |
3086 | * trailing comma. Has extra is_end_token predicate checking. | |
3087 | * TODO: is this best solution? implements most of the same algorithm. */ | |
3088 | template <typename ManagedTokenSource> | |
3089 | template <typename EndTokenPred> | |
3090 | std::vector<AST::LifetimeParam> | |
3091 | Parser<ManagedTokenSource>::parse_lifetime_params_objs ( | |
3092 | EndTokenPred is_end_token) | |
3093 | { | |
3094 | std::vector<AST::LifetimeParam> lifetime_params; | |
3095 | ||
3096 | while (!is_end_token (lexer.peek_token ()->get_id ())) | |
3097 | { | |
3098 | AST::LifetimeParam lifetime_param = parse_lifetime_param (); | |
3099 | ||
3100 | if (lifetime_param.is_error ()) | |
3101 | { | |
3102 | /* TODO: is it worth throwing away all lifetime params just because | |
3103 | * one failed? */ | |
3104 | Error error (lexer.peek_token ()->get_locus (), | |
3105 | "failed to parse lifetime param in lifetime params"); | |
3106 | add_error (std::move (error)); | |
3107 | ||
3108 | return {}; | |
3109 | } | |
3110 | ||
3111 | lifetime_params.push_back (std::move (lifetime_param)); | |
3112 | ||
3113 | if (lexer.peek_token ()->get_id () != COMMA) | |
3114 | break; | |
3115 | ||
3116 | // skip commas, including trailing commas | |
3117 | lexer.skip_token (); | |
3118 | } | |
3119 | ||
3120 | lifetime_params.shrink_to_fit (); | |
3121 | ||
3122 | return lifetime_params; | |
3123 | } | |
3124 | ||
3125 | /* Parses a sequence of a certain grammar rule in object form (not pointer or | |
3126 | * smart pointer), delimited by commas and ending when 'is_end_token' is | |
3127 | * satisfied (templated). Will also consume any trailing comma. | |
3128 | * FIXME: this cannot be used due to member function pointer problems (i.e. | |
3129 | * parsing_function cannot be specified properly) */ | |
3130 | template <typename ManagedTokenSource> | |
3131 | template <typename ParseFunction, typename EndTokenPred> | |
3132 | auto | |
3133 | Parser<ManagedTokenSource>::parse_non_ptr_sequence ( | |
3134 | ParseFunction parsing_function, EndTokenPred is_end_token, | |
3135 | std::string error_msg) -> std::vector<decltype (parsing_function ())> | |
3136 | { | |
3137 | std::vector<decltype (parsing_function ())> params; | |
3138 | ||
3139 | while (!is_end_token (lexer.peek_token ()->get_id ())) | |
3140 | { | |
3141 | auto param = parsing_function (); | |
3142 | ||
3143 | if (param.is_error ()) | |
3144 | { | |
3145 | // TODO: is it worth throwing away all params just because one | |
3146 | // failed? | |
3147 | Error error (lexer.peek_token ()->get_locus (), | |
3148 | std::move (error_msg)); | |
3149 | add_error (std::move (error)); | |
3150 | ||
3151 | return {}; | |
3152 | } | |
3153 | ||
3154 | params.push_back (std::move (param)); | |
3155 | ||
3156 | if (lexer.peek_token ()->get_id () != COMMA) | |
3157 | break; | |
3158 | ||
3159 | // skip commas, including trailing commas | |
3160 | lexer.skip_token (); | |
3161 | } | |
3162 | ||
3163 | params.shrink_to_fit (); | |
3164 | ||
3165 | return params; | |
3166 | } | |
3167 | ||
3168 | /* Parses a single lifetime generic parameter (not including comma). */ | |
3169 | template <typename ManagedTokenSource> | |
3170 | AST::LifetimeParam | |
3171 | Parser<ManagedTokenSource>::parse_lifetime_param () | |
3172 | { | |
3173 | // parse outer attribute, which is optional and may not exist | |
3174 | AST::Attribute outer_attr = parse_outer_attribute (); | |
3175 | ||
3176 | // save lifetime token - required | |
3177 | const_TokenPtr lifetime_tok = lexer.peek_token (); | |
3178 | if (lifetime_tok->get_id () != LIFETIME) | |
3179 | { | |
3180 | // if lifetime is missing, must not be a lifetime param, so return null | |
3181 | return AST::LifetimeParam::create_error (); | |
3182 | } | |
3183 | lexer.skip_token (); | |
3184 | /* TODO: does this always create a named lifetime? or can a different type | |
3185 | * be made? */ | |
3186 | AST::Lifetime lifetime (AST::Lifetime::NAMED, lifetime_tok->get_str (), | |
3187 | lifetime_tok->get_locus ()); | |
3188 | ||
3189 | // parse lifetime bounds, if it exists | |
3190 | std::vector<AST::Lifetime> lifetime_bounds; | |
3191 | if (lexer.peek_token ()->get_id () == COLON) | |
3192 | { | |
3193 | // parse lifetime bounds | |
3194 | lifetime_bounds = parse_lifetime_bounds (); | |
3195 | // TODO: have end token passed in? | |
3196 | } | |
3197 | ||
3198 | return AST::LifetimeParam (std::move (lifetime), std::move (lifetime_bounds), | |
3199 | std::move (outer_attr), | |
3200 | lifetime_tok->get_locus ()); | |
3201 | } | |
3202 | ||
3203 | // Parses type generic parameters. Will also consume any trailing comma. | |
3204 | template <typename ManagedTokenSource> | |
3205 | std::vector<std::unique_ptr<AST::TypeParam>> | |
3206 | Parser<ManagedTokenSource>::parse_type_params () | |
3207 | { | |
3208 | std::vector<std::unique_ptr<AST::TypeParam>> type_params; | |
3209 | ||
3210 | // infinite loop with break on failure as no info on ending token | |
3211 | while (true) | |
3212 | { | |
3213 | std::unique_ptr<AST::TypeParam> type_param = parse_type_param (); | |
3214 | ||
3215 | if (type_param == nullptr) | |
3216 | { | |
3217 | // break if fails to parse | |
3218 | break; | |
3219 | } | |
3220 | ||
3221 | type_params.push_back (std::move (type_param)); | |
3222 | ||
3223 | if (lexer.peek_token ()->get_id () != COMMA) | |
3224 | break; | |
3225 | ||
3226 | // skip commas, including trailing commas | |
3227 | lexer.skip_token (); | |
3228 | } | |
3229 | ||
3230 | type_params.shrink_to_fit (); | |
3231 | return type_params; | |
3232 | } | |
3233 | ||
3234 | // Parses type generic parameters. Will also consume any trailing comma. | |
3235 | template <typename ManagedTokenSource> | |
3236 | template <typename EndTokenPred> | |
3237 | std::vector<std::unique_ptr<AST::TypeParam>> | |
3238 | Parser<ManagedTokenSource>::parse_type_params (EndTokenPred is_end_token) | |
3239 | { | |
3240 | std::vector<std::unique_ptr<AST::TypeParam>> type_params; | |
3241 | ||
3242 | while (!is_end_token (lexer.peek_token ()->get_id ())) | |
3243 | { | |
3244 | std::unique_ptr<AST::TypeParam> type_param = parse_type_param (); | |
3245 | ||
3246 | if (type_param == nullptr) | |
3247 | { | |
3248 | Error error (lexer.peek_token ()->get_locus (), | |
3249 | "failed to parse type param in type params"); | |
3250 | add_error (std::move (error)); | |
3251 | ||
3252 | return {}; | |
3253 | } | |
3254 | ||
3255 | type_params.push_back (std::move (type_param)); | |
3256 | ||
3257 | if (lexer.peek_token ()->get_id () != COMMA) | |
3258 | break; | |
3259 | ||
3260 | // skip commas, including trailing commas | |
3261 | lexer.skip_token (); | |
3262 | } | |
3263 | ||
3264 | type_params.shrink_to_fit (); | |
3265 | return type_params; | |
3266 | /* TODO: this shares most code with parse_lifetime_params - good place to | |
3267 | * use template (i.e. parse_non_ptr_sequence if doable) */ | |
3268 | } | |
3269 | ||
3270 | /* Parses a single type (generic) parameter, not including commas. May change | |
3271 | * to return value. */ | |
3272 | template <typename ManagedTokenSource> | |
3273 | std::unique_ptr<AST::TypeParam> | |
3274 | Parser<ManagedTokenSource>::parse_type_param () | |
3275 | { | |
3276 | // parse outer attribute, which is optional and may not exist | |
3277 | AST::Attribute outer_attr = parse_outer_attribute (); | |
3278 | ||
3279 | const_TokenPtr identifier_tok = lexer.peek_token (); | |
3280 | if (identifier_tok->get_id () != IDENTIFIER) | |
3281 | { | |
3282 | // return null as type param can't exist without this required | |
3283 | // identifier | |
3284 | return nullptr; | |
3285 | } | |
3286 | // TODO: create identifier from identifier token | |
3287 | Identifier ident = identifier_tok->get_str (); | |
3288 | lexer.skip_token (); | |
3289 | ||
3290 | // parse type param bounds (if they exist) | |
3291 | std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds; | |
3292 | if (lexer.peek_token ()->get_id () == COLON) | |
3293 | { | |
3294 | lexer.skip_token (); | |
3295 | ||
3296 | // parse type param bounds, which may or may not exist | |
3297 | type_param_bounds = parse_type_param_bounds (); | |
3298 | } | |
3299 | ||
3300 | // parse type (if it exists) | |
3301 | std::unique_ptr<AST::Type> type = nullptr; | |
3302 | if (lexer.peek_token ()->get_id () == EQUAL) | |
3303 | { | |
3304 | lexer.skip_token (); | |
3305 | ||
3306 | // parse type (now required) | |
3307 | type = parse_type (); | |
3308 | if (type == nullptr) | |
3309 | { | |
3310 | Error error (lexer.peek_token ()->get_locus (), | |
3311 | "failed to parse type in type param"); | |
3312 | add_error (std::move (error)); | |
3313 | ||
3314 | return nullptr; | |
3315 | } | |
3316 | } | |
3317 | ||
3318 | return std::unique_ptr<AST::TypeParam> ( | |
3319 | new AST::TypeParam (std::move (ident), identifier_tok->get_locus (), | |
3320 | std::move (type_param_bounds), std::move (type), | |
3321 | std::move (outer_attr))); | |
3322 | } | |
3323 | ||
3324 | /* Parses regular (i.e. non-generic) parameters in functions or methods. Also | |
3325 | * has end token handling. */ | |
3326 | template <typename ManagedTokenSource> | |
3327 | template <typename EndTokenPred> | |
3328 | std::vector<AST::FunctionParam> | |
3329 | Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token) | |
3330 | { | |
3331 | std::vector<AST::FunctionParam> params; | |
3332 | ||
3333 | if (is_end_token (lexer.peek_token ()->get_id ())) | |
3334 | return params; | |
3335 | ||
3336 | AST::FunctionParam initial_param = parse_function_param (); | |
3337 | ||
3338 | // Return empty parameter list if no parameter there | |
3339 | if (initial_param.is_error ()) | |
3340 | { | |
3341 | // TODO: is this an error? | |
3342 | return params; | |
3343 | } | |
3344 | ||
3345 | params.push_back (std::move (initial_param)); | |
3346 | ||
3347 | // maybe think of a better control structure here - do-while with an initial | |
3348 | // error state? basically, loop through parameter list until can't find any | |
3349 | // more params | |
3350 | const_TokenPtr t = lexer.peek_token (); | |
3351 | while (t->get_id () == COMMA) | |
3352 | { | |
3353 | // skip comma if applies | |
3354 | lexer.skip_token (); | |
3355 | ||
3356 | // TODO: strictly speaking, shouldn't there be no trailing comma? | |
3357 | if (is_end_token (lexer.peek_token ()->get_id ())) | |
3358 | break; | |
3359 | ||
3360 | // now, as right paren would break, function param is required | |
3361 | AST::FunctionParam param = parse_function_param (); | |
3362 | if (param.is_error ()) | |
3363 | { | |
3364 | Error error (lexer.peek_token ()->get_locus (), | |
3365 | "failed to parse function param (in function params)"); | |
3366 | add_error (std::move (error)); | |
3367 | ||
3368 | // skip somewhere? | |
3369 | return std::vector<AST::FunctionParam> (); | |
3370 | } | |
3371 | ||
3372 | params.push_back (std::move (param)); | |
3373 | ||
3374 | t = lexer.peek_token (); | |
3375 | } | |
3376 | ||
3377 | params.shrink_to_fit (); | |
3378 | return params; | |
3379 | } | |
3380 | ||
3381 | /* Parses a single regular (i.e. non-generic) parameter in a function or | |
3382 | * method, i.e. the "name: type" bit. Also handles it not existing. */ | |
3383 | template <typename ManagedTokenSource> | |
3384 | AST::FunctionParam | |
3385 | Parser<ManagedTokenSource>::parse_function_param () | |
3386 | { | |
3387 | // parse outer attributes if they exist | |
3388 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
3389 | ||
3390 | // TODO: should saved location be at start of outer attributes or pattern? | |
3391 | Location locus = lexer.peek_token ()->get_locus (); | |
3392 | std::unique_ptr<AST::Pattern> param_pattern = parse_pattern (); | |
3393 | ||
3394 | // create error function param if it doesn't exist | |
3395 | if (param_pattern == nullptr) | |
3396 | { | |
3397 | // skip after something | |
3398 | return AST::FunctionParam::create_error (); | |
3399 | } | |
3400 | ||
3401 | if (!skip_token (COLON)) | |
3402 | { | |
3403 | // skip after something | |
3404 | return AST::FunctionParam::create_error (); | |
3405 | } | |
3406 | ||
3407 | std::unique_ptr<AST::Type> param_type = parse_type (); | |
3408 | if (param_type == nullptr) | |
3409 | { | |
3410 | // skip? | |
3411 | return AST::FunctionParam::create_error (); | |
3412 | } | |
3413 | ||
3414 | return AST::FunctionParam (std::move (param_pattern), std::move (param_type), | |
3415 | std::move (outer_attrs), locus); | |
3416 | } | |
3417 | ||
3418 | /* Parses a function or method return type syntactical construction. Also | |
3419 | * handles a function return type not existing. */ | |
3420 | template <typename ManagedTokenSource> | |
3421 | std::unique_ptr<AST::Type> | |
3422 | Parser<ManagedTokenSource>::parse_function_return_type () | |
3423 | { | |
3424 | if (lexer.peek_token ()->get_id () != RETURN_TYPE) | |
3425 | return nullptr; | |
3426 | ||
3427 | // skip return type, as it now obviously exists | |
3428 | lexer.skip_token (); | |
3429 | ||
3430 | std::unique_ptr<AST::Type> type = parse_type (); | |
3431 | ||
3432 | return type; | |
3433 | } | |
3434 | ||
3435 | /* Parses a "where clause" (in a function, struct, method, etc.). Also handles | |
3436 | * a where clause not existing, in which it will return | |
3437 | * WhereClause::create_empty(), which can be checked via | |
3438 | * WhereClause::is_empty(). */ | |
3439 | template <typename ManagedTokenSource> | |
3440 | AST::WhereClause | |
3441 | Parser<ManagedTokenSource>::parse_where_clause () | |
3442 | { | |
3443 | const_TokenPtr where_tok = lexer.peek_token (); | |
3444 | if (where_tok->get_id () != WHERE) | |
3445 | { | |
3446 | // where clause doesn't exist, so create empty one | |
3447 | return AST::WhereClause::create_empty (); | |
3448 | } | |
3449 | ||
3450 | lexer.skip_token (); | |
3451 | ||
3452 | /* parse where clause items - this is not a separate rule in the reference | |
3453 | * so won't be here */ | |
3454 | std::vector<std::unique_ptr<AST::WhereClauseItem>> where_clause_items; | |
3455 | ||
3456 | /* HACK: where clauses end with a right curly or semicolon or equals in all | |
3457 | * uses currently */ | |
3458 | const_TokenPtr t = lexer.peek_token (); | |
3459 | while (t->get_id () != LEFT_CURLY && t->get_id () != SEMICOLON | |
3460 | && t->get_id () != EQUAL) | |
3461 | { | |
3462 | std::unique_ptr<AST::WhereClauseItem> where_clause_item | |
3463 | = parse_where_clause_item (); | |
3464 | ||
3465 | if (where_clause_item == nullptr) | |
3466 | { | |
3467 | Error error (t->get_locus (), "failed to parse where clause item"); | |
3468 | add_error (std::move (error)); | |
3469 | ||
3470 | return AST::WhereClause::create_empty (); | |
3471 | } | |
3472 | ||
3473 | where_clause_items.push_back (std::move (where_clause_item)); | |
3474 | ||
3475 | // also skip comma if it exists | |
3476 | if (lexer.peek_token ()->get_id () != COMMA) | |
3477 | break; | |
3478 | ||
3479 | lexer.skip_token (); | |
3480 | t = lexer.peek_token (); | |
3481 | } | |
3482 | ||
3483 | where_clause_items.shrink_to_fit (); | |
3484 | return AST::WhereClause (std::move (where_clause_items)); | |
3485 | } | |
3486 | ||
3487 | /* Parses a where clause item (lifetime or type bound). Does not parse any | |
3488 | * commas. */ | |
3489 | template <typename ManagedTokenSource> | |
3490 | std::unique_ptr<AST::WhereClauseItem> | |
3491 | Parser<ManagedTokenSource>::parse_where_clause_item () | |
3492 | { | |
3493 | // shitty cheat way of determining lifetime or type bound - test for | |
3494 | // lifetime | |
3495 | const_TokenPtr t = lexer.peek_token (); | |
3496 | ||
3497 | if (t->get_id () == LIFETIME) | |
3498 | return parse_lifetime_where_clause_item (); | |
3499 | else | |
3500 | return parse_type_bound_where_clause_item (); | |
3501 | } | |
3502 | ||
3503 | // Parses a lifetime where clause item. | |
3504 | template <typename ManagedTokenSource> | |
3505 | std::unique_ptr<AST::LifetimeWhereClauseItem> | |
3506 | Parser<ManagedTokenSource>::parse_lifetime_where_clause_item () | |
3507 | { | |
3508 | AST::Lifetime lifetime = parse_lifetime (); | |
3509 | if (lifetime.is_error ()) | |
3510 | { | |
3511 | // TODO: error here? | |
3512 | return nullptr; | |
3513 | } | |
3514 | ||
3515 | if (!skip_token (COLON)) | |
3516 | { | |
3517 | // TODO: skip after somewhere | |
3518 | return nullptr; | |
3519 | } | |
3520 | ||
3521 | std::vector<AST::Lifetime> lifetime_bounds = parse_lifetime_bounds (); | |
3522 | // TODO: have end token passed in? | |
3523 | ||
3524 | Location locus = lifetime.get_locus (); | |
3525 | ||
3526 | return std::unique_ptr<AST::LifetimeWhereClauseItem> ( | |
3527 | new AST::LifetimeWhereClauseItem (std::move (lifetime), | |
3528 | std::move (lifetime_bounds), locus)); | |
3529 | } | |
3530 | ||
3531 | // Parses a type bound where clause item. | |
3532 | template <typename ManagedTokenSource> | |
3533 | std::unique_ptr<AST::TypeBoundWhereClauseItem> | |
3534 | Parser<ManagedTokenSource>::parse_type_bound_where_clause_item () | |
3535 | { | |
3536 | // parse for lifetimes, if it exists | |
3537 | std::vector<AST::LifetimeParam> for_lifetimes; | |
3538 | if (lexer.peek_token ()->get_id () == FOR) | |
3539 | for_lifetimes = parse_for_lifetimes (); | |
3540 | ||
3541 | std::unique_ptr<AST::Type> type = parse_type (); | |
3542 | if (type == nullptr) | |
3543 | { | |
3544 | return nullptr; | |
3545 | } | |
3546 | ||
3547 | if (!skip_token (COLON)) | |
3548 | { | |
3549 | // TODO: skip after somewhere | |
3550 | return nullptr; | |
3551 | } | |
3552 | ||
3553 | // parse type param bounds if they exist | |
3554 | std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds | |
3555 | = parse_type_param_bounds (); | |
3556 | ||
3557 | Location locus = lexer.peek_token ()->get_locus (); | |
3558 | ||
3559 | return std::unique_ptr<AST::TypeBoundWhereClauseItem> ( | |
3560 | new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes), | |
3561 | std::move (type), | |
3562 | std::move (type_param_bounds), locus)); | |
3563 | } | |
3564 | ||
3565 | // Parses a for lifetimes clause, including the for keyword and angle | |
3566 | // brackets. | |
3567 | template <typename ManagedTokenSource> | |
3568 | std::vector<AST::LifetimeParam> | |
3569 | Parser<ManagedTokenSource>::parse_for_lifetimes () | |
3570 | { | |
3571 | std::vector<AST::LifetimeParam> params; | |
3572 | ||
3573 | if (!skip_token (FOR)) | |
3574 | { | |
3575 | // skip after somewhere? | |
3576 | return params; | |
3577 | } | |
3578 | ||
3579 | if (!skip_token (LEFT_ANGLE)) | |
3580 | { | |
3581 | // skip after somewhere? | |
3582 | return params; | |
3583 | } | |
3584 | ||
3585 | /* cannot specify end token due to parsing problems with '>' tokens being | |
3586 | * nested */ | |
3587 | params = parse_lifetime_params_objs (is_right_angle_tok); | |
3588 | ||
3589 | if (!skip_generics_right_angle ()) | |
3590 | { | |
3591 | // DEBUG | |
3592 | rust_debug ("failed to skip generics right angle after (supposedly) " | |
3593 | "finished parsing where clause items"); | |
3594 | // ok, well this gets called. | |
3595 | ||
3596 | // skip after somewhere? | |
3597 | return params; | |
3598 | } | |
3599 | ||
3600 | return params; | |
3601 | } | |
3602 | ||
3603 | // Parses type parameter bounds in where clause or generic arguments. | |
3604 | template <typename ManagedTokenSource> | |
3605 | std::vector<std::unique_ptr<AST::TypeParamBound>> | |
3606 | Parser<ManagedTokenSource>::parse_type_param_bounds () | |
3607 | { | |
3608 | std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds; | |
3609 | ||
3610 | std::unique_ptr<AST::TypeParamBound> initial_bound | |
3611 | = parse_type_param_bound (); | |
3612 | ||
3613 | // quick exit if null | |
3614 | if (initial_bound == nullptr) | |
3615 | { | |
3616 | /* error? type param bounds must have at least one term, but are bounds | |
3617 | * optional? */ | |
3618 | return type_param_bounds; | |
3619 | } | |
3620 | type_param_bounds.push_back (std::move (initial_bound)); | |
3621 | ||
3622 | while (lexer.peek_token ()->get_id () == PLUS) | |
3623 | { | |
3624 | lexer.skip_token (); | |
3625 | ||
3626 | std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound (); | |
3627 | if (bound == nullptr) | |
3628 | { | |
3629 | /* not an error: bound is allowed to be null as trailing plus is | |
3630 | * allowed */ | |
3631 | return type_param_bounds; | |
3632 | } | |
3633 | ||
3634 | type_param_bounds.push_back (std::move (bound)); | |
3635 | } | |
3636 | ||
3637 | type_param_bounds.shrink_to_fit (); | |
3638 | return type_param_bounds; | |
3639 | } | |
3640 | ||
3641 | /* Parses type parameter bounds in where clause or generic arguments, with end | |
3642 | * token handling. */ | |
3643 | template <typename ManagedTokenSource> | |
3644 | template <typename EndTokenPred> | |
3645 | std::vector<std::unique_ptr<AST::TypeParamBound>> | |
3646 | Parser<ManagedTokenSource>::parse_type_param_bounds (EndTokenPred is_end_token) | |
3647 | { | |
3648 | std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds; | |
3649 | ||
3650 | std::unique_ptr<AST::TypeParamBound> initial_bound | |
3651 | = parse_type_param_bound (); | |
3652 | ||
3653 | // quick exit if null | |
3654 | if (initial_bound == nullptr) | |
3655 | { | |
3656 | /* error? type param bounds must have at least one term, but are bounds | |
3657 | * optional? */ | |
3658 | return type_param_bounds; | |
3659 | } | |
3660 | type_param_bounds.push_back (std::move (initial_bound)); | |
3661 | ||
3662 | while (lexer.peek_token ()->get_id () == PLUS) | |
3663 | { | |
3664 | lexer.skip_token (); | |
3665 | ||
3666 | // break if end token character | |
3667 | if (is_end_token (lexer.peek_token ()->get_id ())) | |
3668 | break; | |
3669 | ||
3670 | std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound (); | |
3671 | if (bound == nullptr) | |
3672 | { | |
3673 | // TODO how wise is it to ditch all bounds if only one failed? | |
3674 | Error error (lexer.peek_token ()->get_locus (), | |
3675 | "failed to parse type param bound in type param bounds"); | |
3676 | add_error (std::move (error)); | |
3677 | ||
3678 | return {}; | |
3679 | } | |
3680 | ||
3681 | type_param_bounds.push_back (std::move (bound)); | |
3682 | } | |
3683 | ||
3684 | type_param_bounds.shrink_to_fit (); | |
3685 | return type_param_bounds; | |
3686 | } | |
3687 | ||
3688 | /* Parses a single type parameter bound in a where clause or generic argument. | |
3689 | * Does not parse the '+' between arguments. */ | |
3690 | template <typename ManagedTokenSource> | |
3691 | std::unique_ptr<AST::TypeParamBound> | |
3692 | Parser<ManagedTokenSource>::parse_type_param_bound () | |
3693 | { | |
3694 | // shitty cheat way of determining lifetime or trait bound - test for | |
3695 | // lifetime | |
3696 | const_TokenPtr t = lexer.peek_token (); | |
3697 | switch (t->get_id ()) | |
3698 | { | |
3699 | case LIFETIME: | |
3700 | return std::unique_ptr<AST::Lifetime> ( | |
3701 | new AST::Lifetime (parse_lifetime ())); | |
3702 | case LEFT_PAREN: | |
3703 | case QUESTION_MARK: | |
3704 | case FOR: | |
3705 | case IDENTIFIER: | |
3706 | case SUPER: | |
3707 | case SELF: | |
3708 | case SELF_ALIAS: | |
3709 | case CRATE: | |
3710 | case DOLLAR_SIGN: | |
3711 | return parse_trait_bound (); | |
3712 | default: | |
3713 | // don't error - assume this is fine TODO | |
3714 | return nullptr; | |
3715 | } | |
3716 | } | |
3717 | ||
3718 | // Parses a trait bound type param bound. | |
3719 | template <typename ManagedTokenSource> | |
3720 | std::unique_ptr<AST::TraitBound> | |
3721 | Parser<ManagedTokenSource>::parse_trait_bound () | |
3722 | { | |
3723 | bool has_parens = false; | |
3724 | bool has_question_mark = false; | |
3725 | ||
3726 | Location locus = lexer.peek_token ()->get_locus (); | |
3727 | ||
3728 | // handle trait bound being in parentheses | |
3729 | if (lexer.peek_token ()->get_id () == LEFT_PAREN) | |
3730 | { | |
3731 | has_parens = true; | |
3732 | lexer.skip_token (); | |
3733 | } | |
3734 | ||
3735 | // handle having question mark (optional) | |
3736 | if (lexer.peek_token ()->get_id () == QUESTION_MARK) | |
3737 | { | |
3738 | has_question_mark = true; | |
3739 | lexer.skip_token (); | |
3740 | } | |
3741 | ||
3742 | /* parse for lifetimes, if it exists (although empty for lifetimes is ok to | |
3743 | * handle this) */ | |
3744 | std::vector<AST::LifetimeParam> for_lifetimes; | |
3745 | if (lexer.peek_token ()->get_id () == FOR) | |
3746 | for_lifetimes = parse_for_lifetimes (); | |
3747 | ||
3748 | // handle TypePath | |
3749 | AST::TypePath type_path = parse_type_path (); | |
3750 | ||
3751 | // handle closing parentheses | |
3752 | if (has_parens) | |
3753 | { | |
3754 | if (!skip_token (RIGHT_PAREN)) | |
3755 | { | |
3756 | return nullptr; | |
3757 | } | |
3758 | } | |
3759 | ||
3760 | return std::unique_ptr<AST::TraitBound> ( | |
3761 | new AST::TraitBound (std::move (type_path), locus, has_parens, | |
3762 | has_question_mark, std::move (for_lifetimes))); | |
3763 | } | |
3764 | ||
3765 | // Parses lifetime bounds. | |
3766 | template <typename ManagedTokenSource> | |
3767 | std::vector<AST::Lifetime> | |
3768 | Parser<ManagedTokenSource>::parse_lifetime_bounds () | |
3769 | { | |
3770 | std::vector<AST::Lifetime> lifetime_bounds; | |
3771 | ||
3772 | while (true) | |
3773 | { | |
3774 | AST::Lifetime lifetime = parse_lifetime (); | |
3775 | ||
3776 | // quick exit for parsing failure | |
3777 | if (lifetime.is_error ()) | |
3778 | break; | |
3779 | ||
3780 | lifetime_bounds.push_back (std::move (lifetime)); | |
3781 | ||
3782 | /* plus is maybe not allowed at end - spec defines it weirdly, so | |
3783 | * assuming allowed at end */ | |
3784 | if (lexer.peek_token ()->get_id () != PLUS) | |
3785 | break; | |
3786 | ||
3787 | lexer.skip_token (); | |
3788 | } | |
3789 | ||
3790 | lifetime_bounds.shrink_to_fit (); | |
3791 | return lifetime_bounds; | |
3792 | } | |
3793 | ||
3794 | // Parses lifetime bounds, with added check for ending token. | |
3795 | template <typename ManagedTokenSource> | |
3796 | template <typename EndTokenPred> | |
3797 | std::vector<AST::Lifetime> | |
3798 | Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token) | |
3799 | { | |
3800 | std::vector<AST::Lifetime> lifetime_bounds; | |
3801 | ||
3802 | while (!is_end_token (lexer.peek_token ()->get_id ())) | |
3803 | { | |
3804 | AST::Lifetime lifetime = parse_lifetime (); | |
3805 | ||
3806 | if (lifetime.is_error ()) | |
3807 | { | |
3808 | /* TODO: is it worth throwing away all lifetime bound info just | |
3809 | * because one failed? */ | |
3810 | Error error (lexer.peek_token ()->get_locus (), | |
3811 | "failed to parse lifetime in lifetime bounds"); | |
3812 | add_error (std::move (error)); | |
3813 | ||
3814 | return {}; | |
3815 | } | |
3816 | ||
3817 | lifetime_bounds.push_back (std::move (lifetime)); | |
3818 | ||
3819 | /* plus is maybe not allowed at end - spec defines it weirdly, so | |
3820 | * assuming allowed at end */ | |
3821 | if (lexer.peek_token ()->get_id () != PLUS) | |
3822 | break; | |
3823 | ||
3824 | lexer.skip_token (); | |
3825 | } | |
3826 | ||
3827 | lifetime_bounds.shrink_to_fit (); | |
3828 | return lifetime_bounds; | |
3829 | } | |
3830 | ||
3831 | /* Parses a lifetime token (named, 'static, or '_). Also handles lifetime not | |
3832 | * existing. */ | |
3833 | template <typename ManagedTokenSource> | |
3834 | AST::Lifetime | |
3835 | Parser<ManagedTokenSource>::parse_lifetime () | |
3836 | { | |
3837 | const_TokenPtr lifetime_tok = lexer.peek_token (); | |
3838 | Location locus = lifetime_tok->get_locus (); | |
3839 | // create error lifetime if doesn't exist | |
3840 | if (lifetime_tok->get_id () != LIFETIME) | |
3841 | { | |
3842 | return AST::Lifetime::error (); | |
3843 | } | |
3844 | lexer.skip_token (); | |
3845 | ||
3846 | std::string lifetime_ident = lifetime_tok->get_str (); | |
3847 | ||
3848 | if (lifetime_ident == "'static") | |
3849 | { | |
3850 | return AST::Lifetime (AST::Lifetime::STATIC, "", locus); | |
3851 | } | |
3852 | else if (lifetime_ident == "'_") | |
3853 | { | |
3854 | return AST::Lifetime (AST::Lifetime::WILDCARD, "", locus); | |
3855 | } | |
3856 | else | |
3857 | { | |
3858 | return AST::Lifetime (AST::Lifetime::NAMED, std::move (lifetime_ident), | |
3859 | locus); | |
3860 | } | |
3861 | } | |
3862 | ||
3863 | // Parses a "type alias" (typedef) item. | |
3864 | template <typename ManagedTokenSource> | |
3865 | std::unique_ptr<AST::TypeAlias> | |
3866 | Parser<ManagedTokenSource>::parse_type_alias (AST::Visibility vis, | |
3867 | AST::AttrVec outer_attrs) | |
3868 | { | |
3869 | Location locus = lexer.peek_token ()->get_locus (); | |
3870 | skip_token (TYPE); | |
3871 | ||
3872 | // TODO: use this token for identifier when finished that | |
3873 | const_TokenPtr alias_name_tok = expect_token (IDENTIFIER); | |
3874 | if (alias_name_tok == nullptr) | |
3875 | { | |
3876 | Error error (lexer.peek_token ()->get_locus (), | |
3877 | "could not parse identifier in type alias"); | |
3878 | add_error (std::move (error)); | |
3879 | ||
3880 | skip_after_semicolon (); | |
3881 | return nullptr; | |
3882 | } | |
3883 | Identifier alias_name = alias_name_tok->get_str (); | |
3884 | ||
3885 | // parse generic params, which may not exist | |
3886 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
3887 | = parse_generic_params_in_angles (); | |
3888 | ||
3889 | // parse where clause, which may not exist | |
3890 | AST::WhereClause where_clause = parse_where_clause (); | |
3891 | ||
3892 | if (!skip_token (EQUAL)) | |
3893 | { | |
3894 | skip_after_semicolon (); | |
3895 | return nullptr; | |
3896 | } | |
3897 | ||
3898 | std::unique_ptr<AST::Type> type_to_alias = parse_type (); | |
3899 | ||
3900 | if (!skip_token (SEMICOLON)) | |
3901 | { | |
3902 | // should be skipping past this, not the next line | |
3903 | return nullptr; | |
3904 | } | |
3905 | ||
3906 | return std::unique_ptr<AST::TypeAlias> ( | |
3907 | new AST::TypeAlias (std::move (alias_name), std::move (generic_params), | |
3908 | std::move (where_clause), std::move (type_to_alias), | |
3909 | std::move (vis), std::move (outer_attrs), locus)); | |
3910 | } | |
3911 | ||
3912 | // Parse a struct item AST node. | |
3913 | template <typename ManagedTokenSource> | |
3914 | std::unique_ptr<AST::Struct> | |
3915 | Parser<ManagedTokenSource>::parse_struct (AST::Visibility vis, | |
3916 | AST::AttrVec outer_attrs) | |
3917 | { | |
3918 | /* TODO: determine best way to parse the proper struct vs tuple struct - | |
3919 | * share most of initial constructs so lookahead might be impossible, and if | |
3920 | * not probably too expensive. Best way is probably unified parsing for the | |
3921 | * initial parts and then pass them in as params to more derived functions. | |
3922 | * Alternatively, just parse everything in this one function - do this if | |
3923 | * function not too long. */ | |
3924 | ||
3925 | /* Proper struct <- 'struct' IDENTIFIER generic_params? where_clause? ( '{' | |
3926 | * struct_fields? '}' | ';' ) */ | |
3927 | /* Tuple struct <- 'struct' IDENTIFIER generic_params? '(' tuple_fields? ')' | |
3928 | * where_clause? ';' */ | |
3929 | Location locus = lexer.peek_token ()->get_locus (); | |
3930 | skip_token (STRUCT_TOK); | |
3931 | ||
3932 | // parse struct name | |
3933 | const_TokenPtr name_tok = expect_token (IDENTIFIER); | |
3934 | if (name_tok == nullptr) | |
3935 | { | |
3936 | Error error (lexer.peek_token ()->get_locus (), | |
3937 | "could not parse struct or tuple struct identifier"); | |
3938 | add_error (std::move (error)); | |
3939 | ||
3940 | // skip after somewhere? | |
3941 | return nullptr; | |
3942 | } | |
3943 | Identifier struct_name = name_tok->get_str (); | |
3944 | ||
3945 | // parse generic params, which may or may not exist | |
3946 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
3947 | = parse_generic_params_in_angles (); | |
3948 | ||
3949 | // branch on next token - determines whether proper struct or tuple struct | |
3950 | if (lexer.peek_token ()->get_id () == LEFT_PAREN) | |
3951 | { | |
3952 | // tuple struct | |
3953 | ||
3954 | // skip left parenthesis | |
3955 | lexer.skip_token (); | |
3956 | ||
3957 | // parse tuple fields | |
3958 | std::vector<AST::TupleField> tuple_fields; | |
3959 | // Might be empty tuple for unit tuple struct. | |
3960 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
3961 | tuple_fields = std::vector<AST::TupleField> (); | |
3962 | else | |
3963 | tuple_fields = parse_tuple_fields (); | |
3964 | ||
3965 | // tuple parameters must have closing parenthesis | |
3966 | if (!skip_token (RIGHT_PAREN)) | |
3967 | { | |
3968 | skip_after_semicolon (); | |
3969 | return nullptr; | |
3970 | } | |
3971 | ||
3972 | // parse where clause, which is optional | |
3973 | AST::WhereClause where_clause = parse_where_clause (); | |
3974 | ||
3975 | if (!skip_token (SEMICOLON)) | |
3976 | { | |
3977 | // can't skip after semicolon because it's meant to be here | |
3978 | return nullptr; | |
3979 | } | |
3980 | ||
3981 | return std::unique_ptr<AST::TupleStruct> ( | |
3982 | new AST::TupleStruct (std::move (tuple_fields), std::move (struct_name), | |
3983 | std::move (generic_params), | |
3984 | std::move (where_clause), std::move (vis), | |
3985 | std::move (outer_attrs), locus)); | |
3986 | } | |
3987 | ||
3988 | // assume it is a proper struct being parsed and continue outside of switch | |
3989 | // - label only here to suppress warning | |
3990 | ||
3991 | // parse where clause, which is optional | |
3992 | AST::WhereClause where_clause = parse_where_clause (); | |
3993 | ||
3994 | // branch on next token - determines whether struct is a unit struct | |
3995 | const_TokenPtr t = lexer.peek_token (); | |
3996 | switch (t->get_id ()) | |
3997 | { | |
3998 | case LEFT_CURLY: { | |
3999 | // struct with body | |
4000 | ||
4001 | // skip curly bracket | |
4002 | lexer.skip_token (); | |
4003 | ||
4004 | // parse struct fields, if any | |
4005 | std::vector<AST::StructField> struct_fields | |
4006 | = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; }); | |
4007 | ||
4008 | if (!skip_token (RIGHT_CURLY)) | |
4009 | { | |
4010 | // skip somewhere? | |
4011 | return nullptr; | |
4012 | } | |
4013 | ||
4014 | return std::unique_ptr<AST::StructStruct> (new AST::StructStruct ( | |
4015 | std::move (struct_fields), std::move (struct_name), | |
4016 | std::move (generic_params), std::move (where_clause), false, | |
4017 | std::move (vis), std::move (outer_attrs), locus)); | |
4018 | } | |
4019 | case SEMICOLON: | |
4020 | // unit struct declaration | |
4021 | ||
4022 | lexer.skip_token (); | |
4023 | ||
4024 | return std::unique_ptr<AST::StructStruct> ( | |
4025 | new AST::StructStruct (std::move (struct_name), | |
4026 | std::move (generic_params), | |
4027 | std::move (where_clause), std::move (vis), | |
4028 | std::move (outer_attrs), locus)); | |
4029 | default: | |
4030 | add_error (Error (t->get_locus (), | |
4031 | "unexpected token %qs in struct declaration", | |
4032 | t->get_token_description ())); | |
4033 | ||
4034 | // skip somewhere? | |
4035 | return nullptr; | |
4036 | } | |
4037 | } | |
4038 | ||
4039 | // Parses struct fields in struct declarations. | |
4040 | template <typename ManagedTokenSource> | |
4041 | std::vector<AST::StructField> | |
4042 | Parser<ManagedTokenSource>::parse_struct_fields () | |
4043 | { | |
4044 | std::vector<AST::StructField> fields; | |
4045 | ||
4046 | AST::StructField initial_field = parse_struct_field (); | |
4047 | ||
4048 | // Return empty field list if no field there | |
4049 | if (initial_field.is_error ()) | |
4050 | return fields; | |
4051 | ||
4052 | fields.push_back (std::move (initial_field)); | |
4053 | ||
4054 | while (lexer.peek_token ()->get_id () == COMMA) | |
4055 | { | |
4056 | lexer.skip_token (); | |
4057 | ||
4058 | AST::StructField field = parse_struct_field (); | |
4059 | ||
4060 | if (field.is_error ()) | |
4061 | { | |
4062 | // would occur with trailing comma, so allowed | |
4063 | break; | |
4064 | } | |
4065 | ||
4066 | fields.push_back (std::move (field)); | |
4067 | } | |
4068 | ||
4069 | fields.shrink_to_fit (); | |
4070 | return fields; | |
4071 | // TODO: template if possible (parse_non_ptr_seq) | |
4072 | } | |
4073 | ||
4074 | // Parses struct fields in struct declarations. | |
4075 | template <typename ManagedTokenSource> | |
4076 | template <typename EndTokenPred> | |
4077 | std::vector<AST::StructField> | |
4078 | Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok) | |
4079 | { | |
4080 | std::vector<AST::StructField> fields; | |
4081 | ||
4082 | AST::StructField initial_field = parse_struct_field (); | |
4083 | ||
4084 | // Return empty field list if no field there | |
4085 | if (initial_field.is_error ()) | |
4086 | return fields; | |
4087 | ||
4088 | fields.push_back (std::move (initial_field)); | |
4089 | ||
4090 | while (lexer.peek_token ()->get_id () == COMMA) | |
4091 | { | |
4092 | lexer.skip_token (); | |
4093 | ||
4094 | if (is_end_tok (lexer.peek_token ()->get_id ())) | |
4095 | break; | |
4096 | ||
4097 | AST::StructField field = parse_struct_field (); | |
4098 | if (field.is_error ()) | |
4099 | { | |
4100 | /* TODO: should every field be ditched just because one couldn't be | |
4101 | * parsed? */ | |
4102 | Error error (lexer.peek_token ()->get_locus (), | |
4103 | "failed to parse struct field in struct fields"); | |
4104 | add_error (std::move (error)); | |
4105 | ||
4106 | return {}; | |
4107 | } | |
4108 | ||
4109 | fields.push_back (std::move (field)); | |
4110 | } | |
4111 | ||
4112 | fields.shrink_to_fit (); | |
4113 | return fields; | |
4114 | // TODO: template if possible (parse_non_ptr_seq) | |
4115 | } | |
4116 | ||
4117 | // Parses a single struct field (in a struct definition). Does not parse | |
4118 | // commas. | |
4119 | template <typename ManagedTokenSource> | |
4120 | AST::StructField | |
4121 | Parser<ManagedTokenSource>::parse_struct_field () | |
4122 | { | |
4123 | // parse outer attributes, if they exist | |
4124 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
4125 | ||
4126 | // parse visibility, if it exists | |
4127 | AST::Visibility vis = parse_visibility (); | |
4128 | ||
4129 | Location locus = lexer.peek_token ()->get_locus (); | |
4130 | ||
4131 | // parse field name | |
4132 | const_TokenPtr field_name_tok = lexer.peek_token (); | |
4133 | if (field_name_tok->get_id () != IDENTIFIER) | |
4134 | { | |
4135 | // if not identifier, assumes there is no struct field and exits - not | |
4136 | // necessarily error | |
4137 | return AST::StructField::create_error (); | |
4138 | } | |
4139 | Identifier field_name = field_name_tok->get_str (); | |
4140 | lexer.skip_token (); | |
4141 | ||
4142 | if (!skip_token (COLON)) | |
4143 | { | |
4144 | // skip after somewhere? | |
4145 | return AST::StructField::create_error (); | |
4146 | } | |
4147 | ||
4148 | // parse field type - this is required | |
4149 | std::unique_ptr<AST::Type> field_type = parse_type (); | |
4150 | if (field_type == nullptr) | |
4151 | { | |
4152 | Error error (lexer.peek_token ()->get_locus (), | |
4153 | "could not parse type in struct field definition"); | |
4154 | add_error (std::move (error)); | |
4155 | ||
4156 | // skip after somewhere | |
4157 | return AST::StructField::create_error (); | |
4158 | } | |
4159 | ||
4160 | return AST::StructField (std::move (field_name), std::move (field_type), | |
4161 | std::move (vis), locus, std::move (outer_attrs)); | |
4162 | } | |
4163 | ||
4164 | // Parses tuple fields in tuple/tuple struct declarations. | |
4165 | template <typename ManagedTokenSource> | |
4166 | std::vector<AST::TupleField> | |
4167 | Parser<ManagedTokenSource>::parse_tuple_fields () | |
4168 | { | |
4169 | std::vector<AST::TupleField> fields; | |
4170 | ||
4171 | AST::TupleField initial_field = parse_tuple_field (); | |
4172 | ||
4173 | // Return empty field list if no field there | |
4174 | if (initial_field.is_error ()) | |
4175 | { | |
4176 | return fields; | |
4177 | } | |
4178 | ||
4179 | fields.push_back (std::move (initial_field)); | |
4180 | ||
4181 | // maybe think of a better control structure here - do-while with an initial | |
4182 | // error state? basically, loop through field list until can't find any more | |
4183 | // params HACK: all current syntax uses of tuple fields have them ending | |
4184 | // with a right paren token | |
4185 | const_TokenPtr t = lexer.peek_token (); | |
4186 | while (t->get_id () == COMMA) | |
4187 | { | |
4188 | // skip comma if applies - e.g. trailing comma | |
4189 | lexer.skip_token (); | |
4190 | ||
4191 | // break out due to right paren if it exists | |
4192 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
4193 | { | |
4194 | break; | |
4195 | } | |
4196 | ||
4197 | AST::TupleField field = parse_tuple_field (); | |
4198 | if (field.is_error ()) | |
4199 | { | |
4200 | Error error (lexer.peek_token ()->get_locus (), | |
4201 | "failed to parse tuple field in tuple fields"); | |
4202 | add_error (std::move (error)); | |
4203 | ||
4204 | return std::vector<AST::TupleField> (); | |
4205 | } | |
4206 | ||
4207 | fields.push_back (std::move (field)); | |
4208 | ||
4209 | t = lexer.peek_token (); | |
4210 | } | |
4211 | ||
4212 | fields.shrink_to_fit (); | |
4213 | return fields; | |
4214 | ||
4215 | // TODO: this shares basically all code with function params and struct | |
4216 | // fields | |
4217 | // - templates? | |
4218 | } | |
4219 | ||
4220 | /* Parses a single tuple struct field in a tuple struct definition. Does not | |
4221 | * parse commas. */ | |
4222 | template <typename ManagedTokenSource> | |
4223 | AST::TupleField | |
4224 | Parser<ManagedTokenSource>::parse_tuple_field () | |
4225 | { | |
4226 | // parse outer attributes if they exist | |
4227 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
4228 | ||
4229 | // parse visibility if it exists | |
4230 | AST::Visibility vis = parse_visibility (); | |
4231 | ||
4232 | Location locus = lexer.peek_token ()->get_locus (); | |
4233 | ||
4234 | // parse type, which is required | |
4235 | std::unique_ptr<AST::Type> field_type = parse_type (); | |
4236 | if (field_type == nullptr) | |
4237 | { | |
4238 | // error if null | |
4239 | Error error (lexer.peek_token ()->get_locus (), | |
4240 | "could not parse type in tuple struct field"); | |
4241 | add_error (std::move (error)); | |
4242 | ||
4243 | // skip after something | |
4244 | return AST::TupleField::create_error (); | |
4245 | } | |
4246 | ||
4247 | return AST::TupleField (std::move (field_type), std::move (vis), locus, | |
4248 | std::move (outer_attrs)); | |
4249 | } | |
4250 | ||
4251 | // Parses a Rust "enum" tagged union item definition. | |
4252 | template <typename ManagedTokenSource> | |
4253 | std::unique_ptr<AST::Enum> | |
4254 | Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis, | |
4255 | AST::AttrVec outer_attrs) | |
4256 | { | |
4257 | Location locus = lexer.peek_token ()->get_locus (); | |
4258 | skip_token (ENUM_TOK); | |
4259 | ||
4260 | // parse enum name | |
4261 | const_TokenPtr enum_name_tok = expect_token (IDENTIFIER); | |
4262 | if (enum_name_tok == nullptr) | |
4263 | return nullptr; | |
4264 | ||
4265 | Identifier enum_name = enum_name_tok->get_str (); | |
4266 | ||
4267 | // parse generic params (of enum container, not enum variants) if they exist | |
4268 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
4269 | = parse_generic_params_in_angles (); | |
4270 | ||
4271 | // parse where clause if it exists | |
4272 | AST::WhereClause where_clause = parse_where_clause (); | |
4273 | ||
4274 | if (!skip_token (LEFT_CURLY)) | |
4275 | { | |
4276 | skip_after_end_block (); | |
4277 | return nullptr; | |
4278 | } | |
4279 | ||
4280 | // parse actual enum variant definitions | |
4281 | std::vector<std::unique_ptr<AST::EnumItem>> enum_items | |
4282 | = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; }); | |
4283 | ||
4284 | if (!skip_token (RIGHT_CURLY)) | |
4285 | { | |
4286 | skip_after_end_block (); | |
4287 | return nullptr; | |
4288 | } | |
4289 | ||
4290 | return std::unique_ptr<AST::Enum> ( | |
4291 | new AST::Enum (std::move (enum_name), std::move (vis), | |
4292 | std::move (generic_params), std::move (where_clause), | |
4293 | std::move (enum_items), std::move (outer_attrs), locus)); | |
4294 | } | |
4295 | ||
4296 | // Parses the enum variants inside an enum definiton. | |
4297 | template <typename ManagedTokenSource> | |
4298 | std::vector<std::unique_ptr<AST::EnumItem>> | |
4299 | Parser<ManagedTokenSource>::parse_enum_items () | |
4300 | { | |
4301 | std::vector<std::unique_ptr<AST::EnumItem>> items; | |
4302 | ||
4303 | std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item (); | |
4304 | ||
4305 | // Return empty item list if no field there | |
4306 | if (initial_item == nullptr) | |
4307 | return items; | |
4308 | ||
4309 | items.push_back (std::move (initial_item)); | |
4310 | ||
4311 | while (lexer.peek_token ()->get_id () == COMMA) | |
4312 | { | |
4313 | lexer.skip_token (); | |
4314 | ||
4315 | std::unique_ptr<AST::EnumItem> item = parse_enum_item (); | |
4316 | if (item == nullptr) | |
4317 | { | |
4318 | // this would occur with a trailing comma, which is allowed | |
4319 | break; | |
4320 | } | |
4321 | ||
4322 | items.push_back (std::move (item)); | |
4323 | } | |
4324 | ||
4325 | items.shrink_to_fit (); | |
4326 | return items; | |
4327 | ||
4328 | /* TODO: use template if doable (parse_non_ptr_sequence) */ | |
4329 | } | |
4330 | ||
4331 | // Parses the enum variants inside an enum definiton. | |
4332 | template <typename ManagedTokenSource> | |
4333 | template <typename EndTokenPred> | |
4334 | std::vector<std::unique_ptr<AST::EnumItem>> | |
4335 | Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok) | |
4336 | { | |
4337 | std::vector<std::unique_ptr<AST::EnumItem>> items; | |
4338 | ||
4339 | std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item (); | |
4340 | ||
4341 | // Return empty item list if no field there | |
4342 | if (initial_item == nullptr) | |
4343 | return items; | |
4344 | ||
4345 | items.push_back (std::move (initial_item)); | |
4346 | ||
4347 | while (lexer.peek_token ()->get_id () == COMMA) | |
4348 | { | |
4349 | lexer.skip_token (); | |
4350 | ||
4351 | if (is_end_tok (lexer.peek_token ()->get_id ())) | |
4352 | break; | |
4353 | ||
4354 | std::unique_ptr<AST::EnumItem> item = parse_enum_item (); | |
4355 | if (item == nullptr) | |
4356 | { | |
4357 | /* TODO should this ignore all successfully parsed enum items just | |
4358 | * because one failed? */ | |
4359 | Error error (lexer.peek_token ()->get_locus (), | |
4360 | "failed to parse enum item in enum items"); | |
4361 | add_error (std::move (error)); | |
4362 | ||
4363 | return {}; | |
4364 | } | |
4365 | ||
4366 | items.push_back (std::move (item)); | |
4367 | } | |
4368 | ||
4369 | items.shrink_to_fit (); | |
4370 | return items; | |
4371 | ||
4372 | /* TODO: use template if doable (parse_non_ptr_sequence) */ | |
4373 | } | |
4374 | ||
4375 | /* Parses a single enum variant item in an enum definition. Does not parse | |
4376 | * commas. */ | |
4377 | template <typename ManagedTokenSource> | |
4378 | std::unique_ptr<AST::EnumItem> | |
4379 | Parser<ManagedTokenSource>::parse_enum_item () | |
4380 | { | |
4381 | // parse outer attributes if they exist | |
4382 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
4383 | ||
4384 | // parse visibility, which may or may not exist | |
4385 | AST::Visibility vis = parse_visibility (); | |
4386 | ||
4387 | // parse name for enum item, which is required | |
4388 | const_TokenPtr item_name_tok = lexer.peek_token (); | |
4389 | if (item_name_tok->get_id () != IDENTIFIER) | |
4390 | { | |
4391 | // this may not be an error but it means there is no enum item here | |
4392 | return nullptr; | |
4393 | } | |
4394 | lexer.skip_token (); | |
4395 | Identifier item_name = item_name_tok->get_str (); | |
4396 | ||
4397 | // branch based on next token | |
4398 | const_TokenPtr t = lexer.peek_token (); | |
4399 | switch (t->get_id ()) | |
4400 | { | |
4401 | case LEFT_PAREN: { | |
4402 | // tuple enum item | |
4403 | lexer.skip_token (); | |
4404 | ||
4405 | std::vector<AST::TupleField> tuple_fields; | |
4406 | // Might be empty tuple for unit tuple enum variant. | |
4407 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
4408 | tuple_fields = std::vector<AST::TupleField> (); | |
4409 | else | |
4410 | tuple_fields = parse_tuple_fields (); | |
4411 | ||
4412 | if (!skip_token (RIGHT_PAREN)) | |
4413 | { | |
4414 | // skip after somewhere | |
4415 | return nullptr; | |
4416 | } | |
4417 | ||
4418 | return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple ( | |
4419 | std::move (item_name), std::move (vis), std::move (tuple_fields), | |
4420 | std::move (outer_attrs), item_name_tok->get_locus ())); | |
4421 | } | |
4422 | case LEFT_CURLY: { | |
4423 | // struct enum item | |
4424 | lexer.skip_token (); | |
4425 | ||
4426 | std::vector<AST::StructField> struct_fields | |
4427 | = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; }); | |
4428 | ||
4429 | if (!skip_token (RIGHT_CURLY)) | |
4430 | { | |
4431 | // skip after somewhere | |
4432 | return nullptr; | |
4433 | } | |
4434 | ||
4435 | return std::unique_ptr<AST::EnumItemStruct> (new AST::EnumItemStruct ( | |
4436 | std::move (item_name), std::move (vis), std::move (struct_fields), | |
4437 | std::move (outer_attrs), item_name_tok->get_locus ())); | |
4438 | } | |
4439 | case EQUAL: { | |
4440 | // discriminant enum item | |
4441 | lexer.skip_token (); | |
4442 | ||
4443 | std::unique_ptr<AST::Expr> discriminant_expr = parse_expr (); | |
4444 | ||
4445 | return std::unique_ptr<AST::EnumItemDiscriminant> ( | |
4446 | new AST::EnumItemDiscriminant (std::move (item_name), std::move (vis), | |
4447 | std::move (discriminant_expr), | |
4448 | std::move (outer_attrs), | |
4449 | item_name_tok->get_locus ())); | |
4450 | } | |
4451 | default: | |
4452 | // regular enum with just an identifier | |
4453 | return std::unique_ptr<AST::EnumItem> ( | |
4454 | new AST::EnumItem (std::move (item_name), std::move (vis), | |
4455 | std::move (outer_attrs), | |
4456 | item_name_tok->get_locus ())); | |
4457 | } | |
4458 | } | |
4459 | ||
4460 | // Parses a C-style (and C-compat) untagged union declaration. | |
4461 | template <typename ManagedTokenSource> | |
4462 | std::unique_ptr<AST::Union> | |
4463 | Parser<ManagedTokenSource>::parse_union (AST::Visibility vis, | |
4464 | AST::AttrVec outer_attrs) | |
4465 | { | |
4466 | /* hack - "weak keyword" by finding identifier called "union" (lookahead in | |
4467 | * item switch) */ | |
4468 | const_TokenPtr union_keyword = expect_token (IDENTIFIER); | |
4469 | rust_assert (union_keyword->get_str () == "union"); | |
4470 | Location locus = union_keyword->get_locus (); | |
4471 | ||
4472 | // parse actual union name | |
4473 | const_TokenPtr union_name_tok = expect_token (IDENTIFIER); | |
4474 | if (union_name_tok == nullptr) | |
4475 | { | |
4476 | skip_after_next_block (); | |
4477 | return nullptr; | |
4478 | } | |
4479 | Identifier union_name = union_name_tok->get_str (); | |
4480 | ||
4481 | // parse optional generic parameters | |
4482 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
4483 | = parse_generic_params_in_angles (); | |
4484 | ||
4485 | // parse optional where clause | |
4486 | AST::WhereClause where_clause = parse_where_clause (); | |
4487 | ||
4488 | if (!skip_token (LEFT_CURLY)) | |
4489 | { | |
4490 | skip_after_end_block (); | |
4491 | return nullptr; | |
4492 | } | |
4493 | ||
4494 | /* parse union inner items as "struct fields" because hey, syntax reuse. | |
4495 | * Spec said so. */ | |
4496 | std::vector<AST::StructField> union_fields | |
4497 | = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; }); | |
4498 | ||
4499 | if (!skip_token (RIGHT_CURLY)) | |
4500 | { | |
4501 | // skip after somewhere | |
4502 | return nullptr; | |
4503 | } | |
4504 | ||
4505 | return std::unique_ptr<AST::Union> ( | |
4506 | new AST::Union (std::move (union_name), std::move (vis), | |
4507 | std::move (generic_params), std::move (where_clause), | |
4508 | std::move (union_fields), std::move (outer_attrs), locus)); | |
4509 | } | |
4510 | ||
4511 | /* Parses a "constant item" (compile-time constant to maybe "inline" | |
4512 | * throughout the program - like constexpr). */ | |
4513 | template <typename ManagedTokenSource> | |
4514 | std::unique_ptr<AST::ConstantItem> | |
4515 | Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis, | |
4516 | AST::AttrVec outer_attrs) | |
4517 | { | |
4518 | Location locus = lexer.peek_token ()->get_locus (); | |
4519 | skip_token (CONST); | |
4520 | ||
4521 | /* get constant identifier - this is either a proper identifier or the _ | |
4522 | * wildcard */ | |
4523 | const_TokenPtr ident_tok = lexer.peek_token (); | |
4524 | // make default identifier the underscore wildcard one | |
4525 | std::string ident ("_"); | |
4526 | switch (ident_tok->get_id ()) | |
4527 | { | |
4528 | case IDENTIFIER: | |
4529 | ident = ident_tok->get_str (); | |
4530 | lexer.skip_token (); | |
4531 | break; | |
4532 | case UNDERSCORE: | |
4533 | // do nothing - identifier is already "_" | |
4534 | lexer.skip_token (); | |
4535 | break; | |
4536 | default: | |
4537 | add_error ( | |
4538 | Error (ident_tok->get_locus (), | |
4539 | "expected item name (identifier or %<_%>) in constant item " | |
4540 | "declaration - found %qs", | |
4541 | ident_tok->get_token_description ())); | |
4542 | ||
4543 | skip_after_semicolon (); | |
4544 | return nullptr; | |
4545 | } | |
4546 | ||
4547 | if (!skip_token (COLON)) | |
4548 | { | |
4549 | skip_after_semicolon (); | |
4550 | return nullptr; | |
4551 | } | |
4552 | ||
4553 | // parse constant type (required) | |
4554 | std::unique_ptr<AST::Type> type = parse_type (); | |
4555 | ||
4556 | if (!skip_token (EQUAL)) | |
4557 | { | |
4558 | skip_after_semicolon (); | |
4559 | return nullptr; | |
4560 | } | |
4561 | ||
4562 | // parse constant expression (required) | |
4563 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
4564 | ||
4565 | if (!skip_token (SEMICOLON)) | |
4566 | { | |
4567 | // skip somewhere? | |
4568 | return nullptr; | |
4569 | } | |
4570 | ||
4571 | return std::unique_ptr<AST::ConstantItem> ( | |
4572 | new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type), | |
4573 | std::move (expr), std::move (outer_attrs), locus)); | |
4574 | } | |
4575 | ||
4576 | // Parses a "static item" (static storage item, with 'static lifetime). | |
4577 | template <typename ManagedTokenSource> | |
4578 | std::unique_ptr<AST::StaticItem> | |
4579 | Parser<ManagedTokenSource>::parse_static_item (AST::Visibility vis, | |
4580 | AST::AttrVec outer_attrs) | |
4581 | { | |
4582 | Location locus = lexer.peek_token ()->get_locus (); | |
4583 | skip_token (STATIC_TOK); | |
4584 | ||
4585 | // determine whether static item is mutable | |
4586 | bool is_mut = false; | |
4587 | if (lexer.peek_token ()->get_id () == MUT) | |
4588 | { | |
4589 | is_mut = true; | |
4590 | lexer.skip_token (); | |
4591 | } | |
4592 | ||
4593 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
4594 | if (ident_tok == nullptr) | |
4595 | return nullptr; | |
4596 | ||
4597 | Identifier ident = ident_tok->get_str (); | |
4598 | ||
4599 | if (!skip_token (COLON)) | |
4600 | { | |
4601 | skip_after_semicolon (); | |
4602 | return nullptr; | |
4603 | } | |
4604 | ||
4605 | // parse static item type (required) | |
4606 | std::unique_ptr<AST::Type> type = parse_type (); | |
4607 | ||
4608 | if (!skip_token (EQUAL)) | |
4609 | { | |
4610 | skip_after_semicolon (); | |
4611 | return nullptr; | |
4612 | } | |
4613 | ||
4614 | // parse static item expression (required) | |
4615 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
4616 | ||
4617 | if (!skip_token (SEMICOLON)) | |
4618 | { | |
4619 | // skip after somewhere | |
4620 | return nullptr; | |
4621 | } | |
4622 | ||
4623 | return std::unique_ptr<AST::StaticItem> ( | |
4624 | new AST::StaticItem (std::move (ident), is_mut, std::move (type), | |
4625 | std::move (expr), std::move (vis), | |
4626 | std::move (outer_attrs), locus)); | |
4627 | } | |
4628 | ||
4629 | // Parses a trait definition item, including unsafe ones. | |
4630 | template <typename ManagedTokenSource> | |
4631 | std::unique_ptr<AST::Trait> | |
4632 | Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis, | |
4633 | AST::AttrVec outer_attrs) | |
4634 | { | |
4635 | Location locus = lexer.peek_token ()->get_locus (); | |
4636 | bool is_unsafe = false; | |
4637 | if (lexer.peek_token ()->get_id () == UNSAFE) | |
4638 | { | |
4639 | is_unsafe = true; | |
4640 | lexer.skip_token (); | |
4641 | } | |
4642 | ||
4643 | skip_token (TRAIT); | |
4644 | ||
4645 | // parse trait name | |
4646 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
4647 | if (ident_tok == nullptr) | |
4648 | return nullptr; | |
4649 | ||
4650 | Identifier ident = ident_tok->get_str (); | |
4651 | ||
4652 | // parse generic parameters (if they exist) | |
4653 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
4654 | = parse_generic_params_in_angles (); | |
4655 | ||
4656 | // create placeholder type param bounds in case they don't exist | |
4657 | std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds; | |
4658 | ||
4659 | // parse type param bounds (if they exist) | |
4660 | if (lexer.peek_token ()->get_id () == COLON) | |
4661 | { | |
4662 | lexer.skip_token (); | |
4663 | ||
4664 | type_param_bounds = parse_type_param_bounds ( | |
4665 | [] (TokenId id) { return id == WHERE || id == LEFT_CURLY; }); | |
4666 | // type_param_bounds = parse_type_param_bounds (); | |
4667 | } | |
4668 | ||
4669 | // parse where clause (if it exists) | |
4670 | AST::WhereClause where_clause = parse_where_clause (); | |
4671 | ||
4672 | if (!skip_token (LEFT_CURLY)) | |
4673 | { | |
4674 | skip_after_end_block (); | |
4675 | return nullptr; | |
4676 | } | |
4677 | ||
4678 | // parse inner attrs (if they exist) | |
4679 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
4680 | ||
4681 | // parse trait items | |
4682 | std::vector<std::unique_ptr<AST::TraitItem>> trait_items; | |
4683 | ||
4684 | const_TokenPtr t = lexer.peek_token (); | |
4685 | while (t->get_id () != RIGHT_CURLY) | |
4686 | { | |
4687 | std::unique_ptr<AST::TraitItem> trait_item = parse_trait_item (); | |
4688 | ||
4689 | if (trait_item == nullptr) | |
4690 | { | |
4691 | Error error (lexer.peek_token ()->get_locus (), | |
4692 | "failed to parse trait item in trait"); | |
4693 | add_error (std::move (error)); | |
4694 | ||
4695 | return nullptr; | |
4696 | } | |
4697 | trait_items.push_back (std::move (trait_item)); | |
4698 | ||
4699 | t = lexer.peek_token (); | |
4700 | } | |
4701 | ||
4702 | if (!skip_token (RIGHT_CURLY)) | |
4703 | { | |
4704 | // skip after something | |
4705 | return nullptr; | |
4706 | } | |
4707 | ||
4708 | trait_items.shrink_to_fit (); | |
4709 | return std::unique_ptr<AST::Trait> ( | |
4710 | new AST::Trait (std::move (ident), is_unsafe, std::move (generic_params), | |
4711 | std::move (type_param_bounds), std::move (where_clause), | |
4712 | std::move (trait_items), std::move (vis), | |
4713 | std::move (outer_attrs), std::move (inner_attrs), locus)); | |
4714 | } | |
4715 | ||
4716 | // Parses a trait item used inside traits (not trait, the Item). | |
4717 | template <typename ManagedTokenSource> | |
4718 | std::unique_ptr<AST::TraitItem> | |
4719 | Parser<ManagedTokenSource>::parse_trait_item () | |
4720 | { | |
4721 | // parse outer attributes (if they exist) | |
4722 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
4723 | ||
4724 | // lookahead to determine what type of trait item to parse | |
4725 | const_TokenPtr tok = lexer.peek_token (); | |
4726 | switch (tok->get_id ()) | |
4727 | { | |
4728 | case TYPE: | |
4729 | return parse_trait_type (std::move (outer_attrs)); | |
4730 | case CONST: | |
4731 | // disambiguate with function qualifier | |
4732 | if (lexer.peek_token (1)->get_id () == IDENTIFIER) | |
4733 | { | |
4734 | return parse_trait_const (std::move (outer_attrs)); | |
4735 | } | |
4736 | // else, fallthrough to function | |
4737 | // TODO: find out how to disable gcc "implicit fallthrough" error | |
4738 | gcc_fallthrough (); | |
4739 | case UNSAFE: | |
4740 | case EXTERN_TOK: | |
4741 | case FN_TOK: { | |
4742 | /* function and method can't be disambiguated by lookahead alone | |
4743 | * (without a lot of work and waste), so either make a | |
4744 | * "parse_trait_function_or_method" or parse here mostly and pass in | |
4745 | * most parameters (or if short enough, parse whole thing here). */ | |
4746 | // parse function and method here | |
4747 | ||
4748 | // parse function or method qualifiers | |
4749 | AST::FunctionQualifiers qualifiers = parse_function_qualifiers (); | |
4750 | ||
4751 | skip_token (FN_TOK); | |
4752 | ||
4753 | // parse function or method name | |
4754 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
4755 | if (ident_tok == nullptr) | |
4756 | return nullptr; | |
4757 | ||
4758 | Identifier ident = ident_tok->get_str (); | |
4759 | ||
4760 | // parse generic params | |
4761 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
4762 | = parse_generic_params_in_angles (); | |
4763 | ||
4764 | if (!skip_token (LEFT_PAREN)) | |
4765 | { | |
4766 | // skip after somewhere? | |
4767 | return nullptr; | |
4768 | } | |
4769 | ||
4770 | /* now for function vs method disambiguation - method has opening | |
4771 | * "self" param */ | |
4772 | AST::SelfParam self_param = parse_self_param (); | |
4773 | /* FIXME: ensure that self param doesn't accidently consume tokens for | |
4774 | * a function */ | |
4775 | bool is_method = false; | |
4776 | if (!self_param.is_error ()) | |
4777 | { | |
4778 | is_method = true; | |
4779 | ||
4780 | /* skip comma so function and method regular params can be parsed | |
4781 | * in same way */ | |
4782 | if (lexer.peek_token ()->get_id () == COMMA) | |
4783 | lexer.skip_token (); | |
4784 | } | |
4785 | ||
4786 | // parse trait function params | |
4787 | std::vector<AST::FunctionParam> function_params | |
4788 | = parse_function_params ( | |
4789 | [] (TokenId id) { return id == RIGHT_PAREN; }); | |
4790 | ||
4791 | if (!skip_token (RIGHT_PAREN)) | |
4792 | { | |
4793 | // skip after somewhere? | |
4794 | return nullptr; | |
4795 | } | |
4796 | ||
4797 | // parse return type (optional) | |
4798 | std::unique_ptr<AST::Type> return_type = parse_function_return_type (); | |
4799 | ||
4800 | // parse where clause (optional) | |
4801 | AST::WhereClause where_clause = parse_where_clause (); | |
4802 | ||
4803 | // parse semicolon or function definition (in block) | |
4804 | const_TokenPtr t = lexer.peek_token (); | |
4805 | std::unique_ptr<AST::BlockExpr> definition = nullptr; | |
4806 | switch (t->get_id ()) | |
4807 | { | |
4808 | case SEMICOLON: | |
4809 | lexer.skip_token (); | |
4810 | // definition is already nullptr, so don't need to change it | |
4811 | break; | |
4812 | case LEFT_CURLY: | |
4813 | definition = parse_block_expr (); | |
4814 | /* FIXME: are these outer attributes meant to be passed into the | |
4815 | * block? */ | |
4816 | break; | |
4817 | default: | |
4818 | add_error ( | |
4819 | Error (t->get_locus (), | |
4820 | "expected %<;%> or definiton at the end of trait %s " | |
4821 | "definition - found %qs instead", | |
4822 | is_method ? "method" : "function", | |
4823 | t->get_token_description ())); | |
4824 | ||
4825 | // skip? | |
4826 | return nullptr; | |
4827 | } | |
4828 | ||
4829 | // do actual if instead of ternary for return value optimisation | |
4830 | if (is_method) | |
4831 | { | |
4832 | AST::TraitMethodDecl method_decl (std::move (ident), | |
4833 | std::move (qualifiers), | |
4834 | std::move (generic_params), | |
4835 | std::move (self_param), | |
4836 | std::move (function_params), | |
4837 | std::move (return_type), | |
4838 | std::move (where_clause)); | |
4839 | ||
4840 | // TODO: does this (method_decl) need move? | |
4841 | return std::unique_ptr<AST::TraitItemMethod> ( | |
4842 | new AST::TraitItemMethod (std::move (method_decl), | |
4843 | std::move (definition), | |
4844 | std::move (outer_attrs), | |
4845 | tok->get_locus ())); | |
4846 | } | |
4847 | else | |
4848 | { | |
4849 | AST::TraitFunctionDecl function_decl (std::move (ident), | |
4850 | std::move (qualifiers), | |
4851 | std::move (generic_params), | |
4852 | std::move (function_params), | |
4853 | std::move (return_type), | |
4854 | std::move (where_clause)); | |
4855 | ||
4856 | return std::unique_ptr<AST::TraitItemFunc> (new AST::TraitItemFunc ( | |
4857 | std::move (function_decl), std::move (definition), | |
4858 | std::move (outer_attrs), tok->get_locus ())); | |
4859 | } | |
4860 | } | |
4861 | default: { | |
4862 | // TODO: try and parse macro invocation semi - if fails, maybe error. | |
4863 | std::unique_ptr<AST::TraitItem> macro_invoc | |
4864 | = parse_macro_invocation_semi (outer_attrs); | |
4865 | ||
4866 | if (macro_invoc == nullptr) | |
4867 | { | |
4868 | // TODO: error? | |
4869 | return nullptr; | |
4870 | } | |
4871 | else | |
4872 | { | |
4873 | return macro_invoc; | |
4874 | } | |
4875 | /* FIXME: macro invocations can only start with certain tokens. be | |
4876 | * more picky with these? */ | |
4877 | } | |
4878 | } | |
4879 | } | |
4880 | ||
4881 | // Parse a typedef trait item. | |
4882 | template <typename ManagedTokenSource> | |
4883 | std::unique_ptr<AST::TraitItemType> | |
4884 | Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs) | |
4885 | { | |
4886 | Location locus = lexer.peek_token ()->get_locus (); | |
4887 | skip_token (TYPE); | |
4888 | ||
4889 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
4890 | if (ident_tok == nullptr) | |
4891 | return nullptr; | |
4892 | ||
4893 | Identifier ident = ident_tok->get_str (); | |
4894 | ||
4895 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; | |
4896 | ||
4897 | // parse optional colon | |
4898 | if (lexer.peek_token ()->get_id () == COLON) | |
4899 | { | |
4900 | lexer.skip_token (); | |
4901 | ||
4902 | // parse optional type param bounds | |
4903 | bounds | |
4904 | = parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; }); | |
4905 | // bounds = parse_type_param_bounds (); | |
4906 | } | |
4907 | ||
4908 | if (!skip_token (SEMICOLON)) | |
4909 | { | |
4910 | // skip? | |
4911 | return nullptr; | |
4912 | } | |
4913 | ||
4914 | return std::unique_ptr<AST::TraitItemType> ( | |
4915 | new AST::TraitItemType (std::move (ident), std::move (bounds), | |
4916 | std::move (outer_attrs), locus)); | |
4917 | } | |
4918 | ||
4919 | // Parses a constant trait item. | |
4920 | template <typename ManagedTokenSource> | |
4921 | std::unique_ptr<AST::TraitItemConst> | |
4922 | Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs) | |
4923 | { | |
4924 | Location locus = lexer.peek_token ()->get_locus (); | |
4925 | skip_token (CONST); | |
4926 | ||
4927 | // parse constant item name | |
4928 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
4929 | if (ident_tok == nullptr) | |
4930 | return nullptr; | |
4931 | ||
4932 | Identifier ident = ident_tok->get_str (); | |
4933 | ||
4934 | if (!skip_token (COLON)) | |
4935 | { | |
4936 | skip_after_semicolon (); | |
4937 | return nullptr; | |
4938 | } | |
4939 | ||
4940 | // parse constant trait item type | |
4941 | std::unique_ptr<AST::Type> type = parse_type (); | |
4942 | ||
4943 | // parse constant trait body expression, if it exists | |
4944 | std::unique_ptr<AST::Expr> const_body = nullptr; | |
4945 | if (lexer.peek_token ()->get_id () == EQUAL) | |
4946 | { | |
4947 | lexer.skip_token (); | |
4948 | ||
4949 | // expression must exist, so parse it | |
4950 | const_body = parse_expr (); | |
4951 | } | |
4952 | ||
4953 | if (!skip_token (SEMICOLON)) | |
4954 | { | |
4955 | // skip after something? | |
4956 | return nullptr; | |
4957 | } | |
4958 | ||
4959 | return std::unique_ptr<AST::TraitItemConst> ( | |
4960 | new AST::TraitItemConst (std::move (ident), std::move (type), | |
4961 | std::move (const_body), std::move (outer_attrs), | |
4962 | locus)); | |
4963 | } | |
4964 | ||
4965 | /* Parses a struct "impl" item (both inherent impl and trait impl can be | |
4966 | * parsed here), */ | |
4967 | template <typename ManagedTokenSource> | |
4968 | std::unique_ptr<AST::Impl> | |
4969 | Parser<ManagedTokenSource>::parse_impl (AST::Visibility vis, | |
4970 | AST::AttrVec outer_attrs) | |
4971 | { | |
4972 | /* Note that only trait impls are allowed to be unsafe. So if unsafe, it | |
4973 | * must be a trait impl. However, this isn't enough for full disambiguation, | |
4974 | * so don't branch here. */ | |
4975 | Location locus = lexer.peek_token ()->get_locus (); | |
4976 | bool is_unsafe = false; | |
4977 | if (lexer.peek_token ()->get_id () == UNSAFE) | |
4978 | { | |
4979 | lexer.skip_token (); | |
4980 | is_unsafe = true; | |
4981 | } | |
4982 | ||
4983 | if (!skip_token (IMPL)) | |
4984 | { | |
4985 | skip_after_next_block (); | |
4986 | return nullptr; | |
4987 | } | |
4988 | ||
4989 | // parse generic params (shared by trait and inherent impls) | |
4990 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
4991 | = parse_generic_params_in_angles (); | |
4992 | ||
4993 | // Again, trait impl-only feature, but optional one, so can be used for | |
4994 | // branching yet. | |
4995 | bool has_exclam = false; | |
4996 | if (lexer.peek_token ()->get_id () == EXCLAM) | |
4997 | { | |
4998 | lexer.skip_token (); | |
4999 | has_exclam = true; | |
5000 | } | |
5001 | ||
5002 | /* FIXME: code that doesn't look shit for TypePath. Also, make sure this | |
5003 | * doesn't parse too much and not work. */ | |
5004 | AST::TypePath type_path = parse_type_path (); | |
5005 | if (type_path.is_error () || lexer.peek_token ()->get_id () != FOR) | |
5006 | { | |
5007 | /* cannot parse type path (or not for token next, at least), so must be | |
5008 | * inherent impl */ | |
5009 | ||
5010 | // hacky conversion of TypePath stack object to Type pointer | |
5011 | std::unique_ptr<AST::Type> type = nullptr; | |
5012 | if (!type_path.is_error ()) | |
5013 | type = std::unique_ptr<AST::TypePath> ( | |
5014 | new AST::TypePath (std::move (type_path))); | |
5015 | else | |
5016 | type = parse_type (); | |
5017 | ||
5018 | // Type is required, so error if null | |
5019 | if (type == nullptr) | |
5020 | { | |
5021 | Error error (lexer.peek_token ()->get_locus (), | |
5022 | "could not parse type in inherent impl"); | |
5023 | add_error (std::move (error)); | |
5024 | ||
5025 | skip_after_next_block (); | |
5026 | return nullptr; | |
5027 | } | |
5028 | ||
5029 | // parse optional where clause | |
5030 | AST::WhereClause where_clause = parse_where_clause (); | |
5031 | ||
5032 | if (!skip_token (LEFT_CURLY)) | |
5033 | { | |
5034 | // TODO: does this still skip properly? | |
5035 | skip_after_end_block (); | |
5036 | return nullptr; | |
5037 | } | |
5038 | ||
5039 | // parse inner attributes (optional) | |
5040 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
5041 | ||
5042 | // parse inherent impl items | |
5043 | std::vector<std::unique_ptr<AST::InherentImplItem>> impl_items; | |
5044 | ||
5045 | const_TokenPtr t = lexer.peek_token (); | |
5046 | while (t->get_id () != RIGHT_CURLY) | |
5047 | { | |
5048 | std::unique_ptr<AST::InherentImplItem> impl_item | |
5049 | = parse_inherent_impl_item (); | |
5050 | ||
5051 | if (impl_item == nullptr) | |
5052 | { | |
5053 | Error error ( | |
5054 | lexer.peek_token ()->get_locus (), | |
5055 | "failed to parse inherent impl item in inherent impl"); | |
5056 | add_error (std::move (error)); | |
5057 | ||
5058 | return nullptr; | |
5059 | } | |
5060 | ||
5061 | impl_items.push_back (std::move (impl_item)); | |
5062 | ||
5063 | t = lexer.peek_token (); | |
5064 | } | |
5065 | ||
5066 | if (!skip_token (RIGHT_CURLY)) | |
5067 | { | |
5068 | // skip somewhere | |
5069 | return nullptr; | |
5070 | } | |
5071 | ||
5072 | // DEBUG | |
5073 | rust_debug ("successfully parsed inherent impl"); | |
5074 | ||
5075 | impl_items.shrink_to_fit (); | |
5076 | ||
5077 | return std::unique_ptr<AST::InherentImpl> (new AST::InherentImpl ( | |
5078 | std::move (impl_items), std::move (generic_params), std::move (type), | |
5079 | std::move (where_clause), std::move (vis), std::move (inner_attrs), | |
5080 | std::move (outer_attrs), locus)); | |
5081 | } | |
5082 | else | |
5083 | { | |
5084 | // type path must both be valid and next token is for, so trait impl | |
5085 | if (!skip_token (FOR)) | |
5086 | { | |
5087 | skip_after_next_block (); | |
5088 | return nullptr; | |
5089 | } | |
5090 | ||
5091 | // parse type | |
5092 | std::unique_ptr<AST::Type> type = parse_type (); | |
5093 | // ensure type is included as it is required | |
5094 | if (type == nullptr) | |
5095 | { | |
5096 | Error error (lexer.peek_token ()->get_locus (), | |
5097 | "could not parse type in trait impl"); | |
5098 | add_error (std::move (error)); | |
5099 | ||
5100 | skip_after_next_block (); | |
5101 | return nullptr; | |
5102 | } | |
5103 | ||
5104 | // parse optional where clause | |
5105 | AST::WhereClause where_clause = parse_where_clause (); | |
5106 | ||
5107 | if (!skip_token (LEFT_CURLY)) | |
5108 | { | |
5109 | // TODO: does this still skip properly? | |
5110 | skip_after_end_block (); | |
5111 | return nullptr; | |
5112 | } | |
5113 | ||
5114 | // parse inner attributes (optional) | |
5115 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
5116 | ||
5117 | // parse trait impl items | |
5118 | std::vector<std::unique_ptr<AST::TraitImplItem>> impl_items; | |
5119 | ||
5120 | const_TokenPtr t = lexer.peek_token (); | |
5121 | while (t->get_id () != RIGHT_CURLY) | |
5122 | { | |
5123 | std::unique_ptr<AST::TraitImplItem> impl_item | |
5124 | = parse_trait_impl_item (); | |
5125 | ||
5126 | if (impl_item == nullptr) | |
5127 | { | |
5128 | Error error (lexer.peek_token ()->get_locus (), | |
5129 | "failed to parse trait impl item in trait impl"); | |
5130 | add_error (std::move (error)); | |
5131 | ||
5132 | return nullptr; | |
5133 | } | |
5134 | ||
5135 | impl_items.push_back (std::move (impl_item)); | |
5136 | ||
5137 | t = lexer.peek_token (); | |
5138 | ||
5139 | // DEBUG | |
5140 | rust_debug ("successfully parsed a trait impl item"); | |
5141 | } | |
5142 | // DEBUG | |
5143 | rust_debug ("successfully finished trait impl items"); | |
5144 | ||
5145 | if (!skip_token (RIGHT_CURLY)) | |
5146 | { | |
5147 | // skip somewhere | |
5148 | return nullptr; | |
5149 | } | |
5150 | ||
5151 | // DEBUG | |
5152 | rust_debug ("successfully parsed trait impl"); | |
5153 | ||
5154 | impl_items.shrink_to_fit (); | |
5155 | ||
5156 | return std::unique_ptr<AST::TraitImpl> ( | |
5157 | new AST::TraitImpl (std::move (type_path), is_unsafe, has_exclam, | |
5158 | std::move (impl_items), std::move (generic_params), | |
5159 | std::move (type), std::move (where_clause), | |
5160 | std::move (vis), std::move (inner_attrs), | |
5161 | std::move (outer_attrs), locus)); | |
5162 | } | |
5163 | } | |
5164 | ||
5165 | // Parses a single inherent impl item (item inside an inherent impl block). | |
5166 | template <typename ManagedTokenSource> | |
5167 | std::unique_ptr<AST::InherentImplItem> | |
5168 | Parser<ManagedTokenSource>::parse_inherent_impl_item () | |
5169 | { | |
5170 | // parse outer attributes (if they exist) | |
5171 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
5172 | ||
5173 | // TODO: cleanup - currently an unreadable mess | |
5174 | ||
5175 | // branch on next token: | |
5176 | const_TokenPtr t = lexer.peek_token (); | |
5177 | switch (t->get_id ()) | |
5178 | { | |
5179 | case IDENTIFIER: | |
5180 | // FIXME: Arthur: Do we need to some lookahead here? | |
5181 | return parse_macro_invocation_semi (outer_attrs); | |
5182 | case SUPER: | |
5183 | case SELF: | |
5184 | case CRATE: | |
5185 | case PUB: { | |
5186 | // visibility, so not a macro invocation semi - must be constant, | |
5187 | // function, or method | |
5188 | AST::Visibility vis = parse_visibility (); | |
5189 | ||
5190 | // TODO: is a recursive call to parse_inherent_impl_item better? | |
5191 | switch (lexer.peek_token ()->get_id ()) | |
5192 | { | |
5193 | case EXTERN_TOK: | |
5194 | case UNSAFE: | |
5195 | case FN_TOK: | |
5196 | // function or method | |
5197 | return parse_inherent_impl_function_or_method (std::move (vis), | |
5198 | std::move ( | |
5199 | outer_attrs)); | |
5200 | case CONST: | |
5201 | // lookahead to resolve production - could be function/method or | |
5202 | // const item | |
5203 | t = lexer.peek_token (1); | |
5204 | ||
5205 | switch (t->get_id ()) | |
5206 | { | |
5207 | case IDENTIFIER: | |
5208 | case UNDERSCORE: | |
5209 | return parse_const_item (std::move (vis), | |
5210 | std::move (outer_attrs)); | |
5211 | case UNSAFE: | |
5212 | case EXTERN_TOK: | |
5213 | case FN_TOK: | |
5214 | return parse_inherent_impl_function_or_method (std::move (vis), | |
5215 | std::move ( | |
5216 | outer_attrs)); | |
5217 | default: | |
5218 | add_error (Error (t->get_locus (), | |
5219 | "unexpected token %qs in some sort of const " | |
5220 | "item in inherent impl", | |
5221 | t->get_token_description ())); | |
5222 | ||
5223 | lexer.skip_token (1); // TODO: is this right thing to do? | |
5224 | return nullptr; | |
5225 | } | |
5226 | default: | |
5227 | add_error ( | |
5228 | Error (t->get_locus (), | |
5229 | "unrecognised token %qs for item in inherent impl", | |
5230 | t->get_token_description ())); | |
5231 | // skip? | |
5232 | return nullptr; | |
5233 | } | |
5234 | } | |
5235 | case EXTERN_TOK: | |
5236 | case UNSAFE: | |
5237 | case FN_TOK: | |
5238 | // function or method | |
5239 | return parse_inherent_impl_function_or_method ( | |
5240 | AST::Visibility::create_private (), std::move (outer_attrs)); | |
5241 | case CONST: | |
5242 | /* lookahead to resolve production - could be function/method or const | |
5243 | * item */ | |
5244 | t = lexer.peek_token (1); | |
5245 | ||
5246 | switch (t->get_id ()) | |
5247 | { | |
5248 | case IDENTIFIER: | |
5249 | case UNDERSCORE: | |
5250 | return parse_const_item (AST::Visibility::create_private (), | |
5251 | std::move (outer_attrs)); | |
5252 | case UNSAFE: | |
5253 | case EXTERN_TOK: | |
5254 | case FN_TOK: | |
5255 | return parse_inherent_impl_function_or_method ( | |
5256 | AST::Visibility::create_private (), std::move (outer_attrs)); | |
5257 | default: | |
5258 | add_error (Error (t->get_locus (), | |
5259 | "unexpected token %qs in some sort of const item " | |
5260 | "in inherent impl", | |
5261 | t->get_token_description ())); | |
5262 | ||
5263 | lexer.skip_token (1); // TODO: is this right thing to do? | |
5264 | return nullptr; | |
5265 | } | |
5266 | gcc_unreachable (); | |
5267 | default: | |
5268 | add_error (Error (t->get_locus (), | |
5269 | "unrecognised token %qs for item in inherent impl", | |
5270 | t->get_token_description ())); | |
5271 | ||
5272 | // skip? | |
5273 | return nullptr; | |
5274 | } | |
5275 | } | |
5276 | ||
5277 | /* For internal use only by parse_inherent_impl_item() - splits giant method | |
5278 | * into smaller ones and prevents duplication of logic. Strictly, this parses | |
5279 | * a function or method item inside an inherent impl item block. */ | |
5280 | // TODO: make this a templated function with "return type" as type param - | |
5281 | // InherentImplItem is this specialisation of the template while TraitImplItem | |
5282 | // will be the other. | |
5283 | template <typename ManagedTokenSource> | |
5284 | std::unique_ptr<AST::InherentImplItem> | |
5285 | Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method ( | |
5286 | AST::Visibility vis, AST::AttrVec outer_attrs) | |
5287 | { | |
5288 | Location locus = lexer.peek_token ()->get_locus (); | |
5289 | // parse function or method qualifiers | |
5290 | AST::FunctionQualifiers qualifiers = parse_function_qualifiers (); | |
5291 | ||
5292 | skip_token (FN_TOK); | |
5293 | ||
5294 | // parse function or method name | |
5295 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
5296 | if (ident_tok == nullptr) | |
5297 | return nullptr; | |
5298 | ||
5299 | Identifier ident = ident_tok->get_str (); | |
5300 | ||
5301 | // parse generic params | |
5302 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
5303 | = parse_generic_params_in_angles (); | |
5304 | ||
5305 | if (!skip_token (LEFT_PAREN)) | |
5306 | { | |
5307 | // skip after somewhere? | |
5308 | return nullptr; | |
5309 | } | |
5310 | ||
5311 | // now for function vs method disambiguation - method has opening "self" | |
5312 | // param | |
5313 | AST::SelfParam self_param = parse_self_param (); | |
5314 | /* FIXME: ensure that self param doesn't accidently consume tokens for a | |
5315 | * function one idea is to lookahead up to 4 tokens to see whether self is | |
5316 | * one of them */ | |
5317 | bool is_method = false; | |
5318 | if (!self_param.is_error ()) | |
5319 | { | |
5320 | is_method = true; | |
5321 | ||
5322 | /* skip comma so function and method regular params can be parsed in | |
5323 | * same way */ | |
5324 | if (lexer.peek_token ()->get_id () == COMMA) | |
5325 | lexer.skip_token (); | |
5326 | } | |
5327 | ||
5328 | // parse trait function params | |
5329 | std::vector<AST::FunctionParam> function_params | |
5330 | = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; }); | |
5331 | ||
5332 | if (!skip_token (RIGHT_PAREN)) | |
5333 | { | |
5334 | skip_after_end_block (); | |
5335 | return nullptr; | |
5336 | } | |
5337 | ||
5338 | // parse return type (optional) | |
5339 | std::unique_ptr<AST::Type> return_type = parse_function_return_type (); | |
5340 | ||
5341 | // parse where clause (optional) | |
5342 | AST::WhereClause where_clause = parse_where_clause (); | |
5343 | ||
5344 | // parse function definition (in block) - semicolon not allowed | |
5345 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
5346 | { | |
5347 | Error error (lexer.peek_token ()->get_locus (), | |
5348 | "%s declaration in inherent impl not allowed - must have " | |
5349 | "a definition", | |
5350 | is_method ? "method" : "function"); | |
5351 | add_error (std::move (error)); | |
5352 | ||
5353 | lexer.skip_token (); | |
5354 | return nullptr; | |
5355 | } | |
5356 | std::unique_ptr<AST::BlockExpr> body = parse_block_expr (); | |
5357 | if (body == nullptr) | |
5358 | { | |
5359 | Error error (lexer.peek_token ()->get_locus (), | |
5360 | "could not parse definition in inherent impl %s definition", | |
5361 | is_method ? "method" : "function"); | |
5362 | add_error (std::move (error)); | |
5363 | ||
5364 | skip_after_end_block (); | |
5365 | return nullptr; | |
5366 | } | |
5367 | ||
5368 | // do actual if instead of ternary for return value optimisation | |
5369 | if (is_method) | |
5370 | { | |
5371 | return std::unique_ptr<AST::Method> ( | |
5372 | new AST::Method (std::move (ident), std::move (qualifiers), | |
5373 | std::move (generic_params), std::move (self_param), | |
5374 | std::move (function_params), std::move (return_type), | |
5375 | std::move (where_clause), std::move (body), | |
5376 | std::move (vis), std::move (outer_attrs), locus)); | |
5377 | } | |
5378 | else | |
5379 | { | |
5380 | return std::unique_ptr<AST::Function> ( | |
5381 | new AST::Function (std::move (ident), std::move (qualifiers), | |
5382 | std::move (generic_params), | |
5383 | std::move (function_params), std::move (return_type), | |
5384 | std::move (where_clause), std::move (body), | |
5385 | std::move (vis), std::move (outer_attrs), locus)); | |
5386 | } | |
5387 | } | |
5388 | ||
5389 | // Parses a single trait impl item (item inside a trait impl block). | |
5390 | template <typename ManagedTokenSource> | |
5391 | std::unique_ptr<AST::TraitImplItem> | |
5392 | Parser<ManagedTokenSource>::parse_trait_impl_item () | |
5393 | { | |
5394 | // parse outer attributes (if they exist) | |
5395 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
5396 | ||
5397 | // TODO: clean this function up, it is basically unreadable hacks | |
5398 | ||
5399 | // branch on next token: | |
5400 | const_TokenPtr t = lexer.peek_token (); | |
5401 | switch (t->get_id ()) | |
5402 | { | |
5403 | case IDENTIFIER: | |
5404 | case SUPER: | |
5405 | case SELF: | |
5406 | case CRATE: | |
5407 | case DOLLAR_SIGN: | |
5408 | // these seem to be SimplePath tokens, so this is a macro invocation | |
5409 | // semi | |
5410 | return parse_macro_invocation_semi (std::move (outer_attrs)); | |
5411 | case TYPE: | |
5412 | return parse_type_alias (AST::Visibility::create_private (), | |
5413 | std::move (outer_attrs)); | |
5414 | case PUB: { | |
5415 | // visibility, so not a macro invocation semi - must be constant, | |
5416 | // function, or method | |
5417 | AST::Visibility vis = parse_visibility (); | |
5418 | ||
5419 | // TODO: is a recursive call to parse_trait_impl_item better? | |
5420 | switch (lexer.peek_token ()->get_id ()) | |
5421 | { | |
5422 | case TYPE: | |
5423 | return parse_type_alias (std::move (vis), std::move (outer_attrs)); | |
5424 | case EXTERN_TOK: | |
5425 | case UNSAFE: | |
5426 | case FN_TOK: | |
5427 | // function or method | |
5428 | return parse_trait_impl_function_or_method (std::move (vis), | |
5429 | std::move ( | |
5430 | outer_attrs)); | |
5431 | case CONST: | |
5432 | // lookahead to resolve production - could be function/method or | |
5433 | // const item | |
5434 | t = lexer.peek_token (1); | |
5435 | ||
5436 | switch (t->get_id ()) | |
5437 | { | |
5438 | case IDENTIFIER: | |
5439 | case UNDERSCORE: | |
5440 | return parse_const_item (std::move (vis), | |
5441 | std::move (outer_attrs)); | |
5442 | case UNSAFE: | |
5443 | case EXTERN_TOK: | |
5444 | case FN_TOK: | |
5445 | return parse_trait_impl_function_or_method (std::move (vis), | |
5446 | std::move ( | |
5447 | outer_attrs)); | |
5448 | default: | |
5449 | add_error (Error (t->get_locus (), | |
5450 | "unexpected token %qs in some sort of const " | |
5451 | "item in trait impl", | |
5452 | t->get_token_description ())); | |
5453 | ||
5454 | lexer.skip_token (1); // TODO: is this right thing to do? | |
5455 | return nullptr; | |
5456 | } | |
5457 | default: | |
5458 | add_error (Error (t->get_locus (), | |
5459 | "unrecognised token %qs for item in trait impl", | |
5460 | t->get_token_description ())); | |
5461 | ||
5462 | // skip? | |
5463 | return nullptr; | |
5464 | } | |
5465 | } | |
5466 | case EXTERN_TOK: | |
5467 | case UNSAFE: | |
5468 | case FN_TOK: | |
5469 | // function or method | |
5470 | return parse_trait_impl_function_or_method ( | |
5471 | AST::Visibility::create_private (), std::move (outer_attrs)); | |
5472 | case CONST: | |
5473 | // lookahead to resolve production - could be function/method or const | |
5474 | // item | |
5475 | t = lexer.peek_token (1); | |
5476 | ||
5477 | switch (t->get_id ()) | |
5478 | { | |
5479 | case IDENTIFIER: | |
5480 | case UNDERSCORE: | |
5481 | return parse_const_item (AST::Visibility::create_private (), | |
5482 | std::move (outer_attrs)); | |
5483 | case UNSAFE: | |
5484 | case EXTERN_TOK: | |
5485 | case FN_TOK: | |
5486 | return parse_trait_impl_function_or_method ( | |
5487 | AST::Visibility::create_private (), std::move (outer_attrs)); | |
5488 | default: | |
5489 | add_error (Error ( | |
5490 | t->get_locus (), | |
5491 | "unexpected token %qs in some sort of const item in trait impl", | |
5492 | t->get_token_description ())); | |
5493 | ||
5494 | lexer.skip_token (1); // TODO: is this right thing to do? | |
5495 | return nullptr; | |
5496 | } | |
5497 | gcc_unreachable (); | |
5498 | default: | |
5499 | add_error (Error (t->get_locus (), | |
5500 | "unrecognised token %qs for item in trait impl", | |
5501 | t->get_token_description ())); | |
5502 | ||
5503 | // skip? | |
5504 | return nullptr; | |
5505 | } | |
5506 | } | |
5507 | ||
5508 | /* For internal use only by parse_trait_impl_item() - splits giant method into | |
5509 | * smaller ones and prevents duplication of logic. Strictly, this parses a | |
5510 | * function or method item inside a trait impl item block. */ | |
5511 | template <typename ManagedTokenSource> | |
5512 | std::unique_ptr<AST::TraitImplItem> | |
5513 | Parser<ManagedTokenSource>::parse_trait_impl_function_or_method ( | |
5514 | AST::Visibility vis, AST::AttrVec outer_attrs) | |
5515 | { | |
5516 | // this shares virtually all logic with | |
5517 | // parse_inherent_impl_function_or_method | |
5518 | // - template? | |
5519 | Location locus = lexer.peek_token ()->get_locus (); | |
5520 | ||
5521 | // parse function or method qualifiers | |
5522 | AST::FunctionQualifiers qualifiers = parse_function_qualifiers (); | |
5523 | ||
5524 | skip_token (FN_TOK); | |
5525 | ||
5526 | // parse function or method name | |
5527 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
5528 | if (ident_tok == nullptr) | |
5529 | { | |
5530 | return nullptr; | |
5531 | } | |
5532 | Identifier ident = ident_tok->get_str (); | |
5533 | ||
5534 | // DEBUG: | |
5535 | rust_debug ( | |
5536 | "about to start parsing generic params in trait impl function or method"); | |
5537 | ||
5538 | // parse generic params | |
5539 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
5540 | = parse_generic_params_in_angles (); | |
5541 | ||
5542 | // DEBUG: | |
5543 | rust_debug ( | |
5544 | "finished parsing generic params in trait impl function or method"); | |
5545 | ||
5546 | if (!skip_token (LEFT_PAREN)) | |
5547 | { | |
5548 | // skip after somewhere? | |
5549 | return nullptr; | |
5550 | } | |
5551 | ||
5552 | // now for function vs method disambiguation - method has opening "self" | |
5553 | // param | |
5554 | AST::SelfParam self_param = parse_self_param (); | |
5555 | // FIXME: ensure that self param doesn't accidently consume tokens for a | |
5556 | // function | |
5557 | bool is_method = false; | |
5558 | if (!self_param.is_error ()) | |
5559 | { | |
5560 | is_method = true; | |
5561 | ||
5562 | // skip comma so function and method regular params can be parsed in | |
5563 | // same way | |
5564 | if (lexer.peek_token ()->get_id () == COMMA) | |
5565 | { | |
5566 | lexer.skip_token (); | |
5567 | } | |
5568 | ||
5569 | // DEBUG | |
5570 | rust_debug ("successfully parsed self param in method trait impl item"); | |
5571 | } | |
5572 | ||
5573 | // DEBUG | |
5574 | rust_debug ( | |
5575 | "started to parse function params in function or method trait impl item"); | |
5576 | ||
5577 | // parse trait function params (only if next token isn't right paren) | |
5578 | std::vector<AST::FunctionParam> function_params; | |
5579 | if (lexer.peek_token ()->get_id () != RIGHT_PAREN) | |
5580 | { | |
5581 | function_params | |
5582 | = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; }); | |
5583 | ||
5584 | if (function_params.empty ()) | |
5585 | { | |
5586 | Error error ( | |
5587 | lexer.peek_token ()->get_locus (), | |
5588 | "failed to parse function params in trait impl %s definition", | |
5589 | is_method ? "method" : "function"); | |
5590 | add_error (std::move (error)); | |
5591 | ||
5592 | skip_after_next_block (); | |
5593 | return nullptr; | |
5594 | } | |
5595 | } | |
5596 | ||
5597 | // DEBUG | |
5598 | rust_debug ("successfully parsed function params in function or method " | |
5599 | "trait impl item"); | |
5600 | ||
5601 | if (!skip_token (RIGHT_PAREN)) | |
5602 | { | |
5603 | skip_after_next_block (); | |
5604 | return nullptr; | |
5605 | } | |
5606 | ||
5607 | // parse return type (optional) | |
5608 | std::unique_ptr<AST::Type> return_type = parse_function_return_type (); | |
5609 | ||
5610 | // DEBUG | |
5611 | rust_debug ( | |
5612 | "successfully parsed return type in function or method trait impl item"); | |
5613 | ||
5614 | // parse where clause (optional) | |
5615 | AST::WhereClause where_clause = parse_where_clause (); | |
5616 | ||
5617 | // DEBUG | |
5618 | rust_debug ( | |
5619 | "successfully parsed where clause in function or method trait impl item"); | |
5620 | ||
5621 | // parse function definition (in block) - semicolon not allowed | |
5622 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
5623 | { | |
5624 | Error error ( | |
5625 | lexer.peek_token ()->get_locus (), | |
5626 | "%s declaration in trait impl not allowed - must have a definition", | |
5627 | is_method ? "method" : "function"); | |
5628 | add_error (std::move (error)); | |
5629 | ||
5630 | lexer.skip_token (); | |
5631 | return nullptr; | |
5632 | } | |
5633 | std::unique_ptr<AST::BlockExpr> body = parse_block_expr (); | |
5634 | if (body == nullptr) | |
5635 | { | |
5636 | Error error (lexer.peek_token ()->get_locus (), | |
5637 | "could not parse definition in trait impl %s definition", | |
5638 | is_method ? "method" : "function"); | |
5639 | add_error (std::move (error)); | |
5640 | ||
5641 | skip_after_end_block (); | |
5642 | return nullptr; | |
5643 | } | |
5644 | ||
5645 | // do actual if instead of ternary for return value optimisation | |
5646 | if (is_method) | |
5647 | { | |
5648 | return std::unique_ptr<AST::Method> ( | |
5649 | new AST::Method (std::move (ident), std::move (qualifiers), | |
5650 | std::move (generic_params), std::move (self_param), | |
5651 | std::move (function_params), std::move (return_type), | |
5652 | std::move (where_clause), std::move (body), | |
5653 | std::move (vis), std::move (outer_attrs), locus)); | |
5654 | } | |
5655 | else | |
5656 | { | |
5657 | return std::unique_ptr<AST::Function> ( | |
5658 | new AST::Function (std::move (ident), std::move (qualifiers), | |
5659 | std::move (generic_params), | |
5660 | std::move (function_params), std::move (return_type), | |
5661 | std::move (where_clause), std::move (body), | |
5662 | std::move (vis), std::move (outer_attrs), locus)); | |
5663 | } | |
5664 | } | |
5665 | ||
5666 | // Parses an extern block of declarations. | |
5667 | template <typename ManagedTokenSource> | |
5668 | std::unique_ptr<AST::ExternBlock> | |
5669 | Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis, | |
5670 | AST::AttrVec outer_attrs) | |
5671 | { | |
5672 | Location locus = lexer.peek_token ()->get_locus (); | |
5673 | skip_token (EXTERN_TOK); | |
5674 | ||
5675 | // detect optional abi name | |
5676 | std::string abi; | |
5677 | const_TokenPtr next_tok = lexer.peek_token (); | |
5678 | if (next_tok->get_id () == STRING_LITERAL) | |
5679 | { | |
5680 | lexer.skip_token (); | |
5681 | abi = next_tok->get_str (); | |
5682 | } | |
5683 | ||
5684 | if (!skip_token (LEFT_CURLY)) | |
5685 | { | |
5686 | skip_after_end_block (); | |
5687 | return nullptr; | |
5688 | } | |
5689 | ||
5690 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
5691 | ||
5692 | // parse declarations inside extern block | |
5693 | std::vector<std::unique_ptr<AST::ExternalItem>> extern_items; | |
5694 | ||
5695 | const_TokenPtr t = lexer.peek_token (); | |
5696 | while (t->get_id () != RIGHT_CURLY) | |
5697 | { | |
5698 | std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item (); | |
5699 | ||
5700 | if (extern_item == nullptr) | |
5701 | { | |
5702 | Error error (t->get_locus (), | |
5703 | "failed to parse external item despite not reaching " | |
5704 | "end of extern block"); | |
5705 | add_error (std::move (error)); | |
5706 | ||
5707 | return nullptr; | |
5708 | } | |
5709 | ||
5710 | extern_items.push_back (std::move (extern_item)); | |
5711 | ||
5712 | t = lexer.peek_token (); | |
5713 | } | |
5714 | ||
5715 | if (!skip_token (RIGHT_CURLY)) | |
5716 | { | |
5717 | // skip somewhere | |
5718 | return nullptr; | |
5719 | } | |
5720 | ||
5721 | extern_items.shrink_to_fit (); | |
5722 | ||
5723 | return std::unique_ptr<AST::ExternBlock> ( | |
5724 | new AST::ExternBlock (std::move (abi), std::move (extern_items), | |
5725 | std::move (vis), std::move (inner_attrs), | |
5726 | std::move (outer_attrs), locus)); | |
5727 | } | |
5728 | ||
5729 | // Parses a single extern block item (static or function declaration). | |
5730 | template <typename ManagedTokenSource> | |
5731 | std::unique_ptr<AST::ExternalItem> | |
5732 | Parser<ManagedTokenSource>::parse_external_item () | |
5733 | { | |
5734 | // parse optional outer attributes | |
5735 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
5736 | ||
5737 | Location locus = lexer.peek_token ()->get_locus (); | |
5738 | ||
5739 | // parse optional visibility | |
5740 | AST::Visibility vis = parse_visibility (); | |
5741 | ||
5742 | const_TokenPtr t = lexer.peek_token (); | |
5743 | switch (t->get_id ()) | |
5744 | { | |
5745 | case IDENTIFIER: | |
5746 | return parse_macro_invocation_semi (outer_attrs); | |
5747 | case STATIC_TOK: { | |
5748 | // parse extern static item | |
5749 | lexer.skip_token (); | |
5750 | ||
5751 | // parse mut (optional) | |
5752 | bool has_mut = false; | |
5753 | if (lexer.peek_token ()->get_id () == MUT) | |
5754 | { | |
5755 | lexer.skip_token (); | |
5756 | has_mut = true; | |
5757 | } | |
5758 | ||
5759 | // parse identifier | |
5760 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
5761 | if (ident_tok == nullptr) | |
5762 | { | |
5763 | skip_after_semicolon (); | |
5764 | return nullptr; | |
5765 | } | |
5766 | Identifier ident = ident_tok->get_str (); | |
5767 | ||
5768 | if (!skip_token (COLON)) | |
5769 | { | |
5770 | skip_after_semicolon (); | |
5771 | return nullptr; | |
5772 | } | |
5773 | ||
5774 | // parse type (required) | |
5775 | std::unique_ptr<AST::Type> type = parse_type (); | |
5776 | if (type == nullptr) | |
5777 | { | |
5778 | Error error (lexer.peek_token ()->get_locus (), | |
5779 | "failed to parse type in external static item"); | |
5780 | add_error (std::move (error)); | |
5781 | ||
5782 | skip_after_semicolon (); | |
5783 | return nullptr; | |
5784 | } | |
5785 | ||
5786 | if (!skip_token (SEMICOLON)) | |
5787 | { | |
5788 | // skip after somewhere? | |
5789 | return nullptr; | |
5790 | } | |
5791 | ||
5792 | return std::unique_ptr<AST::ExternalStaticItem> ( | |
5793 | new AST::ExternalStaticItem (std::move (ident), std::move (type), | |
5794 | has_mut, std::move (vis), | |
5795 | std::move (outer_attrs), locus)); | |
5796 | } | |
5797 | case FN_TOK: { | |
5798 | // parse extern function declaration item | |
5799 | // skip function token | |
5800 | lexer.skip_token (); | |
5801 | ||
5802 | // parse identifier | |
5803 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
5804 | if (ident_tok == nullptr) | |
5805 | { | |
5806 | skip_after_semicolon (); | |
5807 | return nullptr; | |
5808 | } | |
5809 | Identifier ident = ident_tok->get_str (); | |
5810 | ||
5811 | // parse (optional) generic params | |
5812 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
5813 | = parse_generic_params_in_angles (); | |
5814 | ||
5815 | if (!skip_token (LEFT_PAREN)) | |
5816 | { | |
5817 | skip_after_semicolon (); | |
5818 | return nullptr; | |
5819 | } | |
5820 | ||
5821 | // parse parameters | |
5822 | std::vector<AST::NamedFunctionParam> function_params; | |
5823 | bool is_variadic = false; | |
5824 | AST::AttrVec variadic_attrs; | |
5825 | ||
5826 | const_TokenPtr t = lexer.peek_token (); | |
5827 | while (t->get_id () != RIGHT_PAREN) | |
5828 | { | |
5829 | AST::AttrVec maybe_variadic_attrs = parse_outer_attributes (); | |
5830 | if (lexer.peek_token ()->get_id () == ELLIPSIS) | |
5831 | { | |
5832 | // variadic - use attrs for this | |
5833 | lexer.skip_token (); | |
5834 | is_variadic = true; | |
5835 | variadic_attrs = std::move (maybe_variadic_attrs); | |
5836 | t = lexer.peek_token (); | |
5837 | ||
5838 | if (t->get_id () != RIGHT_PAREN) | |
5839 | { | |
5840 | Error error (t->get_locus (), | |
5841 | "expected right parentheses after variadic in " | |
5842 | "named function " | |
5843 | "parameters, found %qs", | |
5844 | t->get_token_description ()); | |
5845 | add_error (std::move (error)); | |
5846 | ||
5847 | skip_after_semicolon (); | |
5848 | return nullptr; | |
5849 | } | |
5850 | ||
5851 | break; | |
5852 | } | |
5853 | ||
5854 | AST::NamedFunctionParam param | |
5855 | = parse_named_function_param (std::move (maybe_variadic_attrs)); | |
5856 | if (param.is_error ()) | |
5857 | { | |
5858 | Error error (t->get_locus (), "could not parse named function " | |
5859 | "parameter in external function"); | |
5860 | add_error (std::move (error)); | |
5861 | ||
5862 | skip_after_semicolon (); | |
5863 | return nullptr; | |
5864 | } | |
5865 | function_params.push_back (std::move (param)); | |
5866 | ||
5867 | if (lexer.peek_token ()->get_id () != COMMA) | |
5868 | break; | |
5869 | ||
5870 | // skip comma | |
5871 | lexer.skip_token (); | |
5872 | t = lexer.peek_token (); | |
5873 | } | |
5874 | ||
5875 | if (!skip_token (RIGHT_PAREN)) | |
5876 | { | |
5877 | skip_after_semicolon (); | |
5878 | return nullptr; | |
5879 | } | |
5880 | ||
5881 | // parse (optional) return type | |
5882 | std::unique_ptr<AST::Type> return_type = parse_function_return_type (); | |
5883 | ||
5884 | // parse (optional) where clause | |
5885 | AST::WhereClause where_clause = parse_where_clause (); | |
5886 | ||
5887 | if (!skip_token (SEMICOLON)) | |
5888 | { | |
5889 | // skip somewhere? | |
5890 | return nullptr; | |
5891 | } | |
5892 | ||
5893 | function_params.shrink_to_fit (); | |
5894 | ||
5895 | return std::unique_ptr<AST::ExternalFunctionItem> ( | |
5896 | new AST::ExternalFunctionItem ( | |
5897 | std::move (ident), std::move (generic_params), | |
5898 | std::move (return_type), std::move (where_clause), | |
5899 | std::move (function_params), is_variadic, | |
5900 | std::move (variadic_attrs), std::move (vis), | |
5901 | std::move (outer_attrs), locus)); | |
5902 | } | |
5903 | default: | |
5904 | // error | |
5905 | add_error ( | |
5906 | Error (t->get_locus (), | |
5907 | "unrecognised token %qs in extern block item declaration", | |
5908 | t->get_token_description ())); | |
5909 | ||
5910 | skip_after_semicolon (); | |
5911 | return nullptr; | |
5912 | } | |
5913 | } | |
5914 | ||
5915 | /* Parses an extern block function param (with "pattern" being _ or an | |
5916 | * identifier). */ | |
5917 | template <typename ManagedTokenSource> | |
5918 | AST::NamedFunctionParam | |
5919 | Parser<ManagedTokenSource>::parse_named_function_param ( | |
5920 | AST::AttrVec outer_attrs) | |
5921 | { | |
5922 | // parse identifier/_ | |
5923 | std::string name; | |
5924 | ||
5925 | const_TokenPtr t = lexer.peek_token (); | |
5926 | Location name_location = t->get_locus (); | |
5927 | switch (t->get_id ()) | |
5928 | { | |
5929 | case IDENTIFIER: | |
5930 | name = t->get_str (); | |
5931 | lexer.skip_token (); | |
5932 | break; | |
5933 | case UNDERSCORE: | |
5934 | name = "_"; | |
5935 | lexer.skip_token (); | |
5936 | break; | |
5937 | default: | |
5938 | // this is not a function param, but not necessarily an error | |
5939 | return AST::NamedFunctionParam::create_error (); | |
5940 | } | |
5941 | ||
5942 | if (!skip_token (COLON)) | |
5943 | { | |
5944 | // skip after somewhere? | |
5945 | return AST::NamedFunctionParam::create_error (); | |
5946 | } | |
5947 | ||
5948 | // parse (required) type | |
5949 | std::unique_ptr<AST::Type> param_type = parse_type (); | |
5950 | if (param_type == nullptr) | |
5951 | { | |
5952 | Error error ( | |
5953 | lexer.peek_token ()->get_locus (), | |
5954 | "could not parse param type in extern block function declaration"); | |
5955 | add_error (std::move (error)); | |
5956 | ||
5957 | skip_after_semicolon (); | |
5958 | return AST::NamedFunctionParam::create_error (); | |
5959 | } | |
5960 | ||
5961 | return AST::NamedFunctionParam (std::move (name), std::move (param_type), | |
5962 | std::move (outer_attrs), name_location); | |
5963 | } | |
5964 | ||
5965 | // Parses a statement (will further disambiguate any statement). | |
5966 | template <typename ManagedTokenSource> | |
5967 | std::unique_ptr<AST::Stmt> | |
5968 | Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions) | |
5969 | { | |
5970 | // quick exit for empty statement | |
5971 | // FIXME: Can we have empty statements without semicolons? Just nothing? | |
5972 | const_TokenPtr t = lexer.peek_token (); | |
5973 | if (t->get_id () == SEMICOLON) | |
5974 | { | |
5975 | lexer.skip_token (); | |
5976 | return std::unique_ptr<AST::EmptyStmt> ( | |
5977 | new AST::EmptyStmt (t->get_locus ())); | |
5978 | } | |
5979 | ||
5980 | // parse outer attributes | |
5981 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
5982 | ||
5983 | // parsing this will be annoying because of the many different possibilities | |
5984 | /* best may be just to copy paste in parse_item switch, and failing that try | |
5985 | * to parse outer attributes, and then pass them in to either a let | |
5986 | * statement or (fallback) expression statement. */ | |
5987 | // FIXME: think of a way to do this without such a large switch? | |
5988 | t = lexer.peek_token (); | |
5989 | switch (t->get_id ()) | |
5990 | { | |
5991 | case LET: | |
5992 | // let statement | |
5993 | return parse_let_stmt (std::move (outer_attrs), restrictions); | |
5994 | case PUB: | |
5995 | case MOD: | |
5996 | case EXTERN_TOK: | |
5997 | case USE: | |
5998 | case FN_TOK: | |
5999 | case TYPE: | |
6000 | case STRUCT_TOK: | |
6001 | case ENUM_TOK: | |
6002 | case CONST: | |
6003 | case STATIC_TOK: | |
6004 | case TRAIT: | |
6005 | case IMPL: | |
6006 | /* TODO: implement union keyword but not really because of | |
6007 | * context-dependence crappy hack way to parse a union written below to | |
6008 | * separate it from the good code. */ | |
6009 | // case UNION: | |
6010 | case UNSAFE: // maybe - unsafe traits are a thing | |
6011 | /* if any of these (should be all possible VisItem prefixes), parse a | |
6012 | * VisItem can't parse item because would require reparsing outer | |
6013 | * attributes */ | |
6014 | return parse_vis_item (std::move (outer_attrs)); | |
6015 | break; | |
6016 | case SUPER: | |
6017 | case SELF: | |
6018 | case CRATE: | |
6019 | case DOLLAR_SIGN: | |
6020 | // almost certainly macro invocation semi | |
6021 | return parse_macro_item (std::move (outer_attrs)); | |
6022 | break; | |
6023 | // crappy hack to do union "keyword" | |
6024 | case IDENTIFIER: | |
6025 | if (t->get_str () == "union" | |
6026 | && lexer.peek_token (1)->get_id () == IDENTIFIER) | |
6027 | { | |
6028 | return parse_vis_item (std::move (outer_attrs)); | |
6029 | // or should this go straight to parsing union? | |
6030 | } | |
6031 | else if (t->get_str () == "macro_rules") | |
6032 | { | |
6033 | // macro_rules! macro item | |
6034 | return parse_macro_item (std::move (outer_attrs)); | |
6035 | } | |
6036 | else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION | |
6037 | || lexer.peek_token (1)->get_id () == EXCLAM) | |
6038 | { | |
6039 | // FIXME: ensure doesn't take any expressions by mistake | |
6040 | /* path (probably) or macro invocation, so probably a macro | |
6041 | * invocation semi */ | |
6042 | return parse_macro_item (std::move (outer_attrs)); | |
6043 | } | |
6044 | gcc_fallthrough (); | |
6045 | // TODO: find out how to disable gcc "implicit fallthrough" warning | |
6046 | default: | |
6047 | // fallback: expression statement | |
6048 | return parse_expr_stmt (std::move (outer_attrs), restrictions); | |
6049 | break; | |
6050 | } | |
6051 | } | |
6052 | ||
6053 | // Parses a let statement. | |
6054 | template <typename ManagedTokenSource> | |
6055 | std::unique_ptr<AST::LetStmt> | |
6056 | Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs, | |
6057 | ParseRestrictions restrictions) | |
6058 | { | |
6059 | Location locus = lexer.peek_token ()->get_locus (); | |
6060 | skip_token (LET); | |
6061 | ||
6062 | // parse pattern (required) | |
6063 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
6064 | if (pattern == nullptr) | |
6065 | { | |
6066 | Error error (lexer.peek_token ()->get_locus (), | |
6067 | "failed to parse pattern in let statement"); | |
6068 | add_error (std::move (error)); | |
6069 | ||
6070 | skip_after_semicolon (); | |
6071 | return nullptr; | |
6072 | } | |
6073 | ||
6074 | // parse type declaration (optional) | |
6075 | std::unique_ptr<AST::Type> type = nullptr; | |
6076 | if (lexer.peek_token ()->get_id () == COLON) | |
6077 | { | |
6078 | // must have a type declaration | |
6079 | lexer.skip_token (); | |
6080 | ||
6081 | type = parse_type (); | |
6082 | if (type == nullptr) | |
6083 | { | |
6084 | Error error (lexer.peek_token ()->get_locus (), | |
6085 | "failed to parse type in let statement"); | |
6086 | add_error (std::move (error)); | |
6087 | ||
6088 | skip_after_semicolon (); | |
6089 | return nullptr; | |
6090 | } | |
6091 | } | |
6092 | ||
6093 | // parse expression to set variable to (optional) | |
6094 | std::unique_ptr<AST::Expr> expr = nullptr; | |
6095 | if (lexer.peek_token ()->get_id () == EQUAL) | |
6096 | { | |
6097 | // must have an expression | |
6098 | lexer.skip_token (); | |
6099 | ||
6100 | expr = parse_expr (); | |
6101 | if (expr == nullptr) | |
6102 | { | |
6103 | Error error (lexer.peek_token ()->get_locus (), | |
6104 | "failed to parse expression in let statement"); | |
6105 | add_error (std::move (error)); | |
6106 | ||
6107 | skip_after_semicolon (); | |
6108 | return nullptr; | |
6109 | } | |
6110 | } | |
6111 | ||
6112 | if (restrictions.consume_semi) | |
6113 | if (!skip_token (SEMICOLON)) | |
6114 | return nullptr; | |
6115 | ||
6116 | return std::unique_ptr<AST::LetStmt> ( | |
6117 | new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type), | |
6118 | std::move (outer_attrs), locus)); | |
6119 | } | |
6120 | ||
6121 | // Parses a type path. | |
6122 | template <typename ManagedTokenSource> | |
6123 | AST::TypePath | |
6124 | Parser<ManagedTokenSource>::parse_type_path () | |
6125 | { | |
6126 | bool has_opening_scope_resolution = false; | |
6127 | Location locus = lexer.peek_token ()->get_locus (); | |
6128 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION) | |
6129 | { | |
6130 | has_opening_scope_resolution = true; | |
6131 | lexer.skip_token (); | |
6132 | } | |
6133 | ||
6134 | // create segment vector | |
6135 | std::vector<std::unique_ptr<AST::TypePathSegment>> segments; | |
6136 | ||
6137 | // parse required initial segment | |
6138 | std::unique_ptr<AST::TypePathSegment> initial_segment | |
6139 | = parse_type_path_segment (); | |
6140 | if (initial_segment == nullptr) | |
6141 | { | |
6142 | // skip after somewhere? | |
6143 | // don't necessarily throw error but yeah | |
6144 | return AST::TypePath::create_error (); | |
6145 | } | |
6146 | segments.push_back (std::move (initial_segment)); | |
6147 | ||
6148 | // parse optional segments (as long as scope resolution operator exists) | |
6149 | const_TokenPtr t = lexer.peek_token (); | |
6150 | while (t->get_id () == SCOPE_RESOLUTION) | |
6151 | { | |
6152 | // skip scope resolution operator | |
6153 | lexer.skip_token (); | |
6154 | ||
6155 | // parse the actual segment - it is an error if it doesn't exist now | |
6156 | std::unique_ptr<AST::TypePathSegment> segment | |
6157 | = parse_type_path_segment (); | |
6158 | if (segment == nullptr) | |
6159 | { | |
6160 | // skip after somewhere? | |
6161 | Error error (t->get_locus (), "could not parse type path segment"); | |
6162 | add_error (std::move (error)); | |
6163 | ||
6164 | return AST::TypePath::create_error (); | |
6165 | } | |
6166 | ||
6167 | segments.push_back (std::move (segment)); | |
6168 | ||
6169 | t = lexer.peek_token (); | |
6170 | } | |
6171 | ||
6172 | segments.shrink_to_fit (); | |
6173 | ||
6174 | return AST::TypePath (std::move (segments), locus, | |
6175 | has_opening_scope_resolution); | |
6176 | } | |
6177 | ||
6178 | template <typename ManagedTokenSource> | |
6179 | AST::GenericArg | |
6180 | Parser<ManagedTokenSource>::parse_generic_arg () | |
6181 | { | |
6182 | auto tok = lexer.peek_token (); | |
6183 | std::unique_ptr<AST::Expr> expr = nullptr; | |
6184 | ||
6185 | switch (tok->get_id ()) | |
6186 | { | |
6187 | case IDENTIFIER: { | |
6188 | // This is a bit of a weird situation: With an identifier token, we | |
6189 | // could either have a valid type or a macro (FIXME: anything else?). So | |
6190 | // we need one bit of lookahead to differentiate if this is really | |
6191 | auto next_tok = lexer.peek_token (1); | |
6192 | if (next_tok->get_id () == EXCLAM) | |
6193 | { | |
6194 | auto type = parse_type (); | |
6195 | if (type) | |
6196 | return AST::GenericArg::create_type (std::move (type)); | |
6197 | else | |
6198 | return AST::GenericArg::create_error (); | |
6199 | } | |
6200 | lexer.skip_token (); | |
6201 | return AST::GenericArg::create_ambiguous (tok->get_str (), | |
6202 | tok->get_locus ()); | |
6203 | } | |
6204 | case LEFT_CURLY: | |
6205 | expr = parse_block_expr (); | |
6206 | break; | |
6207 | case MINUS: | |
6208 | case STRING_LITERAL: | |
6209 | case CHAR_LITERAL: | |
6210 | case INT_LITERAL: | |
6211 | case FLOAT_LITERAL: | |
6212 | case TRUE_LITERAL: | |
6213 | case FALSE_LITERAL: | |
6214 | expr = parse_literal_expr (); | |
6215 | break; | |
6216 | // FIXME: Because of this, error reporting is garbage for const generic | |
6217 | // parameter's default values | |
6218 | default: { | |
6219 | auto type = parse_type (); | |
6220 | // FIXME: Find a better way to do this? | |
6221 | if (type) | |
6222 | return AST::GenericArg::create_type (std::move (type)); | |
6223 | else | |
6224 | return AST::GenericArg::create_error (); | |
6225 | } | |
6226 | } | |
6227 | ||
6228 | if (!expr) | |
6229 | return AST::GenericArg::create_error (); | |
6230 | ||
6231 | return AST::GenericArg::create_const (std::move (expr)); | |
6232 | } | |
6233 | ||
6234 | // Parses the generic arguments in each path segment. | |
6235 | template <typename ManagedTokenSource> | |
6236 | AST::GenericArgs | |
6237 | Parser<ManagedTokenSource>::parse_path_generic_args () | |
6238 | { | |
6239 | if (!skip_token (LEFT_ANGLE)) | |
6240 | { | |
6241 | // skip after somewhere? | |
6242 | return AST::GenericArgs::create_empty (); | |
6243 | } | |
6244 | ||
6245 | // We need to parse all lifetimes, then parse types and const generics in | |
6246 | // any order. | |
6247 | ||
6248 | // try to parse lifetimes first | |
6249 | std::vector<AST::Lifetime> lifetime_args; | |
6250 | ||
6251 | const_TokenPtr t = lexer.peek_token (); | |
6252 | Location locus = t->get_locus (); | |
6253 | while (!is_right_angle_tok (t->get_id ())) | |
6254 | { | |
6255 | AST::Lifetime lifetime = parse_lifetime (); | |
6256 | if (lifetime.is_error ()) | |
6257 | { | |
6258 | // not necessarily an error | |
6259 | break; | |
6260 | } | |
6261 | ||
6262 | lifetime_args.push_back (std::move (lifetime)); | |
6263 | ||
6264 | // if next token isn't comma, then it must be end of list | |
6265 | if (lexer.peek_token ()->get_id () != COMMA) | |
6266 | { | |
6267 | break; | |
6268 | } | |
6269 | // skip comma | |
6270 | lexer.skip_token (); | |
6271 | ||
6272 | t = lexer.peek_token (); | |
6273 | } | |
6274 | ||
6275 | // try to parse types and const generics second | |
6276 | std::vector<AST::GenericArg> generic_args; | |
6277 | ||
6278 | // TODO: think of better control structure | |
6279 | t = lexer.peek_token (); | |
6280 | while (!is_right_angle_tok (t->get_id ())) | |
6281 | { | |
6282 | // FIXME: Is it fine to break if there is one binding? Can't there be | |
6283 | // bindings in between types? | |
6284 | ||
6285 | // ensure not binding being parsed as type accidently | |
6286 | if (t->get_id () == IDENTIFIER | |
6287 | && lexer.peek_token (1)->get_id () == EQUAL) | |
6288 | break; | |
6289 | ||
6290 | auto arg = parse_generic_arg (); | |
6291 | if (!arg.is_error ()) | |
6292 | { | |
6293 | generic_args.emplace_back (std::move (arg)); | |
6294 | } | |
6295 | ||
6296 | // FIXME: Do we need to break if we encounter an error? | |
6297 | ||
6298 | // if next token isn't comma, then it must be end of list | |
6299 | if (lexer.peek_token ()->get_id () != COMMA) | |
6300 | break; | |
6301 | ||
6302 | // skip comma | |
6303 | lexer.skip_token (); | |
6304 | t = lexer.peek_token (); | |
6305 | } | |
6306 | ||
6307 | // try to parse bindings third | |
6308 | std::vector<AST::GenericArgsBinding> binding_args; | |
6309 | ||
6310 | // TODO: think of better control structure | |
6311 | t = lexer.peek_token (); | |
6312 | while (!is_right_angle_tok (t->get_id ())) | |
6313 | { | |
6314 | AST::GenericArgsBinding binding = parse_generic_args_binding (); | |
6315 | if (binding.is_error ()) | |
6316 | { | |
6317 | // not necessarily an error | |
6318 | break; | |
6319 | } | |
6320 | ||
6321 | binding_args.push_back (std::move (binding)); | |
6322 | ||
6323 | // if next token isn't comma, then it must be end of list | |
6324 | if (lexer.peek_token ()->get_id () != COMMA) | |
6325 | { | |
6326 | break; | |
6327 | } | |
6328 | // skip comma | |
6329 | lexer.skip_token (); | |
6330 | ||
6331 | t = lexer.peek_token (); | |
6332 | } | |
6333 | ||
6334 | // skip any trailing commas | |
6335 | if (lexer.peek_token ()->get_id () == COMMA) | |
6336 | lexer.skip_token (); | |
6337 | ||
6338 | if (!skip_generics_right_angle ()) | |
6339 | return AST::GenericArgs::create_empty (); | |
6340 | ||
6341 | lifetime_args.shrink_to_fit (); | |
6342 | generic_args.shrink_to_fit (); | |
6343 | binding_args.shrink_to_fit (); | |
6344 | ||
6345 | return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args), | |
6346 | std::move (binding_args), locus); | |
6347 | } | |
6348 | ||
6349 | // Parses a binding in a generic args path segment. | |
6350 | template <typename ManagedTokenSource> | |
6351 | AST::GenericArgsBinding | |
6352 | Parser<ManagedTokenSource>::parse_generic_args_binding () | |
6353 | { | |
6354 | const_TokenPtr ident_tok = lexer.peek_token (); | |
6355 | if (ident_tok->get_id () != IDENTIFIER) | |
6356 | { | |
6357 | // allow non error-inducing use | |
6358 | // skip somewhere? | |
6359 | return AST::GenericArgsBinding::create_error (); | |
6360 | } | |
6361 | lexer.skip_token (); | |
6362 | Identifier ident = ident_tok->get_str (); | |
6363 | ||
6364 | if (!skip_token (EQUAL)) | |
6365 | { | |
6366 | // skip after somewhere? | |
6367 | return AST::GenericArgsBinding::create_error (); | |
6368 | } | |
6369 | ||
6370 | // parse type (required) | |
6371 | std::unique_ptr<AST::Type> type = parse_type (); | |
6372 | if (type == nullptr) | |
6373 | { | |
6374 | // skip somewhere? | |
6375 | return AST::GenericArgsBinding::create_error (); | |
6376 | } | |
6377 | ||
6378 | return AST::GenericArgsBinding (std::move (ident), std::move (type), | |
6379 | ident_tok->get_locus ()); | |
6380 | } | |
6381 | ||
6382 | /* Parses a single type path segment (not including opening scope resolution, | |
6383 | * but includes any internal ones). Includes generic args or type path | |
6384 | * functions too. */ | |
6385 | template <typename ManagedTokenSource> | |
6386 | std::unique_ptr<AST::TypePathSegment> | |
6387 | Parser<ManagedTokenSource>::parse_type_path_segment () | |
6388 | { | |
6389 | Location locus = lexer.peek_token ()->get_locus (); | |
6390 | // parse ident segment part | |
6391 | AST::PathIdentSegment ident_segment = parse_path_ident_segment (); | |
6392 | if (ident_segment.is_error ()) | |
6393 | { | |
6394 | // not necessarily an error | |
6395 | return nullptr; | |
6396 | } | |
6397 | ||
6398 | /* lookahead to determine if variants exist - only consume scope resolution | |
6399 | * then */ | |
6400 | bool has_separating_scope_resolution = false; | |
6401 | const_TokenPtr next = lexer.peek_token (1); | |
6402 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION | |
6403 | && (next->get_id () == LEFT_ANGLE || next->get_id () == LEFT_PAREN)) | |
6404 | { | |
6405 | has_separating_scope_resolution = true; | |
6406 | lexer.skip_token (); | |
6407 | } | |
6408 | ||
6409 | // branch into variants on next token | |
6410 | const_TokenPtr t = lexer.peek_token (); | |
6411 | switch (t->get_id ()) | |
6412 | { | |
6413 | case LEFT_ANGLE: { | |
6414 | // parse generic args | |
6415 | AST::GenericArgs generic_args = parse_path_generic_args (); | |
6416 | ||
6417 | return std::unique_ptr<AST::TypePathSegmentGeneric> ( | |
6418 | new AST::TypePathSegmentGeneric (std::move (ident_segment), | |
6419 | has_separating_scope_resolution, | |
6420 | std::move (generic_args), locus)); | |
6421 | } | |
6422 | case LEFT_PAREN: { | |
6423 | // parse type path function | |
6424 | AST::TypePathFunction type_path_function | |
6425 | = parse_type_path_function (locus); | |
6426 | ||
6427 | if (type_path_function.is_error ()) | |
6428 | { | |
6429 | // skip after somewhere? | |
6430 | return nullptr; | |
6431 | } | |
6432 | ||
6433 | return std::unique_ptr<AST::TypePathSegmentFunction> ( | |
6434 | new AST::TypePathSegmentFunction (std::move (ident_segment), | |
6435 | has_separating_scope_resolution, | |
6436 | std::move (type_path_function), | |
6437 | locus)); | |
6438 | } | |
6439 | default: | |
6440 | // neither of them | |
6441 | return std::unique_ptr<AST::TypePathSegment> ( | |
6442 | new AST::TypePathSegment (std::move (ident_segment), | |
6443 | has_separating_scope_resolution, locus)); | |
6444 | } | |
6445 | gcc_unreachable (); | |
6446 | } | |
6447 | ||
6448 | // Parses a function call representation inside a type path. | |
6449 | template <typename ManagedTokenSource> | |
6450 | AST::TypePathFunction | |
6451 | Parser<ManagedTokenSource>::parse_type_path_function (Location id_location) | |
6452 | { | |
6453 | if (!skip_token (LEFT_PAREN)) | |
6454 | { | |
6455 | // skip somewhere? | |
6456 | return AST::TypePathFunction::create_error (); | |
6457 | } | |
6458 | ||
6459 | // parse function inputs | |
6460 | std::vector<std::unique_ptr<AST::Type>> inputs; | |
6461 | ||
6462 | while (lexer.peek_token ()->get_id () != RIGHT_PAREN) | |
6463 | { | |
6464 | std::unique_ptr<AST::Type> type = parse_type (); | |
6465 | if (type == nullptr) | |
6466 | { | |
6467 | /* this is an error as there should've been a ')' there if there | |
6468 | * wasn't a type */ | |
6469 | Error error ( | |
6470 | lexer.peek_token ()->get_locus (), | |
6471 | "failed to parse type in parameters of type path function"); | |
6472 | add_error (std::move (error)); | |
6473 | ||
6474 | // skip somewhere? | |
6475 | return AST::TypePathFunction::create_error (); | |
6476 | } | |
6477 | ||
6478 | inputs.push_back (std::move (type)); | |
6479 | ||
6480 | // skip commas, including trailing commas | |
6481 | if (lexer.peek_token ()->get_id () != COMMA) | |
6482 | break; | |
6483 | ||
6484 | lexer.skip_token (); | |
6485 | } | |
6486 | ||
6487 | if (!skip_token (RIGHT_PAREN)) | |
6488 | { | |
6489 | // skip somewhere? | |
6490 | return AST::TypePathFunction::create_error (); | |
6491 | } | |
6492 | ||
6493 | // parse optional return type | |
6494 | std::unique_ptr<AST::Type> return_type = parse_function_return_type (); | |
6495 | ||
6496 | inputs.shrink_to_fit (); | |
6497 | return AST::TypePathFunction (std::move (inputs), id_location, | |
6498 | std::move (return_type)); | |
6499 | } | |
6500 | ||
6501 | // Parses a path inside an expression that allows generic arguments. | |
6502 | template <typename ManagedTokenSource> | |
6503 | AST::PathInExpression | |
6504 | Parser<ManagedTokenSource>::parse_path_in_expression () | |
6505 | { | |
6506 | Location locus = Linemap::unknown_location (); | |
6507 | bool has_opening_scope_resolution = false; | |
6508 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION) | |
6509 | { | |
6510 | has_opening_scope_resolution = true; | |
6511 | ||
6512 | locus = lexer.peek_token ()->get_locus (); | |
6513 | ||
6514 | lexer.skip_token (); | |
6515 | } | |
6516 | ||
6517 | // create segment vector | |
6518 | std::vector<AST::PathExprSegment> segments; | |
6519 | ||
6520 | if (locus == Linemap::unknown_location ()) | |
6521 | { | |
6522 | locus = lexer.peek_token ()->get_locus (); | |
6523 | } | |
6524 | ||
6525 | // parse required initial segment | |
6526 | AST::PathExprSegment initial_segment = parse_path_expr_segment (); | |
6527 | if (initial_segment.is_error ()) | |
6528 | { | |
6529 | // skip after somewhere? | |
6530 | // don't necessarily throw error but yeah | |
6531 | return AST::PathInExpression::create_error (); | |
6532 | } | |
6533 | segments.push_back (std::move (initial_segment)); | |
6534 | ||
6535 | // parse optional segments (as long as scope resolution operator exists) | |
6536 | const_TokenPtr t = lexer.peek_token (); | |
6537 | while (t->get_id () == SCOPE_RESOLUTION) | |
6538 | { | |
6539 | // skip scope resolution operator | |
6540 | lexer.skip_token (); | |
6541 | ||
6542 | // parse the actual segment - it is an error if it doesn't exist now | |
6543 | AST::PathExprSegment segment = parse_path_expr_segment (); | |
6544 | if (segment.is_error ()) | |
6545 | { | |
6546 | // skip after somewhere? | |
6547 | Error error (t->get_locus (), | |
6548 | "could not parse path expression segment"); | |
6549 | add_error (std::move (error)); | |
6550 | ||
6551 | return AST::PathInExpression::create_error (); | |
6552 | } | |
6553 | ||
6554 | segments.push_back (std::move (segment)); | |
6555 | ||
6556 | t = lexer.peek_token (); | |
6557 | } | |
6558 | ||
6559 | segments.shrink_to_fit (); | |
6560 | ||
6561 | return AST::PathInExpression (std::move (segments), {}, locus, | |
6562 | has_opening_scope_resolution); | |
6563 | } | |
6564 | ||
6565 | /* Parses a single path in expression path segment (including generic | |
6566 | * arguments). */ | |
6567 | template <typename ManagedTokenSource> | |
6568 | AST::PathExprSegment | |
6569 | Parser<ManagedTokenSource>::parse_path_expr_segment () | |
6570 | { | |
6571 | Location locus = lexer.peek_token ()->get_locus (); | |
6572 | // parse ident segment | |
6573 | AST::PathIdentSegment ident = parse_path_ident_segment (); | |
6574 | if (ident.is_error ()) | |
6575 | { | |
6576 | // not necessarily an error? | |
6577 | return AST::PathExprSegment::create_error (); | |
6578 | } | |
6579 | ||
6580 | // parse generic args (and turbofish), if they exist | |
6581 | /* use lookahead to determine if they actually exist (don't want to | |
6582 | * accidently parse over next ident segment) */ | |
6583 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION | |
6584 | && lexer.peek_token (1)->get_id () == LEFT_ANGLE) | |
6585 | { | |
6586 | // skip scope resolution | |
6587 | lexer.skip_token (); | |
6588 | ||
6589 | AST::GenericArgs generic_args = parse_path_generic_args (); | |
6590 | ||
6591 | return AST::PathExprSegment (std::move (ident), locus, | |
6592 | std::move (generic_args)); | |
6593 | } | |
6594 | ||
6595 | // return a generic parameter-less expr segment if not found | |
6596 | return AST::PathExprSegment (std::move (ident), locus); | |
6597 | } | |
6598 | ||
6599 | /* Parses a fully qualified path in expression (i.e. a pattern). FIXME does | |
6600 | * not parse outer attrs. */ | |
6601 | template <typename ManagedTokenSource> | |
6602 | AST::QualifiedPathInExpression | |
6603 | Parser<ManagedTokenSource>::parse_qualified_path_in_expression ( | |
6604 | Location pratt_parsed_loc) | |
6605 | { | |
6606 | /* Note: the Rust grammar is defined in such a way that it is impossible to | |
6607 | * determine whether a prospective qualified path is a | |
6608 | * QualifiedPathInExpression or QualifiedPathInType in all cases by the | |
6609 | * rules themselves (the only possible difference is a TypePathSegment with | |
6610 | * function, and lookahead to find this is too difficult). However, as this | |
6611 | * is a pattern and QualifiedPathInType is a type, I believe it that their | |
6612 | * construction will not be confused (due to rules regarding patterns vs | |
6613 | * types). | |
6614 | * As such, this function will not attempt to minimise errors created by | |
6615 | * their confusion. */ | |
6616 | ||
6617 | // parse the qualified path type (required) | |
6618 | AST::QualifiedPathType qual_path_type | |
6619 | = parse_qualified_path_type (pratt_parsed_loc); | |
6620 | if (qual_path_type.is_error ()) | |
6621 | { | |
6622 | // TODO: should this create a parse error? | |
6623 | return AST::QualifiedPathInExpression::create_error (); | |
6624 | } | |
6625 | Location locus = qual_path_type.get_locus (); | |
6626 | ||
6627 | // parse path segments | |
6628 | std::vector<AST::PathExprSegment> segments; | |
6629 | ||
6630 | // parse initial required segment | |
6631 | if (!expect_token (SCOPE_RESOLUTION)) | |
6632 | { | |
6633 | // skip after somewhere? | |
6634 | ||
6635 | return AST::QualifiedPathInExpression::create_error (); | |
6636 | } | |
6637 | AST::PathExprSegment initial_segment = parse_path_expr_segment (); | |
6638 | if (initial_segment.is_error ()) | |
6639 | { | |
6640 | // skip after somewhere? | |
6641 | Error error (lexer.peek_token ()->get_locus (), | |
6642 | "required initial path expression segment in " | |
6643 | "qualified path in expression could not be parsed"); | |
6644 | add_error (std::move (error)); | |
6645 | ||
6646 | return AST::QualifiedPathInExpression::create_error (); | |
6647 | } | |
6648 | segments.push_back (std::move (initial_segment)); | |
6649 | ||
6650 | // parse optional segments (as long as scope resolution operator exists) | |
6651 | const_TokenPtr t = lexer.peek_token (); | |
6652 | while (t->get_id () == SCOPE_RESOLUTION) | |
6653 | { | |
6654 | // skip scope resolution operator | |
6655 | lexer.skip_token (); | |
6656 | ||
6657 | // parse the actual segment - it is an error if it doesn't exist now | |
6658 | AST::PathExprSegment segment = parse_path_expr_segment (); | |
6659 | if (segment.is_error ()) | |
6660 | { | |
6661 | // skip after somewhere? | |
6662 | Error error (t->get_locus (), | |
6663 | "could not parse path expression segment in qualified " | |
6664 | "path in expression"); | |
6665 | add_error (std::move (error)); | |
6666 | ||
6667 | return AST::QualifiedPathInExpression::create_error (); | |
6668 | } | |
6669 | ||
6670 | segments.push_back (std::move (segment)); | |
6671 | ||
6672 | t = lexer.peek_token (); | |
6673 | } | |
6674 | ||
6675 | segments.shrink_to_fit (); | |
6676 | ||
6677 | // FIXME: outer attr parsing | |
6678 | return AST::QualifiedPathInExpression (std::move (qual_path_type), | |
6679 | std::move (segments), {}, locus); | |
6680 | } | |
6681 | ||
6682 | // Parses the type syntactical construction at the start of a qualified path. | |
6683 | template <typename ManagedTokenSource> | |
6684 | AST::QualifiedPathType | |
6685 | Parser<ManagedTokenSource>::parse_qualified_path_type ( | |
6686 | Location pratt_parsed_loc) | |
6687 | { | |
6688 | Location locus = pratt_parsed_loc; | |
6689 | /* TODO: should this actually be error? is there anywhere where this could | |
6690 | * be valid? */ | |
6691 | if (locus == Linemap::unknown_location ()) | |
6692 | { | |
6693 | locus = lexer.peek_token ()->get_locus (); | |
6694 | if (!skip_token (LEFT_ANGLE)) | |
6695 | { | |
6696 | // skip after somewhere? | |
6697 | return AST::QualifiedPathType::create_error (); | |
6698 | } | |
6699 | } | |
6700 | ||
6701 | // parse type (required) | |
6702 | std::unique_ptr<AST::Type> type = parse_type (); | |
6703 | if (type == nullptr) | |
6704 | { | |
6705 | Error error (lexer.peek_token ()->get_locus (), | |
6706 | "could not parse type in qualified path type"); | |
6707 | add_error (std::move (error)); | |
6708 | ||
6709 | // skip somewhere? | |
6710 | return AST::QualifiedPathType::create_error (); | |
6711 | } | |
6712 | ||
6713 | // parse optional as clause | |
6714 | AST::TypePath as_type_path = AST::TypePath::create_error (); | |
6715 | if (lexer.peek_token ()->get_id () == AS) | |
6716 | { | |
6717 | lexer.skip_token (); | |
6718 | ||
6719 | // parse type path, which is required now | |
6720 | as_type_path = parse_type_path (); | |
6721 | if (as_type_path.is_error ()) | |
6722 | { | |
6723 | Error error ( | |
6724 | lexer.peek_token ()->get_locus (), | |
6725 | "could not parse type path in as clause in qualified path type"); | |
6726 | add_error (std::move (error)); | |
6727 | ||
6728 | // skip somewhere? | |
6729 | return AST::QualifiedPathType::create_error (); | |
6730 | } | |
6731 | } | |
6732 | ||
6733 | /* NOTE: should actually be a right-angle token, so | |
6734 | * skip_generics_right_angle shouldn't be required */ | |
6735 | if (!skip_token (RIGHT_ANGLE)) | |
6736 | { | |
6737 | // skip after somewhere? | |
6738 | return AST::QualifiedPathType::create_error (); | |
6739 | } | |
6740 | ||
6741 | return AST::QualifiedPathType (std::move (type), locus, | |
6742 | std::move (as_type_path)); | |
6743 | } | |
6744 | ||
6745 | // Parses a fully qualified path in type (i.e. a type). | |
6746 | template <typename ManagedTokenSource> | |
6747 | AST::QualifiedPathInType | |
6748 | Parser<ManagedTokenSource>::parse_qualified_path_in_type () | |
6749 | { | |
6750 | Location locus = lexer.peek_token ()->get_locus (); | |
6751 | // parse the qualified path type (required) | |
6752 | AST::QualifiedPathType qual_path_type = parse_qualified_path_type (); | |
6753 | if (qual_path_type.is_error ()) | |
6754 | { | |
6755 | // TODO: should this create a parse error? | |
6756 | return AST::QualifiedPathInType::create_error (); | |
6757 | } | |
6758 | ||
6759 | // parse initial required segment | |
6760 | if (!expect_token (SCOPE_RESOLUTION)) | |
6761 | { | |
6762 | // skip after somewhere? | |
6763 | ||
6764 | return AST::QualifiedPathInType::create_error (); | |
6765 | } | |
6766 | std::unique_ptr<AST::TypePathSegment> initial_segment | |
6767 | = parse_type_path_segment (); | |
6768 | if (initial_segment == nullptr) | |
6769 | { | |
6770 | // skip after somewhere? | |
6771 | Error error (lexer.peek_token ()->get_locus (), | |
6772 | "required initial type path segment in qualified path in " | |
6773 | "type could not be parsed"); | |
6774 | add_error (std::move (error)); | |
6775 | ||
6776 | return AST::QualifiedPathInType::create_error (); | |
6777 | } | |
6778 | ||
6779 | // parse optional segments (as long as scope resolution operator exists) | |
6780 | std::vector<std::unique_ptr<AST::TypePathSegment>> segments; | |
6781 | const_TokenPtr t = lexer.peek_token (); | |
6782 | while (t->get_id () == SCOPE_RESOLUTION) | |
6783 | { | |
6784 | // skip scope resolution operator | |
6785 | lexer.skip_token (); | |
6786 | ||
6787 | // parse the actual segment - it is an error if it doesn't exist now | |
6788 | std::unique_ptr<AST::TypePathSegment> segment | |
6789 | = parse_type_path_segment (); | |
6790 | if (segment == nullptr) | |
6791 | { | |
6792 | // skip after somewhere? | |
6793 | Error error ( | |
6794 | t->get_locus (), | |
6795 | "could not parse type path segment in qualified path in type"); | |
6796 | add_error (std::move (error)); | |
6797 | ||
6798 | return AST::QualifiedPathInType::create_error (); | |
6799 | } | |
6800 | ||
6801 | segments.push_back (std::move (segment)); | |
6802 | ||
6803 | t = lexer.peek_token (); | |
6804 | } | |
6805 | ||
6806 | segments.shrink_to_fit (); | |
6807 | ||
6808 | return AST::QualifiedPathInType (std::move (qual_path_type), | |
6809 | std::move (initial_segment), | |
6810 | std::move (segments), locus); | |
6811 | } | |
6812 | ||
6813 | // Parses a self param. Also handles self param not existing. | |
6814 | template <typename ManagedTokenSource> | |
6815 | AST::SelfParam | |
6816 | Parser<ManagedTokenSource>::parse_self_param () | |
6817 | { | |
6818 | bool has_reference = false; | |
6819 | AST::Lifetime lifetime = AST::Lifetime::error (); | |
6820 | ||
6821 | Location locus = lexer.peek_token ()->get_locus (); | |
6822 | ||
6823 | // test if self is a reference parameter | |
6824 | if (lexer.peek_token ()->get_id () == AMP) | |
6825 | { | |
6826 | has_reference = true; | |
6827 | lexer.skip_token (); | |
6828 | ||
6829 | // now test whether it has a lifetime | |
6830 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
6831 | { | |
6832 | lifetime = parse_lifetime (); | |
6833 | ||
6834 | // something went wrong somehow | |
6835 | if (lifetime.is_error ()) | |
6836 | { | |
6837 | Error error (lexer.peek_token ()->get_locus (), | |
6838 | "failed to parse lifetime in self param"); | |
6839 | add_error (std::move (error)); | |
6840 | ||
6841 | // skip after somewhere? | |
6842 | return AST::SelfParam::create_error (); | |
6843 | } | |
6844 | } | |
6845 | } | |
6846 | ||
6847 | // test for mut | |
6848 | bool has_mut = false; | |
6849 | if (lexer.peek_token ()->get_id () == MUT) | |
6850 | { | |
6851 | has_mut = true; | |
6852 | lexer.skip_token (); | |
6853 | } | |
6854 | ||
6855 | // skip self token | |
6856 | const_TokenPtr self_tok = lexer.peek_token (); | |
6857 | if (self_tok->get_id () != SELF) | |
6858 | { | |
6859 | // skip after somewhere? | |
6860 | return AST::SelfParam::create_error (); | |
6861 | } | |
6862 | lexer.skip_token (); | |
6863 | ||
6864 | // parse optional type | |
6865 | std::unique_ptr<AST::Type> type = nullptr; | |
6866 | if (lexer.peek_token ()->get_id () == COLON) | |
6867 | { | |
6868 | lexer.skip_token (); | |
6869 | ||
6870 | // type is now required | |
6871 | type = parse_type (); | |
6872 | if (type == nullptr) | |
6873 | { | |
6874 | Error error (lexer.peek_token ()->get_locus (), | |
6875 | "could not parse type in self param"); | |
6876 | add_error (std::move (error)); | |
6877 | ||
6878 | // skip after somewhere? | |
6879 | return AST::SelfParam::create_error (); | |
6880 | } | |
6881 | } | |
6882 | ||
6883 | // ensure that cannot have both type and reference | |
6884 | if (type != nullptr && has_reference) | |
6885 | { | |
6886 | Error error ( | |
6887 | lexer.peek_token ()->get_locus (), | |
6888 | "cannot have both a reference and a type specified in a self param"); | |
6889 | add_error (std::move (error)); | |
6890 | ||
6891 | // skip after somewhere? | |
6892 | return AST::SelfParam::create_error (); | |
6893 | } | |
6894 | ||
6895 | if (has_reference) | |
6896 | { | |
6897 | return AST::SelfParam (std::move (lifetime), has_mut, locus); | |
6898 | } | |
6899 | else | |
6900 | { | |
6901 | // note that type may be nullptr here and that's fine | |
6902 | return AST::SelfParam (std::move (type), has_mut, locus); | |
6903 | } | |
6904 | } | |
32c8fb0e JP |
6905 | |
6906 | /* Parses a method. Note that this function is probably useless because using | |
6907 | * lookahead to determine whether a function is a method is a PITA (maybe not | |
6908 | * even doable), so most places probably parse a "function or method" and then | |
6909 | * resolve it into whatever it is afterward. As such, this is only here for | |
6910 | * algorithmically defining the grammar rule. */ | |
6911 | template <typename ManagedTokenSource> | |
6912 | AST::Method | |
6913 | Parser<ManagedTokenSource>::parse_method () | |
6914 | { | |
6915 | Location locus = lexer.peek_token ()->get_locus (); | |
6916 | /* Note: as a result of the above, this will not attempt to disambiguate a | |
6917 | * function parse qualifiers */ | |
6918 | AST::FunctionQualifiers qualifiers = parse_function_qualifiers (); | |
6919 | ||
6920 | skip_token (FN_TOK); | |
6921 | ||
6922 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
6923 | if (ident_tok == nullptr) | |
6924 | { | |
6925 | skip_after_next_block (); | |
6926 | return AST::Method::create_error (); | |
6927 | } | |
6928 | Identifier method_name = ident_tok->get_str (); | |
6929 | ||
6930 | // parse generic params - if exist | |
6931 | std::vector<std::unique_ptr<AST::GenericParam>> generic_params | |
6932 | = parse_generic_params_in_angles (); | |
6933 | ||
6934 | if (!skip_token (LEFT_PAREN)) | |
6935 | { | |
6936 | Error error (lexer.peek_token ()->get_locus (), | |
6937 | "method missing opening parentheses before parameter list"); | |
6938 | add_error (std::move (error)); | |
6939 | ||
6940 | skip_after_next_block (); | |
6941 | return AST::Method::create_error (); | |
6942 | } | |
6943 | ||
6944 | // parse self param | |
6945 | AST::SelfParam self_param = parse_self_param (); | |
6946 | if (self_param.is_error ()) | |
6947 | { | |
6948 | Error error (lexer.peek_token ()->get_locus (), | |
6949 | "could not parse self param in method"); | |
6950 | add_error (std::move (error)); | |
6951 | ||
6952 | skip_after_next_block (); | |
6953 | return AST::Method::create_error (); | |
6954 | } | |
6955 | ||
6956 | // skip comma if it exists | |
6957 | if (lexer.peek_token ()->get_id () == COMMA) | |
6958 | lexer.skip_token (); | |
6959 | ||
6960 | // parse function parameters | |
6961 | std::vector<AST::FunctionParam> function_params | |
6962 | = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; }); | |
6963 | ||
6964 | if (!skip_token (RIGHT_PAREN)) | |
6965 | { | |
6966 | Error error (lexer.peek_token ()->get_locus (), | |
6967 | "method declaration missing closing parentheses after " | |
6968 | "parameter list"); | |
6969 | add_error (std::move (error)); | |
6970 | ||
6971 | skip_after_next_block (); | |
6972 | return AST::Method::create_error (); | |
6973 | } | |
6974 | ||
6975 | // parse function return type - if exists | |
6976 | std::unique_ptr<AST::Type> return_type = parse_function_return_type (); | |
6977 | ||
6978 | // parse where clause - if exists | |
6979 | AST::WhereClause where_clause = parse_where_clause (); | |
6980 | ||
6981 | // parse block expression | |
6982 | std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr (); | |
6983 | if (block_expr == nullptr) | |
6984 | { | |
6985 | Error error (lexer.peek_token ()->get_locus (), | |
6986 | "method declaration missing block expression"); | |
6987 | add_error (std::move (error)); | |
6988 | ||
6989 | skip_after_end_block (); | |
6990 | return AST::Method::create_error (); | |
6991 | } | |
6992 | ||
6993 | // does not parse visibility, but this method isn't used, so doesn't matter | |
6994 | return AST::Method (std::move (method_name), std::move (qualifiers), | |
6995 | std::move (generic_params), std::move (self_param), | |
6996 | std::move (function_params), std::move (return_type), | |
6997 | std::move (where_clause), std::move (block_expr), | |
6998 | AST::Visibility::create_error (), AST::AttrVec (), locus); | |
6999 | } | |
7000 | ||
7001 | /* Parses an expression statement (disambiguates to expression with or without | |
7002 | * block statement). */ | |
7003 | template <typename ManagedTokenSource> | |
7004 | std::unique_ptr<AST::ExprStmt> | |
7005 | Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, | |
7006 | ParseRestrictions restrictions) | |
7007 | { | |
7008 | /* potential thoughts - define new virtual method "has_block()" on expr. | |
7009 | * parse expr and then determine whether semicolon is needed as a result of | |
7010 | * this method. but then this would require dynamic_cast, which is not | |
7011 | * allowed. */ | |
7012 | ||
7013 | /* okay new thought - big switch to disambiguate exprs with blocks - either | |
7014 | * block expr, async block expr, unsafe block expr, loop expr, if expr, if | |
7015 | * let expr, or match expr. So all others are exprs without block. */ | |
7016 | /* new thought: possible initial tokens: 'loop', 'while', 'for', lifetime | |
7017 | * (and then ':' and then loop), 'if', 'match', '{', 'async', 'unsafe' (and | |
7018 | * then | |
7019 | * '{')). This seems to have no ambiguity. */ | |
7020 | ||
7021 | const_TokenPtr t = lexer.peek_token (); | |
7022 | /* TODO: should the switch just directly call the individual parse methods | |
7023 | * rather than adding another layer of indirection with | |
7024 | * parse_expr_stmt_with_block()? */ | |
7025 | switch (t->get_id ()) | |
7026 | { | |
7027 | case LOOP: | |
7028 | case WHILE: | |
7029 | case FOR: | |
7030 | case IF: | |
7031 | case MATCH_TOK: | |
7032 | case LEFT_CURLY: | |
7033 | case ASYNC: | |
7034 | // expression with block | |
7035 | return parse_expr_stmt_with_block (std::move (outer_attrs)); | |
7036 | case LIFETIME: { | |
7037 | /* FIXME: are there any expressions without blocks that can have | |
7038 | * lifetime as their first token? Or is loop expr the only one? */ | |
7039 | // safe side for now: | |
7040 | if (lexer.peek_token (1)->get_id () == COLON | |
7041 | && lexer.peek_token (2)->get_id () == LOOP) | |
7042 | { | |
7043 | return parse_expr_stmt_with_block (std::move (outer_attrs)); | |
7044 | } | |
7045 | else | |
7046 | { | |
7047 | return parse_expr_stmt_without_block (std::move (outer_attrs), | |
7048 | restrictions); | |
7049 | } | |
7050 | } | |
7051 | case UNSAFE: { | |
7052 | /* FIXME: are there any expressions without blocks that can have | |
7053 | * unsafe as their first token? Or is unsafe the only one? */ | |
7054 | // safe side for now | |
7055 | if (lexer.peek_token (1)->get_id () == LEFT_CURLY) | |
7056 | { | |
7057 | return parse_expr_stmt_with_block (std::move (outer_attrs)); | |
7058 | } | |
7059 | else | |
7060 | { | |
7061 | return parse_expr_stmt_without_block (std::move (outer_attrs), | |
7062 | restrictions); | |
7063 | } | |
7064 | } | |
7065 | default: | |
7066 | // not a parse expr with block, so must be expr without block | |
7067 | /* TODO: if possible, be more selective about possible expr without | |
7068 | * block initial tokens in order to prevent more syntactical errors at | |
7069 | * parse time. */ | |
7070 | return parse_expr_stmt_without_block (std::move (outer_attrs), | |
7071 | restrictions); | |
7072 | } | |
7073 | } | |
7074 | ||
7075 | template <typename ManagedTokenSource> | |
7076 | std::unique_ptr<AST::ExprWithBlock> | |
7077 | Parser<ManagedTokenSource>::parse_expr_with_block (AST::AttrVec outer_attrs) | |
7078 | { | |
7079 | std::unique_ptr<AST::ExprWithBlock> expr_parsed = nullptr; | |
7080 | ||
7081 | const_TokenPtr t = lexer.peek_token (); | |
7082 | switch (t->get_id ()) | |
7083 | { | |
7084 | case IF: | |
7085 | // if or if let, so more lookahead to find out | |
7086 | if (lexer.peek_token (1)->get_id () == LET) | |
7087 | { | |
7088 | // if let expr | |
7089 | expr_parsed = parse_if_let_expr (std::move (outer_attrs)); | |
7090 | break; | |
7091 | } | |
7092 | else | |
7093 | { | |
7094 | // if expr | |
7095 | expr_parsed = parse_if_expr (std::move (outer_attrs)); | |
7096 | break; | |
7097 | } | |
7098 | case LOOP: | |
7099 | // infinite loop | |
7100 | expr_parsed = parse_loop_expr (std::move (outer_attrs)); | |
7101 | break; | |
7102 | case FOR: | |
7103 | // "for" iterator loop | |
7104 | expr_parsed = parse_for_loop_expr (std::move (outer_attrs)); | |
7105 | break; | |
7106 | case WHILE: { | |
7107 | // while or while let, so more lookahead to find out | |
7108 | if (lexer.peek_token (1)->get_id () == LET) | |
7109 | { | |
7110 | // while let loop expr | |
7111 | expr_parsed = parse_while_let_loop_expr (std::move (outer_attrs)); | |
7112 | break; | |
7113 | } | |
7114 | else | |
7115 | { | |
7116 | // while loop expr | |
7117 | expr_parsed = parse_while_loop_expr (std::move (outer_attrs)); | |
7118 | break; | |
7119 | } | |
7120 | } | |
7121 | case MATCH_TOK: | |
7122 | // match expression | |
7123 | expr_parsed = parse_match_expr (std::move (outer_attrs)); | |
7124 | break; | |
7125 | case LEFT_CURLY: | |
7126 | // block expression | |
7127 | expr_parsed = parse_block_expr (std::move (outer_attrs)); | |
7128 | break; | |
7129 | case ASYNC: | |
7130 | // async block expression | |
7131 | expr_parsed = parse_async_block_expr (std::move (outer_attrs)); | |
7132 | break; | |
7133 | case UNSAFE: | |
7134 | // unsafe block expression | |
7135 | expr_parsed = parse_unsafe_block_expr (std::move (outer_attrs)); | |
7136 | break; | |
7137 | case LIFETIME: | |
7138 | // some kind of loop expr (with loop label) | |
7139 | expr_parsed = parse_labelled_loop_expr (std::move (outer_attrs)); | |
7140 | break; | |
7141 | default: | |
7142 | add_error (Error ( | |
7143 | t->get_locus (), | |
7144 | "could not recognise expr beginning with %qs as an expr with block in" | |
7145 | " parsing expr statement", | |
7146 | t->get_token_description ())); | |
7147 | ||
7148 | skip_after_next_block (); | |
7149 | return nullptr; | |
7150 | } | |
7151 | ||
7152 | // ensure expr parsed exists | |
7153 | if (expr_parsed == nullptr) | |
7154 | { | |
7155 | Error error (t->get_locus (), | |
7156 | "failed to parse expr with block in parsing expr statement"); | |
7157 | add_error (std::move (error)); | |
7158 | ||
7159 | skip_after_end_block (); | |
7160 | return nullptr; | |
7161 | } | |
7162 | ||
7163 | return expr_parsed; | |
7164 | } | |
7165 | ||
7166 | /* Parses a expression statement containing an expression with block. | |
7167 | * Disambiguates internally. */ | |
7168 | template <typename ManagedTokenSource> | |
7169 | std::unique_ptr<AST::ExprStmtWithBlock> | |
7170 | Parser<ManagedTokenSource>::parse_expr_stmt_with_block ( | |
7171 | AST::AttrVec outer_attrs) | |
7172 | { | |
7173 | auto expr_parsed = parse_expr_with_block (std::move (outer_attrs)); | |
7174 | auto locus = expr_parsed->get_locus (); | |
7175 | ||
7176 | // return expr stmt created from expr | |
7177 | return std::unique_ptr<AST::ExprStmtWithBlock> ( | |
7178 | new AST::ExprStmtWithBlock (std::move (expr_parsed), locus, | |
7179 | lexer.peek_token ()->get_id () == SEMICOLON)); | |
7180 | } | |
7181 | ||
7182 | /* Parses an expression statement containing an expression without block. | |
7183 | * Disambiguates further. */ | |
7184 | template <typename ManagedTokenSource> | |
7185 | std::unique_ptr<AST::ExprStmtWithoutBlock> | |
7186 | Parser<ManagedTokenSource>::parse_expr_stmt_without_block ( | |
7187 | AST::AttrVec outer_attrs, ParseRestrictions restrictions) | |
7188 | { | |
7189 | /* TODO: maybe move more logic for expr without block in here for better | |
7190 | * error handling */ | |
7191 | ||
7192 | // attempt to parse via parse_expr_without_block - seems to work | |
7193 | std::unique_ptr<AST::ExprWithoutBlock> expr = nullptr; | |
7194 | Location locus = lexer.peek_token ()->get_locus (); | |
7195 | ||
7196 | restrictions.expr_can_be_stmt = true; | |
7197 | ||
7198 | expr = parse_expr_without_block (std::move (outer_attrs), restrictions); | |
7199 | if (expr == nullptr) | |
7200 | { | |
7201 | // expr is required, error | |
7202 | Error error (lexer.peek_token ()->get_locus (), | |
7203 | "failed to parse expr without block in expr statement"); | |
7204 | add_error (std::move (error)); | |
7205 | ||
7206 | skip_after_semicolon (); | |
7207 | return nullptr; | |
7208 | } | |
7209 | ||
7210 | if (restrictions.consume_semi) | |
7211 | if (!skip_token (SEMICOLON)) | |
7212 | return nullptr; | |
7213 | ||
7214 | return std::unique_ptr<AST::ExprStmtWithoutBlock> ( | |
7215 | new AST::ExprStmtWithoutBlock (std::move (expr), locus)); | |
7216 | } | |
7217 | ||
7218 | /* Parses an expression without a block associated with it (further | |
7219 | * disambiguates). */ | |
7220 | template <typename ManagedTokenSource> | |
7221 | std::unique_ptr<AST::ExprWithoutBlock> | |
7222 | Parser<ManagedTokenSource>::parse_expr_without_block ( | |
7223 | AST::AttrVec outer_attrs, ParseRestrictions restrictions) | |
7224 | { | |
7225 | /* Notes on types of expr without block: | |
7226 | * - literal expr tokens that are literals | |
7227 | * - path expr path_in_expr or qual_path_in_expr | |
7228 | * - operator expr many different types | |
7229 | * unary: | |
7230 | * borrow expr ( '&' | '&&' ) 'mut'? expr | |
7231 | * dereference expr '*' expr | |
7232 | * error propagation expr '?' | |
7233 | * negation '-' expr | |
7234 | * not '!' expr | |
7235 | * binary: all start with expr | |
7236 | * - grouped/paren expr '(' inner_attributes expr ')' | |
7237 | * - array expr '[' inner_attributes array_elems? ']' | |
7238 | * - await expr expr '.' 'await' | |
7239 | * - (array/slice) index expr expr '[' expr ']' | |
7240 | * - tuple expr '(' inner_attributes tuple_elems? ')' | |
7241 | * note that a single elem tuple is distinguished from a grouped expr | |
7242 | * by a trailing comma, i.e. a grouped expr is preferred over a tuple expr | |
7243 | * - tuple index expr expr '.' tuple_index | |
7244 | * - struct expr path_in_expr (and optional other stuff) | |
7245 | * - enum variant expr path_in_expr (and optional other stuff) | |
7246 | * this means that there is no syntactic difference between an enum | |
7247 | * variant and a struct | |
7248 | * - only name resolution can tell the difference. Thus, maybe rework | |
7249 | * AST to take this into account ("struct or enum" nodes?) | |
7250 | * - (function) call expr expr '(' call_params? ')' | |
7251 | * - method call expr expr '.' path_expr_segment '(' call_params? ')' | |
7252 | * - field expr expr '.' identifier | |
7253 | * note that method call expr is preferred, i.e. field expr must not be | |
7254 | * followed by parenthesised expression sequence. | |
7255 | * - closure expr 'move'? ( '||' | '|' closure_params? '|' ) ( | |
7256 | * expr | '->' type_no_bounds block_expr ) | |
7257 | * - continue expr 'continue' labelled_lifetime? | |
7258 | * - break expr 'break' labelled_lifetime? expr? | |
7259 | * - range expr many different types but all involve '..' or | |
7260 | * '..=' | |
7261 | * - return expr 'return' as 1st tok | |
7262 | * - macro invocation identifier then :: or identifier then ! | |
7263 | * (simple_path '!') | |
7264 | * | |
7265 | * any that have rules beginning with 'expr' should probably be | |
7266 | * pratt-parsed, | |
7267 | * with parsing type to use determined by token AND lookahead. */ | |
7268 | ||
7269 | // ok well at least can do easy ones | |
7270 | const_TokenPtr t = lexer.peek_token (); | |
7271 | switch (t->get_id ()) | |
7272 | { | |
7273 | case RETURN_TOK: | |
7274 | // return expr | |
7275 | return parse_return_expr (std::move (outer_attrs)); | |
7276 | case BREAK: | |
7277 | // break expr | |
7278 | return parse_break_expr (std::move (outer_attrs)); | |
7279 | case CONTINUE: | |
7280 | // continue expr | |
7281 | return parse_continue_expr (std::move (outer_attrs)); | |
7282 | case MOVE: | |
7283 | // closure expr (though not all closure exprs require this) | |
7284 | return parse_closure_expr (std::move (outer_attrs)); | |
7285 | case LEFT_SQUARE: | |
7286 | // array expr (creation, not index) | |
7287 | return parse_array_expr (std::move (outer_attrs)); | |
7288 | default: { | |
7289 | /* HACK: piggyback on pratt parsed expr and abuse polymorphism to | |
7290 | * essentially downcast */ | |
7291 | ||
7292 | std::unique_ptr<AST::Expr> expr | |
7293 | = parse_expr (std::move (outer_attrs), restrictions); | |
7294 | ||
7295 | if (expr == nullptr) | |
7296 | { | |
7297 | Error error (t->get_locus (), | |
7298 | "failed to parse expression for expression without " | |
7299 | "block (pratt-parsed expression is null)"); | |
7300 | add_error (std::move (error)); | |
7301 | ||
7302 | return nullptr; | |
7303 | } | |
7304 | ||
7305 | std::unique_ptr<AST::ExprWithoutBlock> expr_without_block ( | |
7306 | expr->as_expr_without_block ()); | |
7307 | ||
7308 | if (expr_without_block != nullptr) | |
7309 | { | |
7310 | return expr_without_block; | |
7311 | } | |
7312 | else | |
7313 | { | |
7314 | Error error (t->get_locus (), | |
7315 | "converted expr without block is null"); | |
7316 | add_error (std::move (error)); | |
7317 | ||
7318 | return nullptr; | |
7319 | } | |
7320 | } | |
7321 | } | |
7322 | } | |
7323 | ||
7324 | // Parses a block expression, including the curly braces at start and end. | |
7325 | template <typename ManagedTokenSource> | |
7326 | std::unique_ptr<AST::BlockExpr> | |
7327 | Parser<ManagedTokenSource>::parse_block_expr (AST::AttrVec outer_attrs, | |
7328 | Location pratt_parsed_loc) | |
7329 | { | |
7330 | Location locus = pratt_parsed_loc; | |
7331 | if (locus == Linemap::unknown_location ()) | |
7332 | { | |
7333 | locus = lexer.peek_token ()->get_locus (); | |
7334 | if (!skip_token (LEFT_CURLY)) | |
7335 | { | |
7336 | skip_after_end_block (); | |
7337 | return nullptr; | |
7338 | } | |
7339 | } | |
7340 | ||
7341 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
7342 | ||
7343 | // parse statements and expression | |
7344 | std::vector<std::unique_ptr<AST::Stmt>> stmts; | |
7345 | std::unique_ptr<AST::Expr> expr = nullptr; | |
7346 | ||
7347 | const_TokenPtr t = lexer.peek_token (); | |
7348 | while (t->get_id () != RIGHT_CURLY) | |
7349 | { | |
7350 | ExprOrStmt expr_or_stmt = parse_stmt_or_expr_without_block (); | |
7351 | if (expr_or_stmt.is_error ()) | |
7352 | { | |
7353 | Error error (t->get_locus (), | |
7354 | "failed to parse statement or expression without " | |
7355 | "block in block expression"); | |
7356 | add_error (std::move (error)); | |
7357 | ||
7358 | return nullptr; | |
7359 | } | |
7360 | ||
7361 | t = lexer.peek_token (); | |
7362 | ||
7363 | if (expr_or_stmt.stmt != nullptr) | |
7364 | { | |
7365 | stmts.push_back (std::move (expr_or_stmt.stmt)); | |
7366 | } | |
7367 | else | |
7368 | { | |
7369 | // assign to expression and end parsing inside | |
7370 | expr = std::move (expr_or_stmt.expr); | |
7371 | break; | |
7372 | } | |
7373 | } | |
7374 | ||
7375 | Location end_locus = t->get_locus (); | |
7376 | ||
7377 | if (!skip_token (RIGHT_CURLY)) | |
7378 | { | |
7379 | Error error (t->get_locus (), | |
7380 | "error may be from having an expression (as opposed to " | |
7381 | "statement) in the body of the function but not last"); | |
7382 | add_error (std::move (error)); | |
7383 | ||
7384 | skip_after_end_block (); | |
7385 | return nullptr; | |
7386 | } | |
7387 | ||
7388 | // grammar allows for empty block expressions | |
7389 | ||
7390 | stmts.shrink_to_fit (); | |
7391 | ||
7392 | return std::unique_ptr<AST::BlockExpr> ( | |
7393 | new AST::BlockExpr (std::move (stmts), std::move (expr), | |
7394 | std::move (inner_attrs), std::move (outer_attrs), locus, | |
7395 | end_locus)); | |
7396 | } | |
7397 | ||
7398 | /* Parses a "grouped" expression (expression in parentheses), used to control | |
7399 | * precedence. */ | |
7400 | template <typename ManagedTokenSource> | |
7401 | std::unique_ptr<AST::GroupedExpr> | |
7402 | Parser<ManagedTokenSource>::parse_grouped_expr (AST::AttrVec outer_attrs) | |
7403 | { | |
7404 | Location locus = lexer.peek_token ()->get_locus (); | |
7405 | skip_token (LEFT_PAREN); | |
7406 | ||
7407 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
7408 | ||
7409 | // parse required expr inside parentheses | |
7410 | std::unique_ptr<AST::Expr> expr_in_parens = parse_expr (); | |
7411 | if (expr_in_parens == nullptr) | |
7412 | { | |
7413 | // skip after somewhere? | |
7414 | // error? | |
7415 | return nullptr; | |
7416 | } | |
7417 | ||
7418 | if (!skip_token (RIGHT_PAREN)) | |
7419 | { | |
7420 | // skip after somewhere? | |
7421 | return nullptr; | |
7422 | } | |
7423 | ||
7424 | return std::unique_ptr<AST::GroupedExpr> ( | |
7425 | new AST::GroupedExpr (std::move (expr_in_parens), std::move (inner_attrs), | |
7426 | std::move (outer_attrs), locus)); | |
7427 | } | |
7428 | ||
7429 | // Parses a closure expression (closure definition). | |
7430 | template <typename ManagedTokenSource> | |
7431 | std::unique_ptr<AST::ClosureExpr> | |
7432 | Parser<ManagedTokenSource>::parse_closure_expr (AST::AttrVec outer_attrs) | |
7433 | { | |
7434 | Location locus = lexer.peek_token ()->get_locus (); | |
7435 | // detect optional "move" | |
7436 | bool has_move = false; | |
7437 | if (lexer.peek_token ()->get_id () == MOVE) | |
7438 | { | |
7439 | lexer.skip_token (); | |
7440 | has_move = true; | |
7441 | } | |
7442 | ||
7443 | // handle parameter list | |
7444 | std::vector<AST::ClosureParam> params; | |
7445 | ||
7446 | const_TokenPtr t = lexer.peek_token (); | |
7447 | switch (t->get_id ()) | |
7448 | { | |
7449 | case OR: | |
7450 | // skip token, no parameters | |
7451 | lexer.skip_token (); | |
7452 | break; | |
7453 | case PIPE: | |
7454 | // actually may have parameters | |
7455 | lexer.skip_token (); | |
7456 | ||
7457 | while (t->get_id () != PIPE) | |
7458 | { | |
7459 | AST::ClosureParam param = parse_closure_param (); | |
7460 | if (param.is_error ()) | |
7461 | { | |
7462 | // TODO is this really an error? | |
7463 | Error error (t->get_locus (), "could not parse closure param"); | |
7464 | add_error (std::move (error)); | |
7465 | ||
7466 | break; | |
7467 | } | |
7468 | params.push_back (std::move (param)); | |
7469 | ||
7470 | if (lexer.peek_token ()->get_id () != COMMA) | |
7471 | { | |
7472 | // not an error but means param list is done | |
7473 | break; | |
7474 | } | |
7475 | // skip comma | |
7476 | lexer.skip_token (); | |
7477 | ||
7478 | t = lexer.peek_token (); | |
7479 | } | |
7480 | params.shrink_to_fit (); | |
7481 | break; | |
7482 | default: | |
7483 | add_error (Error (t->get_locus (), | |
7484 | "unexpected token %qs in closure expression - expected " | |
7485 | "%<|%> or %<||%>", | |
7486 | t->get_token_description ())); | |
7487 | ||
7488 | // skip somewhere? | |
7489 | return nullptr; | |
7490 | } | |
7491 | ||
7492 | // again branch based on next token | |
7493 | t = lexer.peek_token (); | |
7494 | if (t->get_id () == RETURN_TYPE) | |
7495 | { | |
7496 | // must be return type closure with block expr | |
7497 | ||
7498 | // skip "return type" token | |
7499 | lexer.skip_token (); | |
7500 | ||
7501 | // parse actual type, which is required | |
7502 | std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds (); | |
7503 | if (type == nullptr) | |
7504 | { | |
7505 | // error | |
7506 | Error error (t->get_locus (), "failed to parse type for closure"); | |
7507 | add_error (std::move (error)); | |
7508 | ||
7509 | // skip somewhere? | |
7510 | return nullptr; | |
7511 | } | |
7512 | ||
7513 | // parse block expr, which is required | |
7514 | std::unique_ptr<AST::BlockExpr> block = parse_block_expr (); | |
7515 | if (block == nullptr) | |
7516 | { | |
7517 | // error | |
7518 | Error error (lexer.peek_token ()->get_locus (), | |
7519 | "failed to parse block expr in closure"); | |
7520 | add_error (std::move (error)); | |
7521 | ||
7522 | // skip somewhere? | |
7523 | return nullptr; | |
7524 | } | |
7525 | ||
7526 | return std::unique_ptr<AST::ClosureExprInnerTyped> ( | |
7527 | new AST::ClosureExprInnerTyped (std::move (type), std::move (block), | |
7528 | std::move (params), locus, has_move, | |
7529 | std::move (outer_attrs))); | |
7530 | } | |
7531 | else | |
7532 | { | |
7533 | // must be expr-only closure | |
7534 | ||
7535 | // parse expr, which is required | |
7536 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
7537 | if (expr == nullptr) | |
7538 | { | |
7539 | Error error (t->get_locus (), | |
7540 | "failed to parse expression in closure"); | |
7541 | add_error (std::move (error)); | |
7542 | ||
7543 | // skip somewhere? | |
7544 | return nullptr; | |
7545 | } | |
7546 | ||
7547 | return std::unique_ptr<AST::ClosureExprInner> ( | |
7548 | new AST::ClosureExprInner (std::move (expr), std::move (params), locus, | |
7549 | has_move, std::move (outer_attrs))); | |
7550 | } | |
7551 | } | |
7552 | ||
7553 | // Parses a literal token (to literal expression). | |
7554 | template <typename ManagedTokenSource> | |
7555 | std::unique_ptr<AST::LiteralExpr> | |
7556 | Parser<ManagedTokenSource>::parse_literal_expr (AST::AttrVec outer_attrs) | |
7557 | { | |
7558 | // TODO: change if literal representation in lexer changes | |
7559 | ||
7560 | std::string literal_value; | |
7561 | AST::Literal::LitType type = AST::Literal::STRING; | |
7562 | ||
7563 | // branch based on token | |
7564 | const_TokenPtr t = lexer.peek_token (); | |
7565 | switch (t->get_id ()) | |
7566 | { | |
7567 | case CHAR_LITERAL: | |
7568 | type = AST::Literal::CHAR; | |
7569 | literal_value = t->get_str (); | |
7570 | lexer.skip_token (); | |
7571 | break; | |
7572 | case STRING_LITERAL: | |
7573 | type = AST::Literal::STRING; | |
7574 | literal_value = t->get_str (); | |
7575 | lexer.skip_token (); | |
7576 | break; | |
7577 | case BYTE_CHAR_LITERAL: | |
7578 | type = AST::Literal::BYTE; | |
7579 | literal_value = t->get_str (); | |
7580 | lexer.skip_token (); | |
7581 | break; | |
7582 | case BYTE_STRING_LITERAL: | |
7583 | type = AST::Literal::BYTE_STRING; | |
7584 | literal_value = t->get_str (); | |
7585 | lexer.skip_token (); | |
7586 | break; | |
7587 | case INT_LITERAL: | |
7588 | type = AST::Literal::INT; | |
7589 | literal_value = t->get_str (); | |
7590 | lexer.skip_token (); | |
7591 | break; | |
7592 | case FLOAT_LITERAL: | |
7593 | type = AST::Literal::FLOAT; | |
7594 | literal_value = t->get_str (); | |
7595 | lexer.skip_token (); | |
7596 | break; | |
7597 | // case BOOL_LITERAL | |
7598 | // use true and false keywords rather than "bool literal" Rust terminology | |
7599 | case TRUE_LITERAL: | |
7600 | type = AST::Literal::BOOL; | |
7601 | literal_value = "true"; | |
7602 | lexer.skip_token (); | |
7603 | break; | |
7604 | case FALSE_LITERAL: | |
7605 | type = AST::Literal::BOOL; | |
7606 | literal_value = "false"; | |
7607 | lexer.skip_token (); | |
7608 | break; | |
7609 | default: | |
7610 | // error - cannot be a literal expr | |
7611 | add_error (Error (t->get_locus (), | |
7612 | "unexpected token %qs when parsing literal expression", | |
7613 | t->get_token_description ())); | |
7614 | ||
7615 | // skip? | |
7616 | return nullptr; | |
7617 | } | |
7618 | ||
7619 | // create literal based on stuff in switch | |
7620 | return std::unique_ptr<AST::LiteralExpr> ( | |
7621 | new AST::LiteralExpr (std::move (literal_value), std::move (type), | |
7622 | t->get_type_hint (), std::move (outer_attrs), | |
7623 | t->get_locus ())); | |
7624 | } | |
7625 | ||
7626 | // Parses a return expression (including any expression to return). | |
7627 | template <typename ManagedTokenSource> | |
7628 | std::unique_ptr<AST::ReturnExpr> | |
7629 | Parser<ManagedTokenSource>::parse_return_expr (AST::AttrVec outer_attrs, | |
7630 | Location pratt_parsed_loc) | |
7631 | { | |
7632 | Location locus = pratt_parsed_loc; | |
7633 | if (locus == Linemap::unknown_location ()) | |
7634 | { | |
7635 | locus = lexer.peek_token ()->get_locus (); | |
7636 | skip_token (RETURN_TOK); | |
7637 | } | |
7638 | ||
7639 | // parse expression to return, if it exists | |
7640 | ParseRestrictions restrictions; | |
7641 | restrictions.expr_can_be_null = true; | |
7642 | std::unique_ptr<AST::Expr> returned_expr | |
7643 | = parse_expr (AST::AttrVec (), restrictions); | |
7644 | ||
7645 | return std::unique_ptr<AST::ReturnExpr> ( | |
7646 | new AST::ReturnExpr (std::move (returned_expr), std::move (outer_attrs), | |
7647 | locus)); | |
7648 | } | |
7649 | ||
7650 | /* Parses a break expression (including any label to break to AND any return | |
7651 | * expression). */ | |
7652 | template <typename ManagedTokenSource> | |
7653 | std::unique_ptr<AST::BreakExpr> | |
7654 | Parser<ManagedTokenSource>::parse_break_expr (AST::AttrVec outer_attrs, | |
7655 | Location pratt_parsed_loc) | |
7656 | { | |
7657 | Location locus = pratt_parsed_loc; | |
7658 | if (locus == Linemap::unknown_location ()) | |
7659 | { | |
7660 | locus = lexer.peek_token ()->get_locus (); | |
7661 | skip_token (BREAK); | |
7662 | } | |
7663 | ||
7664 | // parse label (lifetime) if it exists - create dummy first | |
7665 | AST::Lifetime label = AST::Lifetime::error (); | |
7666 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
7667 | { | |
7668 | label = parse_lifetime (); | |
7669 | } | |
7670 | ||
7671 | // parse break return expression if it exists | |
7672 | ParseRestrictions restrictions; | |
7673 | restrictions.expr_can_be_null = true; | |
7674 | std::unique_ptr<AST::Expr> return_expr | |
7675 | = parse_expr (AST::AttrVec (), restrictions); | |
7676 | ||
7677 | return std::unique_ptr<AST::BreakExpr> ( | |
7678 | new AST::BreakExpr (std::move (label), std::move (return_expr), | |
7679 | std::move (outer_attrs), locus)); | |
7680 | } | |
7681 | ||
7682 | // Parses a continue expression (including any label to continue from). | |
7683 | template <typename ManagedTokenSource> | |
7684 | std::unique_ptr<AST::ContinueExpr> | |
7685 | Parser<ManagedTokenSource>::parse_continue_expr (AST::AttrVec outer_attrs, | |
7686 | Location pratt_parsed_loc) | |
7687 | { | |
7688 | Location locus = pratt_parsed_loc; | |
7689 | if (locus == Linemap::unknown_location ()) | |
7690 | { | |
7691 | locus = lexer.peek_token ()->get_locus (); | |
7692 | skip_token (CONTINUE); | |
7693 | } | |
7694 | ||
7695 | // parse label (lifetime) if it exists - create dummy first | |
7696 | AST::Lifetime label = AST::Lifetime::error (); | |
7697 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
7698 | { | |
7699 | label = parse_lifetime (); | |
7700 | } | |
7701 | ||
7702 | return std::unique_ptr<AST::ContinueExpr> ( | |
7703 | new AST::ContinueExpr (std::move (label), std::move (outer_attrs), locus)); | |
7704 | } | |
7705 | ||
7706 | // Parses a loop label used in loop expressions. | |
7707 | template <typename ManagedTokenSource> | |
7708 | AST::LoopLabel | |
7709 | Parser<ManagedTokenSource>::parse_loop_label () | |
7710 | { | |
7711 | // parse lifetime - if doesn't exist, assume no label | |
7712 | const_TokenPtr t = lexer.peek_token (); | |
7713 | if (t->get_id () != LIFETIME) | |
7714 | { | |
7715 | // not necessarily an error | |
7716 | return AST::LoopLabel::error (); | |
7717 | } | |
7718 | /* FIXME: check for named lifetime requirement here? or check in semantic | |
7719 | * analysis phase? */ | |
7720 | AST::Lifetime label = parse_lifetime (); | |
7721 | ||
7722 | if (!skip_token (COLON)) | |
7723 | { | |
7724 | // skip somewhere? | |
7725 | return AST::LoopLabel::error (); | |
7726 | } | |
7727 | ||
7728 | return AST::LoopLabel (std::move (label), t->get_locus ()); | |
7729 | } | |
7730 | ||
7731 | /* Parses an if expression of any kind, including with else, else if, else if | |
7732 | * let, and neither. Note that any outer attributes will be ignored because if | |
7733 | * expressions don't support them. */ | |
7734 | template <typename ManagedTokenSource> | |
7735 | std::unique_ptr<AST::IfExpr> | |
7736 | Parser<ManagedTokenSource>::parse_if_expr (AST::AttrVec outer_attrs, | |
7737 | Location pratt_parsed_loc) | |
7738 | { | |
7739 | // TODO: make having outer attributes an error? | |
7740 | Location locus = pratt_parsed_loc; | |
7741 | if (locus == Linemap::unknown_location ()) | |
7742 | { | |
7743 | locus = lexer.peek_token ()->get_locus (); | |
7744 | if (!skip_token (IF)) | |
7745 | { | |
7746 | skip_after_end_block (); | |
7747 | return nullptr; | |
7748 | } | |
7749 | } | |
7750 | ||
7751 | // detect accidental if let | |
7752 | if (lexer.peek_token ()->get_id () == LET) | |
7753 | { | |
7754 | Error error (lexer.peek_token ()->get_locus (), | |
7755 | "if let expression probably exists, but is being parsed " | |
7756 | "as an if expression. This may be a parser error"); | |
7757 | add_error (std::move (error)); | |
7758 | ||
7759 | // skip somewhere? | |
7760 | return nullptr; | |
7761 | } | |
7762 | ||
7763 | /* parse required condition expr - HACK to prevent struct expr from being | |
7764 | * parsed */ | |
7765 | ParseRestrictions no_struct_expr; | |
7766 | no_struct_expr.can_be_struct_expr = false; | |
7767 | std::unique_ptr<AST::Expr> condition = parse_expr ({}, no_struct_expr); | |
7768 | if (condition == nullptr) | |
7769 | { | |
7770 | Error error (lexer.peek_token ()->get_locus (), | |
7771 | "failed to parse condition expression in if expression"); | |
7772 | add_error (std::move (error)); | |
7773 | ||
7774 | // skip somewhere? | |
7775 | return nullptr; | |
7776 | } | |
7777 | ||
7778 | // parse required block expr | |
7779 | std::unique_ptr<AST::BlockExpr> if_body = parse_block_expr (); | |
7780 | if (if_body == nullptr) | |
7781 | { | |
7782 | Error error (lexer.peek_token ()->get_locus (), | |
7783 | "failed to parse if body block expression in if expression"); | |
7784 | add_error (std::move (error)); | |
7785 | ||
7786 | // skip somewhere? | |
7787 | return nullptr; | |
7788 | } | |
7789 | ||
7790 | // branch to parse end or else (and then else, else if, or else if let) | |
7791 | if (lexer.peek_token ()->get_id () != ELSE) | |
7792 | { | |
7793 | // single selection - end of if expression | |
7794 | return std::unique_ptr<AST::IfExpr> ( | |
7795 | new AST::IfExpr (std::move (condition), std::move (if_body), | |
7796 | std::move (outer_attrs), locus)); | |
7797 | } | |
7798 | else | |
7799 | { | |
7800 | // double or multiple selection - branch on end, else if, or else if let | |
7801 | ||
7802 | // skip "else" | |
7803 | lexer.skip_token (); | |
7804 | ||
7805 | // branch on whether next token is '{' or 'if' | |
7806 | const_TokenPtr t = lexer.peek_token (); | |
7807 | switch (t->get_id ()) | |
7808 | { | |
7809 | case LEFT_CURLY: { | |
7810 | // double selection - else | |
7811 | // parse else block expr (required) | |
7812 | std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr (); | |
7813 | if (else_body == nullptr) | |
7814 | { | |
7815 | Error error (lexer.peek_token ()->get_locus (), | |
7816 | "failed to parse else body block expression in " | |
7817 | "if expression"); | |
7818 | add_error (std::move (error)); | |
7819 | ||
7820 | // skip somewhere? | |
7821 | return nullptr; | |
7822 | } | |
7823 | ||
7824 | return std::unique_ptr<AST::IfExprConseqElse> ( | |
7825 | new AST::IfExprConseqElse (std::move (condition), | |
7826 | std::move (if_body), | |
7827 | std::move (else_body), | |
7828 | std::move (outer_attrs), locus)); | |
7829 | } | |
7830 | case IF: { | |
7831 | // multiple selection - else if or else if let | |
7832 | // branch on whether next token is 'let' or not | |
7833 | if (lexer.peek_token (1)->get_id () == LET) | |
7834 | { | |
7835 | // parse if let expr (required) | |
7836 | std::unique_ptr<AST::IfLetExpr> if_let_expr | |
7837 | = parse_if_let_expr (); | |
7838 | if (if_let_expr == nullptr) | |
7839 | { | |
7840 | Error error (lexer.peek_token ()->get_locus (), | |
7841 | "failed to parse (else) if let expression " | |
7842 | "after if expression"); | |
7843 | add_error (std::move (error)); | |
7844 | ||
7845 | // skip somewhere? | |
7846 | return nullptr; | |
7847 | } | |
7848 | ||
7849 | return std::unique_ptr<AST::IfExprConseqIfLet> ( | |
7850 | new AST::IfExprConseqIfLet (std::move (condition), | |
7851 | std::move (if_body), | |
7852 | std::move (if_let_expr), | |
7853 | std::move (outer_attrs), locus)); | |
7854 | } | |
7855 | else | |
7856 | { | |
7857 | // parse if expr (required) | |
7858 | std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr (); | |
7859 | if (if_expr == nullptr) | |
7860 | { | |
7861 | Error error (lexer.peek_token ()->get_locus (), | |
7862 | "failed to parse (else) if expression after " | |
7863 | "if expression"); | |
7864 | add_error (std::move (error)); | |
7865 | ||
7866 | // skip somewhere? | |
7867 | return nullptr; | |
7868 | } | |
7869 | ||
7870 | return std::unique_ptr<AST::IfExprConseqIf> ( | |
7871 | new AST::IfExprConseqIf (std::move (condition), | |
7872 | std::move (if_body), | |
7873 | std::move (if_expr), | |
7874 | std::move (outer_attrs), locus)); | |
7875 | } | |
7876 | } | |
7877 | default: | |
7878 | // error - invalid token | |
7879 | add_error (Error (t->get_locus (), | |
7880 | "unexpected token %qs after else in if expression", | |
7881 | t->get_token_description ())); | |
7882 | ||
7883 | // skip somewhere? | |
7884 | return nullptr; | |
7885 | } | |
7886 | } | |
7887 | } | |
7888 | ||
7889 | /* Parses an if let expression of any kind, including with else, else if, else | |
7890 | * if let, and none. Note that any outer attributes will be ignored as if let | |
7891 | * expressions don't support them. */ | |
7892 | template <typename ManagedTokenSource> | |
7893 | std::unique_ptr<AST::IfLetExpr> | |
7894 | Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs, | |
7895 | Location pratt_parsed_loc) | |
7896 | { | |
7897 | // TODO: make having outer attributes an error? | |
7898 | Location locus = pratt_parsed_loc; | |
7899 | if (locus == Linemap::unknown_location ()) | |
7900 | { | |
7901 | locus = lexer.peek_token ()->get_locus (); | |
7902 | if (!skip_token (IF)) | |
7903 | { | |
7904 | skip_after_end_block (); | |
7905 | return nullptr; | |
7906 | } | |
7907 | } | |
7908 | ||
7909 | // detect accidental if expr parsed as if let expr | |
7910 | if (lexer.peek_token ()->get_id () != LET) | |
7911 | { | |
7912 | Error error (lexer.peek_token ()->get_locus (), | |
7913 | "if expression probably exists, but is being parsed as an " | |
7914 | "if let expression. This may be a parser error"); | |
7915 | add_error (std::move (error)); | |
7916 | ||
7917 | // skip somewhere? | |
7918 | return nullptr; | |
7919 | } | |
7920 | lexer.skip_token (); | |
7921 | ||
7922 | // parse match arm patterns (which are required) | |
7923 | std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns | |
7924 | = parse_match_arm_patterns (EQUAL); | |
7925 | if (match_arm_patterns.empty ()) | |
7926 | { | |
7927 | Error error ( | |
7928 | lexer.peek_token ()->get_locus (), | |
7929 | "failed to parse any match arm patterns in if let expression"); | |
7930 | add_error (std::move (error)); | |
7931 | ||
7932 | // skip somewhere? | |
7933 | return nullptr; | |
7934 | } | |
7935 | ||
7936 | if (!skip_token (EQUAL)) | |
7937 | { | |
7938 | // skip somewhere? | |
7939 | return nullptr; | |
7940 | } | |
7941 | ||
7942 | // parse expression (required) - HACK to prevent struct expr being parsed | |
7943 | ParseRestrictions no_struct_expr; | |
7944 | no_struct_expr.can_be_struct_expr = false; | |
7945 | std::unique_ptr<AST::Expr> scrutinee_expr = parse_expr ({}, no_struct_expr); | |
7946 | if (scrutinee_expr == nullptr) | |
7947 | { | |
7948 | Error error (lexer.peek_token ()->get_locus (), | |
7949 | "failed to parse scrutinee expression in if let expression"); | |
7950 | add_error (std::move (error)); | |
7951 | ||
7952 | // skip somewhere? | |
7953 | return nullptr; | |
7954 | } | |
7955 | /* TODO: check for expression not being a struct expression or lazy boolean | |
7956 | * expression here? or actually probably in semantic analysis. */ | |
7957 | ||
7958 | // parse block expression (required) | |
7959 | std::unique_ptr<AST::BlockExpr> if_let_body = parse_block_expr (); | |
7960 | if (if_let_body == nullptr) | |
7961 | { | |
7962 | Error error ( | |
7963 | lexer.peek_token ()->get_locus (), | |
7964 | "failed to parse if let body block expression in if let expression"); | |
7965 | add_error (std::move (error)); | |
7966 | ||
7967 | // skip somewhere? | |
7968 | return nullptr; | |
7969 | } | |
7970 | ||
7971 | // branch to parse end or else (and then else, else if, or else if let) | |
7972 | if (lexer.peek_token ()->get_id () != ELSE) | |
7973 | { | |
7974 | // single selection - end of if let expression | |
7975 | return std::unique_ptr<AST::IfLetExpr> ( | |
7976 | new AST::IfLetExpr (std::move (match_arm_patterns), | |
7977 | std::move (scrutinee_expr), std::move (if_let_body), | |
7978 | std::move (outer_attrs), locus)); | |
7979 | } | |
7980 | else | |
7981 | { | |
7982 | // double or multiple selection - branch on end, else if, or else if let | |
7983 | ||
7984 | // skip "else" | |
7985 | lexer.skip_token (); | |
7986 | ||
7987 | // branch on whether next token is '{' or 'if' | |
7988 | const_TokenPtr t = lexer.peek_token (); | |
7989 | switch (t->get_id ()) | |
7990 | { | |
7991 | case LEFT_CURLY: { | |
7992 | // double selection - else | |
7993 | // parse else block expr (required) | |
7994 | std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr (); | |
7995 | if (else_body == nullptr) | |
7996 | { | |
7997 | Error error (lexer.peek_token ()->get_locus (), | |
7998 | "failed to parse else body block expression in " | |
7999 | "if let expression"); | |
8000 | add_error (std::move (error)); | |
8001 | ||
8002 | // skip somewhere? | |
8003 | return nullptr; | |
8004 | } | |
8005 | ||
8006 | return std::unique_ptr<AST::IfLetExprConseqElse> ( | |
8007 | new AST::IfLetExprConseqElse (std::move (match_arm_patterns), | |
8008 | std::move (scrutinee_expr), | |
8009 | std::move (if_let_body), | |
8010 | std::move (else_body), | |
8011 | std::move (outer_attrs), locus)); | |
8012 | } | |
8013 | case IF: { | |
8014 | // multiple selection - else if or else if let | |
8015 | // branch on whether next token is 'let' or not | |
8016 | if (lexer.peek_token (1)->get_id () == LET) | |
8017 | { | |
8018 | // parse if let expr (required) | |
8019 | std::unique_ptr<AST::IfLetExpr> if_let_expr | |
8020 | = parse_if_let_expr (); | |
8021 | if (if_let_expr == nullptr) | |
8022 | { | |
8023 | Error error (lexer.peek_token ()->get_locus (), | |
8024 | "failed to parse (else) if let expression " | |
8025 | "after if let expression"); | |
8026 | add_error (std::move (error)); | |
8027 | ||
8028 | // skip somewhere? | |
8029 | return nullptr; | |
8030 | } | |
8031 | ||
8032 | return std::unique_ptr<AST::IfLetExprConseqIfLet> ( | |
8033 | new AST::IfLetExprConseqIfLet ( | |
8034 | std::move (match_arm_patterns), std::move (scrutinee_expr), | |
8035 | std::move (if_let_body), std::move (if_let_expr), | |
8036 | std::move (outer_attrs), locus)); | |
8037 | } | |
8038 | else | |
8039 | { | |
8040 | // parse if expr (required) | |
8041 | std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr (); | |
8042 | if (if_expr == nullptr) | |
8043 | { | |
8044 | Error error (lexer.peek_token ()->get_locus (), | |
8045 | "failed to parse (else) if expression after " | |
8046 | "if let expression"); | |
8047 | add_error (std::move (error)); | |
8048 | ||
8049 | // skip somewhere? | |
8050 | return nullptr; | |
8051 | } | |
8052 | ||
8053 | return std::unique_ptr<AST::IfLetExprConseqIf> ( | |
8054 | new AST::IfLetExprConseqIf (std::move (match_arm_patterns), | |
8055 | std::move (scrutinee_expr), | |
8056 | std::move (if_let_body), | |
8057 | std::move (if_expr), | |
8058 | std::move (outer_attrs), locus)); | |
8059 | } | |
8060 | } | |
8061 | default: | |
8062 | // error - invalid token | |
8063 | add_error ( | |
8064 | Error (t->get_locus (), | |
8065 | "unexpected token %qs after else in if let expression", | |
8066 | t->get_token_description ())); | |
8067 | ||
8068 | // skip somewhere? | |
8069 | return nullptr; | |
8070 | } | |
8071 | } | |
8072 | } | |
8073 | ||
8074 | /* TODO: possibly decide on different method of handling label (i.e. not | |
8075 | * parameter) */ | |
8076 | ||
8077 | /* Parses a "loop" infinite loop expression. Label is not parsed and should be | |
8078 | * parsed via parse_labelled_loop_expr, which would call this. */ | |
8079 | template <typename ManagedTokenSource> | |
8080 | std::unique_ptr<AST::LoopExpr> | |
8081 | Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs, | |
8082 | AST::LoopLabel label, | |
8083 | Location pratt_parsed_loc) | |
8084 | { | |
8085 | Location locus = pratt_parsed_loc; | |
8086 | if (locus == Linemap::unknown_location ()) | |
8087 | { | |
8088 | if (label.is_error ()) | |
8089 | locus = lexer.peek_token ()->get_locus (); | |
8090 | else | |
8091 | locus = label.get_locus (); | |
8092 | ||
8093 | if (!skip_token (LOOP)) | |
8094 | { | |
8095 | skip_after_end_block (); | |
8096 | return nullptr; | |
8097 | } | |
8098 | } | |
8099 | else | |
8100 | { | |
8101 | if (!label.is_error ()) | |
8102 | locus = label.get_locus (); | |
8103 | } | |
8104 | ||
8105 | // parse loop body, which is required | |
8106 | std::unique_ptr<AST::BlockExpr> loop_body = parse_block_expr (); | |
8107 | if (loop_body == nullptr) | |
8108 | { | |
8109 | Error error (lexer.peek_token ()->get_locus (), | |
8110 | "could not parse loop body in (infinite) loop expression"); | |
8111 | add_error (std::move (error)); | |
8112 | ||
8113 | return nullptr; | |
8114 | } | |
8115 | ||
8116 | return std::unique_ptr<AST::LoopExpr> ( | |
8117 | new AST::LoopExpr (std::move (loop_body), locus, std::move (label), | |
8118 | std::move (outer_attrs))); | |
8119 | } | |
8120 | ||
8121 | /* Parses a "while" loop expression. Label is not parsed and should be parsed | |
8122 | * via parse_labelled_loop_expr, which would call this. */ | |
8123 | template <typename ManagedTokenSource> | |
8124 | std::unique_ptr<AST::WhileLoopExpr> | |
8125 | Parser<ManagedTokenSource>::parse_while_loop_expr (AST::AttrVec outer_attrs, | |
8126 | AST::LoopLabel label, | |
8127 | Location pratt_parsed_loc) | |
8128 | { | |
8129 | Location locus = pratt_parsed_loc; | |
8130 | if (locus == Linemap::unknown_location ()) | |
8131 | { | |
8132 | if (label.is_error ()) | |
8133 | locus = lexer.peek_token ()->get_locus (); | |
8134 | else | |
8135 | locus = label.get_locus (); | |
8136 | ||
8137 | if (!skip_token (WHILE)) | |
8138 | { | |
8139 | skip_after_end_block (); | |
8140 | return nullptr; | |
8141 | } | |
8142 | } | |
8143 | else | |
8144 | { | |
8145 | if (!label.is_error ()) | |
8146 | locus = label.get_locus (); | |
8147 | } | |
8148 | ||
8149 | // ensure it isn't a while let loop | |
8150 | if (lexer.peek_token ()->get_id () == LET) | |
8151 | { | |
8152 | Error error (lexer.peek_token ()->get_locus (), | |
8153 | "appears to be while let loop but is being parsed by " | |
8154 | "while loop - this may be a compiler issue"); | |
8155 | add_error (std::move (error)); | |
8156 | ||
8157 | // skip somewhere? | |
8158 | return nullptr; | |
8159 | } | |
8160 | ||
8161 | // parse loop predicate (required) with HACK to prevent struct expr parsing | |
8162 | ParseRestrictions no_struct_expr; | |
8163 | no_struct_expr.can_be_struct_expr = false; | |
8164 | std::unique_ptr<AST::Expr> predicate = parse_expr ({}, no_struct_expr); | |
8165 | if (predicate == nullptr) | |
8166 | { | |
8167 | Error error (lexer.peek_token ()->get_locus (), | |
8168 | "failed to parse predicate expression in while loop"); | |
8169 | add_error (std::move (error)); | |
8170 | ||
8171 | // skip somewhere? | |
8172 | return nullptr; | |
8173 | } | |
8174 | /* TODO: check that it isn't struct expression here? actually, probably in | |
8175 | * semantic analysis */ | |
8176 | ||
8177 | // parse loop body (required) | |
8178 | std::unique_ptr<AST::BlockExpr> body = parse_block_expr (); | |
8179 | if (body == nullptr) | |
8180 | { | |
8181 | Error error (lexer.peek_token ()->get_locus (), | |
8182 | "failed to parse loop body block expression in while loop"); | |
8183 | add_error (std::move (error)); | |
8184 | ||
8185 | // skip somewhere | |
8186 | return nullptr; | |
8187 | } | |
8188 | ||
8189 | return std::unique_ptr<AST::WhileLoopExpr> ( | |
8190 | new AST::WhileLoopExpr (std::move (predicate), std::move (body), locus, | |
8191 | std::move (label), std::move (outer_attrs))); | |
8192 | } | |
8193 | ||
8194 | /* Parses a "while let" loop expression. Label is not parsed and should be | |
8195 | * parsed via parse_labelled_loop_expr, which would call this. */ | |
8196 | template <typename ManagedTokenSource> | |
8197 | std::unique_ptr<AST::WhileLetLoopExpr> | |
8198 | Parser<ManagedTokenSource>::parse_while_let_loop_expr (AST::AttrVec outer_attrs, | |
8199 | AST::LoopLabel label) | |
8200 | { | |
8201 | Location locus = Linemap::unknown_location (); | |
8202 | if (label.is_error ()) | |
8203 | locus = lexer.peek_token ()->get_locus (); | |
8204 | else | |
8205 | locus = label.get_locus (); | |
8206 | skip_token (WHILE); | |
8207 | ||
8208 | /* check for possible accidental recognition of a while loop as a while let | |
8209 | * loop */ | |
8210 | if (lexer.peek_token ()->get_id () != LET) | |
8211 | { | |
8212 | Error error (lexer.peek_token ()->get_locus (), | |
8213 | "appears to be a while loop but is being parsed by " | |
8214 | "while let loop - this may be a compiler issue"); | |
8215 | add_error (std::move (error)); | |
8216 | ||
8217 | // skip somewhere | |
8218 | return nullptr; | |
8219 | } | |
8220 | // as this token is definitely let now, save the computation of comparison | |
8221 | lexer.skip_token (); | |
8222 | ||
8223 | // parse predicate patterns | |
8224 | std::vector<std::unique_ptr<AST::Pattern>> predicate_patterns | |
8225 | = parse_match_arm_patterns (EQUAL); | |
8226 | // TODO: have to ensure that there is at least 1 pattern? | |
8227 | ||
8228 | if (!skip_token (EQUAL)) | |
8229 | { | |
8230 | // skip somewhere? | |
8231 | return nullptr; | |
8232 | } | |
8233 | ||
8234 | /* parse predicate expression, which is required (and HACK to prevent struct | |
8235 | * expr) */ | |
8236 | ParseRestrictions no_struct_expr; | |
8237 | no_struct_expr.can_be_struct_expr = false; | |
8238 | std::unique_ptr<AST::Expr> predicate_expr = parse_expr ({}, no_struct_expr); | |
8239 | if (predicate_expr == nullptr) | |
8240 | { | |
8241 | Error error (lexer.peek_token ()->get_locus (), | |
8242 | "failed to parse predicate expression in while let loop"); | |
8243 | add_error (std::move (error)); | |
8244 | ||
8245 | // skip somewhere? | |
8246 | return nullptr; | |
8247 | } | |
8248 | /* TODO: ensure that struct expression is not parsed? Actually, probably in | |
8249 | * semantic analysis. */ | |
8250 | ||
8251 | // parse loop body, which is required | |
8252 | std::unique_ptr<AST::BlockExpr> body = parse_block_expr (); | |
8253 | if (body == nullptr) | |
8254 | { | |
8255 | Error error (lexer.peek_token ()->get_locus (), | |
8256 | "failed to parse block expr (loop body) of while let loop"); | |
8257 | add_error (std::move (error)); | |
8258 | ||
8259 | // skip somewhere? | |
8260 | return nullptr; | |
8261 | } | |
8262 | ||
8263 | return std::unique_ptr<AST::WhileLetLoopExpr> (new AST::WhileLetLoopExpr ( | |
8264 | std::move (predicate_patterns), std::move (predicate_expr), | |
8265 | std::move (body), locus, std::move (label), std::move (outer_attrs))); | |
8266 | } | |
8267 | ||
8268 | /* Parses a "for" iterative loop. Label is not parsed and should be parsed via | |
8269 | * parse_labelled_loop_expr, which would call this. */ | |
8270 | template <typename ManagedTokenSource> | |
8271 | std::unique_ptr<AST::ForLoopExpr> | |
8272 | Parser<ManagedTokenSource>::parse_for_loop_expr (AST::AttrVec outer_attrs, | |
8273 | AST::LoopLabel label) | |
8274 | { | |
8275 | Location locus = Linemap::unknown_location (); | |
8276 | if (label.is_error ()) | |
8277 | locus = lexer.peek_token ()->get_locus (); | |
8278 | else | |
8279 | locus = label.get_locus (); | |
8280 | skip_token (FOR); | |
8281 | ||
8282 | // parse pattern, which is required | |
8283 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
8284 | if (pattern == nullptr) | |
8285 | { | |
8286 | Error error (lexer.peek_token ()->get_locus (), | |
8287 | "failed to parse iterator pattern in for loop"); | |
8288 | add_error (std::move (error)); | |
8289 | ||
8290 | // skip somewhere? | |
8291 | return nullptr; | |
8292 | } | |
8293 | ||
8294 | if (!skip_token (IN)) | |
8295 | { | |
8296 | // skip somewhere? | |
8297 | return nullptr; | |
8298 | } | |
8299 | ||
8300 | /* parse iterator expression, which is required - also HACK to prevent | |
8301 | * struct expr */ | |
8302 | ParseRestrictions no_struct_expr; | |
8303 | no_struct_expr.can_be_struct_expr = false; | |
8304 | std::unique_ptr<AST::Expr> expr = parse_expr ({}, no_struct_expr); | |
8305 | if (expr == nullptr) | |
8306 | { | |
8307 | Error error (lexer.peek_token ()->get_locus (), | |
8308 | "failed to parse iterator expression in for loop"); | |
8309 | add_error (std::move (error)); | |
8310 | ||
8311 | // skip somewhere? | |
8312 | return nullptr; | |
8313 | } | |
8314 | // TODO: check to ensure this isn't struct expr? Or in semantic analysis. | |
8315 | ||
8316 | // parse loop body, which is required | |
8317 | std::unique_ptr<AST::BlockExpr> body = parse_block_expr (); | |
8318 | if (body == nullptr) | |
8319 | { | |
8320 | Error error (lexer.peek_token ()->get_locus (), | |
8321 | "failed to parse loop body block expression in for loop"); | |
8322 | add_error (std::move (error)); | |
8323 | ||
8324 | // skip somewhere? | |
8325 | return nullptr; | |
8326 | } | |
8327 | ||
8328 | return std::unique_ptr<AST::ForLoopExpr> ( | |
8329 | new AST::ForLoopExpr (std::move (pattern), std::move (expr), | |
8330 | std::move (body), locus, std::move (label), | |
8331 | std::move (outer_attrs))); | |
8332 | } | |
8333 | ||
8334 | // Parses a loop expression with label (any kind of loop - disambiguates). | |
8335 | template <typename ManagedTokenSource> | |
8336 | std::unique_ptr<AST::BaseLoopExpr> | |
8337 | Parser<ManagedTokenSource>::parse_labelled_loop_expr (AST::AttrVec outer_attrs) | |
8338 | { | |
8339 | /* TODO: decide whether it should not work if there is no label, or parse it | |
8340 | * with no label at the moment, I will make it not work with no label | |
8341 | * because that's the implication. */ | |
8342 | ||
8343 | if (lexer.peek_token ()->get_id () != LIFETIME) | |
8344 | { | |
8345 | Error error (lexer.peek_token ()->get_locus (), | |
8346 | "expected lifetime in labelled loop expr (to parse loop " | |
8347 | "label) - found %qs", | |
8348 | lexer.peek_token ()->get_token_description ()); | |
8349 | add_error (std::move (error)); | |
8350 | ||
8351 | // skip? | |
8352 | return nullptr; | |
8353 | } | |
8354 | ||
8355 | // parse loop label (required) | |
8356 | AST::LoopLabel label = parse_loop_label (); | |
8357 | if (label.is_error ()) | |
8358 | { | |
8359 | Error error (lexer.peek_token ()->get_locus (), | |
8360 | "failed to parse loop label in labelled loop expr"); | |
8361 | add_error (std::move (error)); | |
8362 | ||
8363 | // skip? | |
8364 | return nullptr; | |
8365 | } | |
8366 | ||
8367 | // branch on next token | |
8368 | const_TokenPtr t = lexer.peek_token (); | |
8369 | switch (t->get_id ()) | |
8370 | { | |
8371 | case LOOP: | |
8372 | return parse_loop_expr (std::move (outer_attrs), std::move (label)); | |
8373 | case FOR: | |
8374 | return parse_for_loop_expr (std::move (outer_attrs), std::move (label)); | |
8375 | case WHILE: | |
8376 | // further disambiguate into while vs while let | |
8377 | if (lexer.peek_token (1)->get_id () == LET) | |
8378 | { | |
8379 | return parse_while_let_loop_expr (std::move (outer_attrs), | |
8380 | std::move (label)); | |
8381 | } | |
8382 | else | |
8383 | { | |
8384 | return parse_while_loop_expr (std::move (outer_attrs), | |
8385 | std::move (label)); | |
8386 | } | |
8387 | default: | |
8388 | // error | |
8389 | add_error (Error (t->get_locus (), | |
8390 | "unexpected token %qs when parsing labelled loop", | |
8391 | t->get_token_description ())); | |
8392 | ||
8393 | // skip? | |
8394 | return nullptr; | |
8395 | } | |
8396 | } | |
8397 | ||
8398 | // Parses a match expression. | |
8399 | template <typename ManagedTokenSource> | |
8400 | std::unique_ptr<AST::MatchExpr> | |
8401 | Parser<ManagedTokenSource>::parse_match_expr (AST::AttrVec outer_attrs, | |
8402 | Location pratt_parsed_loc) | |
8403 | { | |
8404 | Location locus = pratt_parsed_loc; | |
8405 | if (locus == Linemap::unknown_location ()) | |
8406 | { | |
8407 | locus = lexer.peek_token ()->get_locus (); | |
8408 | skip_token (MATCH_TOK); | |
8409 | } | |
8410 | ||
8411 | /* parse scrutinee expression, which is required (and HACK to prevent struct | |
8412 | * expr) */ | |
8413 | ParseRestrictions no_struct_expr; | |
8414 | no_struct_expr.can_be_struct_expr = false; | |
8415 | std::unique_ptr<AST::Expr> scrutinee = parse_expr ({}, no_struct_expr); | |
8416 | if (scrutinee == nullptr) | |
8417 | { | |
8418 | Error error (lexer.peek_token ()->get_locus (), | |
8419 | "failed to parse scrutinee expression in match expression"); | |
8420 | add_error (std::move (error)); | |
8421 | ||
8422 | // skip somewhere? | |
8423 | return nullptr; | |
8424 | } | |
8425 | /* TODO: check for scrutinee expr not being struct expr? or do so in | |
8426 | * semantic analysis */ | |
8427 | ||
8428 | if (!skip_token (LEFT_CURLY)) | |
8429 | { | |
8430 | // skip somewhere? | |
8431 | return nullptr; | |
8432 | } | |
8433 | ||
8434 | // parse inner attributes (if they exist) | |
8435 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
8436 | ||
8437 | // parse match arms (if they exist) | |
8438 | // std::vector<std::unique_ptr<AST::MatchCase> > match_arms; | |
8439 | std::vector<AST::MatchCase> match_arms; | |
8440 | ||
8441 | // parse match cases | |
8442 | while (lexer.peek_token ()->get_id () != RIGHT_CURLY) | |
8443 | { | |
8444 | // parse match arm itself, which is required | |
8445 | AST::MatchArm arm = parse_match_arm (); | |
8446 | if (arm.is_error ()) | |
8447 | { | |
8448 | // TODO is this worth throwing everything away? | |
8449 | Error error (lexer.peek_token ()->get_locus (), | |
8450 | "failed to parse match arm in match arms"); | |
8451 | add_error (std::move (error)); | |
8452 | ||
8453 | return nullptr; | |
8454 | } | |
8455 | ||
8456 | if (!skip_token (MATCH_ARROW)) | |
8457 | { | |
8458 | // skip after somewhere? | |
8459 | // TODO is returning here a good idea? or is break better? | |
8460 | return nullptr; | |
8461 | } | |
8462 | ||
8463 | ParseRestrictions restrictions; | |
8464 | restrictions.expr_can_be_stmt = true; | |
8465 | restrictions.consume_semi = false; | |
8466 | ||
8467 | std::unique_ptr<AST::ExprStmt> expr = parse_expr_stmt ({}, restrictions); | |
8468 | if (expr == nullptr) | |
8469 | { | |
8470 | Error error (lexer.peek_token ()->get_locus (), | |
8471 | "failed to parse expr in match arm in match expr"); | |
8472 | add_error (std::move (error)); | |
8473 | ||
8474 | // skip somewhere? | |
8475 | return nullptr; | |
8476 | } | |
8477 | bool is_expr_without_block | |
8478 | = expr->get_type () == AST::ExprStmt::ExprStmtType::WITHOUT_BLOCK; | |
8479 | ||
8480 | // construct match case expr and add to cases | |
8481 | switch (expr->get_type ()) | |
8482 | { | |
8483 | case AST::ExprStmt::ExprStmtType::WITH_BLOCK: { | |
8484 | AST::ExprStmtWithBlock *cast | |
8485 | = static_cast<AST::ExprStmtWithBlock *> (expr.get ()); | |
8486 | std::unique_ptr<AST::Expr> e = cast->get_expr ()->clone_expr (); | |
8487 | match_arms.push_back ( | |
8488 | AST::MatchCase (std::move (arm), std::move (e))); | |
8489 | } | |
8490 | break; | |
8491 | ||
8492 | case AST::ExprStmt::ExprStmtType::WITHOUT_BLOCK: { | |
8493 | AST::ExprStmtWithoutBlock *cast | |
8494 | = static_cast<AST::ExprStmtWithoutBlock *> (expr.get ()); | |
8495 | std::unique_ptr<AST::Expr> e = cast->get_expr ()->clone_expr (); | |
8496 | match_arms.push_back ( | |
8497 | AST::MatchCase (std::move (arm), std::move (e))); | |
8498 | } | |
8499 | break; | |
8500 | } | |
8501 | ||
8502 | // handle comma presence | |
8503 | if (lexer.peek_token ()->get_id () != COMMA) | |
8504 | { | |
8505 | if (!is_expr_without_block) | |
8506 | { | |
8507 | // allowed even if not final case | |
8508 | continue; | |
8509 | } | |
8510 | else if (is_expr_without_block | |
8511 | && lexer.peek_token ()->get_id () != RIGHT_CURLY) | |
8512 | { | |
8513 | // not allowed if not final case | |
8514 | Error error (lexer.peek_token ()->get_locus (), | |
8515 | "exprwithoutblock requires comma after match case " | |
8516 | "expression in match arm (if not final case)"); | |
8517 | add_error (std::move (error)); | |
8518 | ||
8519 | return nullptr; | |
8520 | } | |
8521 | else | |
8522 | { | |
8523 | // otherwise, must be final case, so fine | |
8524 | break; | |
8525 | } | |
8526 | } | |
8527 | lexer.skip_token (); | |
8528 | } | |
8529 | ||
8530 | if (!skip_token (RIGHT_CURLY)) | |
8531 | { | |
8532 | // skip somewhere? | |
8533 | return nullptr; | |
8534 | } | |
8535 | ||
8536 | match_arms.shrink_to_fit (); | |
8537 | ||
8538 | return std::unique_ptr<AST::MatchExpr> ( | |
8539 | new AST::MatchExpr (std::move (scrutinee), std::move (match_arms), | |
8540 | std::move (inner_attrs), std::move (outer_attrs), | |
8541 | locus)); | |
8542 | } | |
8543 | ||
8544 | // Parses the "pattern" part of the match arm (the 'case x:' equivalent). | |
8545 | template <typename ManagedTokenSource> | |
8546 | AST::MatchArm | |
8547 | Parser<ManagedTokenSource>::parse_match_arm () | |
8548 | { | |
8549 | // parse optional outer attributes | |
8550 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
8551 | ||
8552 | // DEBUG | |
8553 | rust_debug ("about to start parsing match arm patterns"); | |
8554 | ||
8555 | // break early if find right curly | |
8556 | if (lexer.peek_token ()->get_id () == RIGHT_CURLY) | |
8557 | { | |
8558 | // not an error | |
8559 | return AST::MatchArm::create_error (); | |
8560 | } | |
8561 | ||
8562 | // parse match arm patterns - at least 1 is required | |
8563 | std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns | |
8564 | = parse_match_arm_patterns (RIGHT_CURLY); | |
8565 | if (match_arm_patterns.empty ()) | |
8566 | { | |
8567 | Error error (lexer.peek_token ()->get_locus (), | |
8568 | "failed to parse any patterns in match arm"); | |
8569 | add_error (std::move (error)); | |
8570 | ||
8571 | // skip somewhere? | |
8572 | return AST::MatchArm::create_error (); | |
8573 | } | |
8574 | ||
8575 | // DEBUG | |
8576 | rust_debug ("successfully parsed match arm patterns"); | |
8577 | ||
8578 | // parse match arm guard expr if it exists | |
8579 | std::unique_ptr<AST::Expr> guard_expr = nullptr; | |
8580 | if (lexer.peek_token ()->get_id () == IF) | |
8581 | { | |
8582 | lexer.skip_token (); | |
8583 | ||
8584 | guard_expr = parse_expr (); | |
8585 | if (guard_expr == nullptr) | |
8586 | { | |
8587 | Error error (lexer.peek_token ()->get_locus (), | |
8588 | "failed to parse guard expression in match arm"); | |
8589 | add_error (std::move (error)); | |
8590 | ||
8591 | // skip somewhere? | |
8592 | return AST::MatchArm::create_error (); | |
8593 | } | |
8594 | } | |
8595 | ||
8596 | // DEBUG | |
8597 | rust_debug ("successfully parsed match arm"); | |
8598 | ||
8599 | return AST::MatchArm (std::move (match_arm_patterns), | |
8600 | lexer.peek_token ()->get_locus (), | |
8601 | std::move (guard_expr), std::move (outer_attrs)); | |
8602 | } | |
8603 | ||
8604 | /* Parses the patterns used in a match arm. End token id is the id of the | |
8605 | * token that would exist after the patterns are done (e.g. '}' for match | |
8606 | * expr, '=' for if let and while let). */ | |
8607 | template <typename ManagedTokenSource> | |
8608 | std::vector<std::unique_ptr<AST::Pattern>> | |
8609 | Parser<ManagedTokenSource>::parse_match_arm_patterns (TokenId end_token_id) | |
8610 | { | |
8611 | // skip optional leading '|' | |
8612 | if (lexer.peek_token ()->get_id () == PIPE) | |
8613 | lexer.skip_token (); | |
8614 | /* TODO: do I even need to store the result of this? can't be used. | |
8615 | * If semantically different, I need a wrapped "match arm patterns" object | |
8616 | * for this. */ | |
8617 | ||
8618 | std::vector<std::unique_ptr<AST::Pattern>> patterns; | |
8619 | ||
8620 | // quick break out if end_token_id | |
8621 | if (lexer.peek_token ()->get_id () == end_token_id) | |
8622 | return patterns; | |
8623 | ||
8624 | // parse required pattern - if doesn't exist, return empty | |
8625 | std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern (); | |
8626 | if (initial_pattern == nullptr) | |
8627 | { | |
8628 | // FIXME: should this be an error? | |
8629 | return patterns; | |
8630 | } | |
8631 | patterns.push_back (std::move (initial_pattern)); | |
8632 | ||
8633 | // DEBUG | |
8634 | rust_debug ("successfully parsed initial match arm pattern"); | |
8635 | ||
8636 | // parse new patterns as long as next char is '|' | |
8637 | const_TokenPtr t = lexer.peek_token (); | |
8638 | while (t->get_id () == PIPE) | |
8639 | { | |
8640 | // skip pipe token | |
8641 | lexer.skip_token (); | |
8642 | ||
8643 | // break if hit end token id | |
8644 | if (lexer.peek_token ()->get_id () == end_token_id) | |
8645 | break; | |
8646 | ||
8647 | // parse pattern | |
8648 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
8649 | if (pattern == nullptr) | |
8650 | { | |
8651 | // this is an error | |
8652 | Error error (lexer.peek_token ()->get_locus (), | |
8653 | "failed to parse pattern in match arm patterns"); | |
8654 | add_error (std::move (error)); | |
8655 | ||
8656 | // skip somewhere? | |
8657 | return {}; | |
8658 | } | |
8659 | ||
8660 | patterns.push_back (std::move (pattern)); | |
8661 | ||
8662 | t = lexer.peek_token (); | |
8663 | } | |
8664 | ||
8665 | patterns.shrink_to_fit (); | |
8666 | ||
8667 | return patterns; | |
8668 | } | |
8669 | ||
8670 | // Parses an async block expression. | |
8671 | template <typename ManagedTokenSource> | |
8672 | std::unique_ptr<AST::AsyncBlockExpr> | |
8673 | Parser<ManagedTokenSource>::parse_async_block_expr (AST::AttrVec outer_attrs) | |
8674 | { | |
8675 | Location locus = lexer.peek_token ()->get_locus (); | |
8676 | skip_token (ASYNC); | |
8677 | ||
8678 | // detect optional move token | |
8679 | bool has_move = false; | |
8680 | if (lexer.peek_token ()->get_id () == MOVE) | |
8681 | { | |
8682 | lexer.skip_token (); | |
8683 | has_move = true; | |
8684 | } | |
8685 | ||
8686 | // parse block expression (required) | |
8687 | std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr (); | |
8688 | if (block_expr == nullptr) | |
8689 | { | |
8690 | Error error ( | |
8691 | lexer.peek_token ()->get_locus (), | |
8692 | "failed to parse block expression of async block expression"); | |
8693 | add_error (std::move (error)); | |
8694 | ||
8695 | // skip somewhere? | |
8696 | return nullptr; | |
8697 | } | |
8698 | ||
8699 | return std::unique_ptr<AST::AsyncBlockExpr> ( | |
8700 | new AST::AsyncBlockExpr (std::move (block_expr), has_move, | |
8701 | std::move (outer_attrs), locus)); | |
8702 | } | |
8703 | ||
8704 | // Parses an unsafe block expression. | |
8705 | template <typename ManagedTokenSource> | |
8706 | std::unique_ptr<AST::UnsafeBlockExpr> | |
8707 | Parser<ManagedTokenSource>::parse_unsafe_block_expr (AST::AttrVec outer_attrs, | |
8708 | Location pratt_parsed_loc) | |
8709 | { | |
8710 | Location locus = pratt_parsed_loc; | |
8711 | if (locus == Linemap::unknown_location ()) | |
8712 | { | |
8713 | locus = lexer.peek_token ()->get_locus (); | |
8714 | skip_token (UNSAFE); | |
8715 | } | |
8716 | ||
8717 | // parse block expression (required) | |
8718 | std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr (); | |
8719 | if (block_expr == nullptr) | |
8720 | { | |
8721 | Error error ( | |
8722 | lexer.peek_token ()->get_locus (), | |
8723 | "failed to parse block expression of unsafe block expression"); | |
8724 | add_error (std::move (error)); | |
8725 | ||
8726 | // skip somewhere? | |
8727 | return nullptr; | |
8728 | } | |
8729 | ||
8730 | return std::unique_ptr<AST::UnsafeBlockExpr> ( | |
8731 | new AST::UnsafeBlockExpr (std::move (block_expr), std::move (outer_attrs), | |
8732 | locus)); | |
8733 | } | |
8734 | ||
8735 | // Parses an array definition expression. | |
8736 | template <typename ManagedTokenSource> | |
8737 | std::unique_ptr<AST::ArrayExpr> | |
8738 | Parser<ManagedTokenSource>::parse_array_expr (AST::AttrVec outer_attrs, | |
8739 | Location pratt_parsed_loc) | |
8740 | { | |
8741 | Location locus = pratt_parsed_loc; | |
8742 | if (locus == Linemap::unknown_location ()) | |
8743 | { | |
8744 | locus = lexer.peek_token ()->get_locus (); | |
8745 | skip_token (LEFT_SQUARE); | |
8746 | } | |
8747 | ||
8748 | // parse optional inner attributes | |
8749 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
8750 | ||
8751 | // parse the "array elements" section, which is optional | |
8752 | if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) | |
8753 | { | |
8754 | // no array elements | |
8755 | lexer.skip_token (); | |
8756 | ||
8757 | std::vector<std::unique_ptr<AST::Expr>> exprs; | |
8758 | auto array_elems | |
8759 | = Rust::make_unique<AST::ArrayElemsValues> (std::move (exprs), locus); | |
8760 | return Rust::make_unique<AST::ArrayExpr> (std::move (array_elems), | |
8761 | std::move (inner_attrs), | |
8762 | std::move (outer_attrs), locus); | |
8763 | } | |
8764 | else | |
8765 | { | |
8766 | // should have array elements | |
8767 | // parse initial expression, which is required for either | |
8768 | std::unique_ptr<AST::Expr> initial_expr = parse_expr (); | |
8769 | if (initial_expr == nullptr) | |
8770 | { | |
8771 | Error error (lexer.peek_token ()->get_locus (), | |
8772 | "could not parse expression in array expression " | |
8773 | "(even though arrayelems seems to be present)"); | |
8774 | add_error (std::move (error)); | |
8775 | ||
8776 | // skip somewhere? | |
8777 | return nullptr; | |
8778 | } | |
8779 | ||
8780 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
8781 | { | |
8782 | // copy array elems | |
8783 | lexer.skip_token (); | |
8784 | ||
8785 | // parse copy amount expression (required) | |
8786 | std::unique_ptr<AST::Expr> copy_amount = parse_expr (); | |
8787 | if (copy_amount == nullptr) | |
8788 | { | |
8789 | Error error (lexer.peek_token ()->get_locus (), | |
8790 | "could not parse copy amount expression in array " | |
8791 | "expression (arrayelems)"); | |
8792 | add_error (std::move (error)); | |
8793 | ||
8794 | // skip somewhere? | |
8795 | return nullptr; | |
8796 | } | |
8797 | ||
8798 | skip_token (RIGHT_SQUARE); | |
8799 | ||
8800 | std::unique_ptr<AST::ArrayElemsCopied> copied_array_elems ( | |
8801 | new AST::ArrayElemsCopied (std::move (initial_expr), | |
8802 | std::move (copy_amount), locus)); | |
8803 | return std::unique_ptr<AST::ArrayExpr> ( | |
8804 | new AST::ArrayExpr (std::move (copied_array_elems), | |
8805 | std::move (inner_attrs), | |
8806 | std::move (outer_attrs), locus)); | |
8807 | } | |
8808 | else if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) | |
8809 | { | |
8810 | // single-element array expression | |
8811 | std::vector<std::unique_ptr<AST::Expr>> exprs; | |
8812 | exprs.reserve (1); | |
8813 | exprs.push_back (std::move (initial_expr)); | |
8814 | exprs.shrink_to_fit (); | |
8815 | ||
8816 | skip_token (RIGHT_SQUARE); | |
8817 | ||
8818 | std::unique_ptr<AST::ArrayElemsValues> array_elems ( | |
8819 | new AST::ArrayElemsValues (std::move (exprs), locus)); | |
8820 | return std::unique_ptr<AST::ArrayExpr> ( | |
8821 | new AST::ArrayExpr (std::move (array_elems), | |
8822 | std::move (inner_attrs), | |
8823 | std::move (outer_attrs), locus)); | |
8824 | } | |
8825 | else if (lexer.peek_token ()->get_id () == COMMA) | |
8826 | { | |
8827 | // multi-element array expression (or trailing comma) | |
8828 | std::vector<std::unique_ptr<AST::Expr>> exprs; | |
8829 | exprs.push_back (std::move (initial_expr)); | |
8830 | ||
8831 | const_TokenPtr t = lexer.peek_token (); | |
8832 | while (t->get_id () == COMMA) | |
8833 | { | |
8834 | lexer.skip_token (); | |
8835 | ||
8836 | // quick break if right square bracket | |
8837 | if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) | |
8838 | break; | |
8839 | ||
8840 | // parse expression (required) | |
8841 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
8842 | if (expr == nullptr) | |
8843 | { | |
8844 | Error error (lexer.peek_token ()->get_locus (), | |
8845 | "failed to parse element in array expression"); | |
8846 | add_error (std::move (error)); | |
8847 | ||
8848 | // skip somewhere? | |
8849 | return nullptr; | |
8850 | } | |
8851 | exprs.push_back (std::move (expr)); | |
8852 | ||
8853 | t = lexer.peek_token (); | |
8854 | } | |
8855 | ||
8856 | skip_token (RIGHT_SQUARE); | |
8857 | ||
8858 | exprs.shrink_to_fit (); | |
8859 | ||
8860 | std::unique_ptr<AST::ArrayElemsValues> array_elems ( | |
8861 | new AST::ArrayElemsValues (std::move (exprs), locus)); | |
8862 | return std::unique_ptr<AST::ArrayExpr> ( | |
8863 | new AST::ArrayExpr (std::move (array_elems), | |
8864 | std::move (inner_attrs), | |
8865 | std::move (outer_attrs), locus)); | |
8866 | } | |
8867 | else | |
8868 | { | |
8869 | // error | |
8870 | Error error (lexer.peek_token ()->get_locus (), | |
8871 | "unexpected token %qs in array expression (arrayelems)", | |
8872 | lexer.peek_token ()->get_token_description ()); | |
8873 | add_error (std::move (error)); | |
8874 | ||
8875 | // skip somewhere? | |
8876 | return nullptr; | |
8877 | } | |
8878 | } | |
8879 | } | |
8880 | ||
8881 | // Parses a single parameter used in a closure definition. | |
8882 | template <typename ManagedTokenSource> | |
8883 | AST::ClosureParam | |
8884 | Parser<ManagedTokenSource>::parse_closure_param () | |
8885 | { | |
8886 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
8887 | ||
8888 | // parse pattern (which is required) | |
8889 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
8890 | if (pattern == nullptr) | |
8891 | { | |
8892 | // not necessarily an error | |
8893 | return AST::ClosureParam::create_error (); | |
8894 | } | |
8895 | ||
8896 | // parse optional type of param | |
8897 | std::unique_ptr<AST::Type> type = nullptr; | |
8898 | if (lexer.peek_token ()->get_id () == COLON) | |
8899 | { | |
8900 | lexer.skip_token (); | |
8901 | ||
8902 | // parse type, which is now required | |
8903 | type = parse_type (); | |
8904 | if (type == nullptr) | |
8905 | { | |
8906 | Error error (lexer.peek_token ()->get_locus (), | |
8907 | "failed to parse type in closure parameter"); | |
8908 | add_error (std::move (error)); | |
8909 | ||
8910 | // skip somewhere? | |
8911 | return AST::ClosureParam::create_error (); | |
8912 | } | |
8913 | } | |
8914 | ||
95dc1147 JJ |
8915 | Location loc = pattern->get_locus (); |
8916 | return AST::ClosureParam (std::move (pattern), loc, std::move (type), | |
8917 | std::move (outer_attrs)); | |
32c8fb0e JP |
8918 | } |
8919 | ||
8920 | // Parses a grouped or tuple expression (disambiguates). | |
8921 | template <typename ManagedTokenSource> | |
8922 | std::unique_ptr<AST::ExprWithoutBlock> | |
8923 | Parser<ManagedTokenSource>::parse_grouped_or_tuple_expr ( | |
8924 | AST::AttrVec outer_attrs, Location pratt_parsed_loc) | |
8925 | { | |
8926 | // adjustment to allow Pratt parsing to reuse function without copy-paste | |
8927 | Location locus = pratt_parsed_loc; | |
8928 | if (locus == Linemap::unknown_location ()) | |
8929 | { | |
8930 | locus = lexer.peek_token ()->get_locus (); | |
8931 | skip_token (LEFT_PAREN); | |
8932 | } | |
8933 | ||
8934 | // parse optional inner attributes | |
8935 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
8936 | ||
8937 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
8938 | { | |
8939 | // must be empty tuple | |
8940 | lexer.skip_token (); | |
8941 | ||
8942 | // create tuple with empty tuple elems | |
8943 | return std::unique_ptr<AST::TupleExpr> ( | |
8944 | new AST::TupleExpr (std::vector<std::unique_ptr<AST::Expr>> (), | |
8945 | std::move (inner_attrs), std::move (outer_attrs), | |
8946 | locus)); | |
8947 | } | |
8948 | ||
8949 | // parse first expression (required) | |
8950 | std::unique_ptr<AST::Expr> first_expr = parse_expr (); | |
8951 | if (first_expr == nullptr) | |
8952 | { | |
8953 | Error error (lexer.peek_token ()->get_locus (), | |
8954 | "failed to parse expression in grouped or tuple expression"); | |
8955 | add_error (std::move (error)); | |
8956 | ||
8957 | // skip after somewhere? | |
8958 | return nullptr; | |
8959 | } | |
8960 | ||
8961 | // detect whether grouped expression with right parentheses as next token | |
8962 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
8963 | { | |
8964 | // must be grouped expr | |
8965 | lexer.skip_token (); | |
8966 | ||
8967 | // create grouped expr | |
8968 | return std::unique_ptr<AST::GroupedExpr> ( | |
8969 | new AST::GroupedExpr (std::move (first_expr), std::move (inner_attrs), | |
8970 | std::move (outer_attrs), locus)); | |
8971 | } | |
8972 | else if (lexer.peek_token ()->get_id () == COMMA) | |
8973 | { | |
8974 | // tuple expr | |
8975 | std::vector<std::unique_ptr<AST::Expr>> exprs; | |
8976 | exprs.push_back (std::move (first_expr)); | |
8977 | ||
8978 | // parse potential other tuple exprs | |
8979 | const_TokenPtr t = lexer.peek_token (); | |
8980 | while (t->get_id () == COMMA) | |
8981 | { | |
8982 | lexer.skip_token (); | |
8983 | ||
8984 | // break out if right paren | |
8985 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
8986 | break; | |
8987 | ||
8988 | // parse expr, which is now required | |
8989 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
8990 | if (expr == nullptr) | |
8991 | { | |
8992 | Error error (lexer.peek_token ()->get_locus (), | |
8993 | "failed to parse expr in tuple expr"); | |
8994 | add_error (std::move (error)); | |
8995 | ||
8996 | // skip somewhere? | |
8997 | return nullptr; | |
8998 | } | |
8999 | exprs.push_back (std::move (expr)); | |
9000 | ||
9001 | t = lexer.peek_token (); | |
9002 | } | |
9003 | ||
9004 | // skip right paren | |
9005 | skip_token (RIGHT_PAREN); | |
9006 | ||
9007 | return std::unique_ptr<AST::TupleExpr> ( | |
9008 | new AST::TupleExpr (std::move (exprs), std::move (inner_attrs), | |
9009 | std::move (outer_attrs), locus)); | |
9010 | } | |
9011 | else | |
9012 | { | |
9013 | // error | |
9014 | const_TokenPtr t = lexer.peek_token (); | |
9015 | Error error (t->get_locus (), | |
9016 | "unexpected token %qs in grouped or tuple expression " | |
9017 | "(parenthesised expression) - expected %<)%> for grouped " | |
9018 | "expr and %<,%> for tuple expr", | |
9019 | t->get_token_description ()); | |
9020 | add_error (std::move (error)); | |
9021 | ||
9022 | // skip somewhere? | |
9023 | return nullptr; | |
9024 | } | |
9025 | } | |
9026 | ||
9027 | // Parses a type (will further disambiguate any type). | |
9028 | template <typename ManagedTokenSource> | |
9029 | std::unique_ptr<AST::Type> | |
9030 | Parser<ManagedTokenSource>::parse_type (bool save_errors) | |
9031 | { | |
9032 | /* rules for all types: | |
9033 | * NeverType: '!' | |
9034 | * SliceType: '[' Type ']' | |
9035 | * InferredType: '_' | |
9036 | * MacroInvocation: SimplePath '!' DelimTokenTree | |
9037 | * ParenthesisedType: '(' Type ')' | |
9038 | * ImplTraitType: 'impl' TypeParamBounds | |
9039 | * TypeParamBounds (not type) TypeParamBound ( '+' TypeParamBound )* '+'? | |
9040 | * TypeParamBound Lifetime | TraitBound | |
9041 | * ImplTraitTypeOneBound: 'impl' TraitBound | |
9042 | * TraitObjectType: 'dyn'? TypeParamBounds | |
9043 | * TraitObjectTypeOneBound: 'dyn'? TraitBound | |
9044 | * TraitBound '?'? ForLifetimes? TypePath | '(' '?'? | |
9045 | * ForLifetimes? TypePath ')' BareFunctionType: ForLifetimes? | |
9046 | * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<' | |
9047 | * LifetimeParams '>' FunctionQualifiers ( 'async' | 'const' )? | |
9048 | * 'unsafe'? | |
9049 | * ('extern' abi?)? QualifiedPathInType: '<' Type ( 'as' TypePath )? '>' | |
9050 | * ( | |
9051 | * '::' TypePathSegment )+ TypePath: '::'? TypePathSegment ( | |
9052 | * '::' TypePathSegment)* ArrayType: '[' Type ';' Expr ']' | |
9053 | * ReferenceType: '&' Lifetime? 'mut'? TypeNoBounds | |
9054 | * RawPointerType: '*' ( 'mut' | 'const' ) TypeNoBounds | |
9055 | * TupleType: '(' Type etc. - regular tuple stuff. Also | |
9056 | * regular tuple vs parenthesised precedence | |
9057 | * | |
9058 | * Disambiguate between macro and type path via type path being parsed, and | |
9059 | * then if '!' found, convert type path to simple path for macro. Usual | |
9060 | * disambiguation for tuple vs parenthesised. For ImplTraitType and | |
9061 | * TraitObjectType individual disambiguations, they seem more like "special | |
9062 | * cases", so probably just try to parse the more general ImplTraitType or | |
9063 | * TraitObjectType and return OneBound versions if they satisfy those | |
9064 | * criteria. */ | |
9065 | ||
9066 | const_TokenPtr t = lexer.peek_token (); | |
9067 | switch (t->get_id ()) | |
9068 | { | |
9069 | case EXCLAM: | |
9070 | // never type - can't be macro as no path beforehand | |
9071 | lexer.skip_token (); | |
9072 | return std::unique_ptr<AST::NeverType> ( | |
9073 | new AST::NeverType (t->get_locus ())); | |
9074 | case LEFT_SQUARE: | |
9075 | // slice type or array type - requires further disambiguation | |
9076 | return parse_slice_or_array_type (); | |
9077 | case LEFT_ANGLE: { | |
9078 | // qualified path in type | |
9079 | AST::QualifiedPathInType path = parse_qualified_path_in_type (); | |
9080 | if (path.is_error ()) | |
9081 | { | |
9082 | if (save_errors) | |
9083 | { | |
9084 | Error error (t->get_locus (), | |
9085 | "failed to parse qualified path in type"); | |
9086 | add_error (std::move (error)); | |
9087 | } | |
9088 | ||
9089 | return nullptr; | |
9090 | } | |
9091 | return std::unique_ptr<AST::QualifiedPathInType> ( | |
9092 | new AST::QualifiedPathInType (std::move (path))); | |
9093 | } | |
9094 | case UNDERSCORE: | |
9095 | // inferred type | |
9096 | lexer.skip_token (); | |
9097 | return std::unique_ptr<AST::InferredType> ( | |
9098 | new AST::InferredType (t->get_locus ())); | |
9099 | case ASTERISK: | |
9100 | // raw pointer type | |
9101 | return parse_raw_pointer_type (); | |
9102 | case AMP: // does this also include AMP_AMP? | |
9103 | // reference type | |
9104 | return parse_reference_type (); | |
9105 | case LIFETIME: { | |
9106 | /* probably a lifetime bound, so probably type param bounds in | |
9107 | * TraitObjectType */ | |
9108 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds | |
9109 | = parse_type_param_bounds (); | |
9110 | ||
9111 | return std::unique_ptr<AST::TraitObjectType> ( | |
9112 | new AST::TraitObjectType (std::move (bounds), t->get_locus (), | |
9113 | false)); | |
9114 | } | |
9115 | case IDENTIFIER: | |
9116 | case SUPER: | |
9117 | case SELF: | |
9118 | case SELF_ALIAS: | |
9119 | case CRATE: | |
9120 | case DOLLAR_SIGN: | |
9121 | case SCOPE_RESOLUTION: { | |
9122 | // macro invocation or type path - requires further disambiguation. | |
9123 | /* for parsing path component of each rule, perhaps parse it as a | |
9124 | * typepath and attempt conversion to simplepath if a trailing '!' is | |
9125 | * found */ | |
9126 | /* Type path also includes TraitObjectTypeOneBound BUT if it starts | |
9127 | * with it, it is exactly the same as a TypePath syntactically, so | |
9128 | * this is a syntactical ambiguity. As such, the parser will parse it | |
9129 | * as a TypePath. This, however, does not prevent TraitObjectType from | |
9130 | * starting with a typepath. */ | |
9131 | ||
9132 | // parse path as type path | |
9133 | AST::TypePath path = parse_type_path (); | |
9134 | if (path.is_error ()) | |
9135 | { | |
9136 | if (save_errors) | |
9137 | { | |
9138 | Error error (t->get_locus (), | |
9139 | "failed to parse path as first component of type"); | |
9140 | add_error (std::move (error)); | |
9141 | } | |
9142 | ||
9143 | return nullptr; | |
9144 | } | |
9145 | Location locus = path.get_locus (); | |
9146 | ||
9147 | // branch on next token | |
9148 | t = lexer.peek_token (); | |
9149 | switch (t->get_id ()) | |
9150 | { | |
9151 | case EXCLAM: { | |
9152 | // macro invocation | |
9153 | // convert to simple path | |
9154 | AST::SimplePath macro_path = path.as_simple_path (); | |
9155 | if (macro_path.is_empty ()) | |
9156 | { | |
9157 | if (save_errors) | |
9158 | { | |
9159 | Error error (t->get_locus (), | |
9160 | "failed to parse simple path in macro " | |
9161 | "invocation (for type)"); | |
9162 | add_error (std::move (error)); | |
9163 | } | |
9164 | ||
9165 | return nullptr; | |
9166 | } | |
9167 | ||
9168 | lexer.skip_token (); | |
9169 | ||
9170 | AST::DelimTokenTree tok_tree = parse_delim_token_tree (); | |
9171 | ||
9172 | return std::unique_ptr<AST::MacroInvocation> ( | |
9173 | new AST::MacroInvocation ( | |
9174 | AST::MacroInvocData (std::move (macro_path), | |
9175 | std::move (tok_tree)), | |
9176 | {}, locus)); | |
9177 | } | |
9178 | case PLUS: { | |
9179 | // type param bounds | |
9180 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; | |
9181 | ||
9182 | // convert type path to trait bound | |
9183 | std::unique_ptr<AST::TraitBound> path_bound ( | |
9184 | new AST::TraitBound (std::move (path), locus, false, false)); | |
9185 | bounds.push_back (std::move (path_bound)); | |
9186 | ||
9187 | /* parse rest of bounds - FIXME: better way to find when to stop | |
9188 | * parsing */ | |
9189 | while (t->get_id () == PLUS) | |
9190 | { | |
9191 | lexer.skip_token (); | |
9192 | ||
9193 | // parse bound if it exists - if not, assume end of sequence | |
9194 | std::unique_ptr<AST::TypeParamBound> bound | |
9195 | = parse_type_param_bound (); | |
9196 | if (bound == nullptr) | |
9197 | { | |
9198 | break; | |
9199 | } | |
9200 | bounds.push_back (std::move (bound)); | |
9201 | ||
9202 | t = lexer.peek_token (); | |
9203 | } | |
9204 | ||
9205 | return std::unique_ptr<AST::TraitObjectType> ( | |
9206 | new AST::TraitObjectType (std::move (bounds), locus, false)); | |
9207 | } | |
9208 | default: | |
9209 | // assume that this is a type path and not an error | |
9210 | return std::unique_ptr<AST::TypePath> ( | |
9211 | new AST::TypePath (std::move (path))); | |
9212 | } | |
9213 | } | |
9214 | case LEFT_PAREN: | |
9215 | /* tuple type or parenthesised type - requires further disambiguation | |
9216 | * (the usual). ok apparently can be a parenthesised TraitBound too, so | |
9217 | * could be TraitObjectTypeOneBound or TraitObjectType */ | |
9218 | return parse_paren_prefixed_type (); | |
9219 | case FOR: | |
9220 | // TraitObjectTypeOneBound or BareFunctionType | |
9221 | return parse_for_prefixed_type (); | |
9222 | case ASYNC: | |
9223 | case CONST: | |
9224 | case UNSAFE: | |
9225 | case EXTERN_TOK: | |
9226 | case FN_TOK: | |
9227 | // bare function type (with no for lifetimes) | |
9228 | return parse_bare_function_type (std::vector<AST::LifetimeParam> ()); | |
9229 | case IMPL: | |
9230 | lexer.skip_token (); | |
9231 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
9232 | { | |
9233 | /* cannot be one bound because lifetime prevents it from being | |
9234 | * traitbound */ | |
9235 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds | |
9236 | = parse_type_param_bounds (); | |
9237 | ||
9238 | return std::unique_ptr<AST::ImplTraitType> ( | |
9239 | new AST::ImplTraitType (std::move (bounds), t->get_locus ())); | |
9240 | } | |
9241 | else | |
9242 | { | |
9243 | // should be trait bound, so parse trait bound | |
9244 | std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound (); | |
9245 | if (initial_bound == nullptr) | |
9246 | { | |
9247 | if (save_errors) | |
9248 | { | |
9249 | Error error (lexer.peek_token ()->get_locus (), | |
9250 | "failed to parse ImplTraitType initial bound"); | |
9251 | add_error (std::move (error)); | |
9252 | } | |
9253 | ||
9254 | return nullptr; | |
9255 | } | |
9256 | ||
9257 | Location locus = t->get_locus (); | |
9258 | ||
9259 | // short cut if next token isn't '+' | |
9260 | t = lexer.peek_token (); | |
9261 | if (t->get_id () != PLUS) | |
9262 | { | |
9263 | // convert trait bound to value object | |
9264 | AST::TraitBound value_bound (*initial_bound); | |
9265 | ||
9266 | // DEBUG: removed as unique ptr, so should auto-delete | |
9267 | // delete initial_bound; | |
9268 | ||
9269 | return std::unique_ptr<AST::ImplTraitTypeOneBound> ( | |
9270 | new AST::ImplTraitTypeOneBound (std::move (value_bound), | |
9271 | locus)); | |
9272 | } | |
9273 | ||
9274 | // parse additional type param bounds | |
9275 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; | |
9276 | bounds.push_back (std::move (initial_bound)); | |
9277 | while (t->get_id () == PLUS) | |
9278 | { | |
9279 | lexer.skip_token (); | |
9280 | ||
9281 | // parse bound if it exists | |
9282 | std::unique_ptr<AST::TypeParamBound> bound | |
9283 | = parse_type_param_bound (); | |
9284 | if (bound == nullptr) | |
9285 | { | |
9286 | // not an error as trailing plus may exist | |
9287 | break; | |
9288 | } | |
9289 | bounds.push_back (std::move (bound)); | |
9290 | ||
9291 | t = lexer.peek_token (); | |
9292 | } | |
9293 | ||
9294 | return std::unique_ptr<AST::ImplTraitType> ( | |
9295 | new AST::ImplTraitType (std::move (bounds), locus)); | |
9296 | } | |
9297 | case DYN: | |
9298 | case QUESTION_MARK: { | |
9299 | // either TraitObjectType or TraitObjectTypeOneBound | |
9300 | bool has_dyn = false; | |
9301 | if (t->get_id () == DYN) | |
9302 | { | |
9303 | lexer.skip_token (); | |
9304 | has_dyn = true; | |
9305 | } | |
9306 | ||
9307 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
9308 | { | |
9309 | /* cannot be one bound because lifetime prevents it from being | |
9310 | * traitbound */ | |
9311 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds | |
9312 | = parse_type_param_bounds (); | |
9313 | ||
9314 | return std::unique_ptr<AST::TraitObjectType> ( | |
9315 | new AST::TraitObjectType (std::move (bounds), t->get_locus (), | |
9316 | has_dyn)); | |
9317 | } | |
9318 | else | |
9319 | { | |
9320 | // should be trait bound, so parse trait bound | |
9321 | std::unique_ptr<AST::TraitBound> initial_bound | |
9322 | = parse_trait_bound (); | |
9323 | if (initial_bound == nullptr) | |
9324 | { | |
9325 | if (save_errors) | |
9326 | { | |
9327 | Error error ( | |
9328 | lexer.peek_token ()->get_locus (), | |
9329 | "failed to parse TraitObjectType initial bound"); | |
9330 | add_error (std::move (error)); | |
9331 | } | |
9332 | ||
9333 | return nullptr; | |
9334 | } | |
9335 | ||
9336 | // short cut if next token isn't '+' | |
9337 | t = lexer.peek_token (); | |
9338 | if (t->get_id () != PLUS) | |
9339 | { | |
9340 | // convert trait bound to value object | |
9341 | AST::TraitBound value_bound (*initial_bound); | |
9342 | ||
9343 | // DEBUG: removed as unique ptr, so should auto delete | |
9344 | // delete initial_bound; | |
9345 | ||
9346 | return std::unique_ptr<AST::TraitObjectTypeOneBound> ( | |
9347 | new AST::TraitObjectTypeOneBound (std::move (value_bound), | |
9348 | t->get_locus (), has_dyn)); | |
9349 | } | |
9350 | ||
9351 | // parse additional type param bounds | |
9352 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; | |
9353 | bounds.push_back (std::move (initial_bound)); | |
9354 | while (t->get_id () == PLUS) | |
9355 | { | |
9356 | lexer.skip_token (); | |
9357 | ||
9358 | // parse bound if it exists | |
9359 | std::unique_ptr<AST::TypeParamBound> bound | |
9360 | = parse_type_param_bound (); | |
9361 | if (bound == nullptr) | |
9362 | { | |
9363 | // not an error as trailing plus may exist | |
9364 | break; | |
9365 | } | |
9366 | bounds.push_back (std::move (bound)); | |
9367 | ||
9368 | t = lexer.peek_token (); | |
9369 | } | |
9370 | ||
9371 | return std::unique_ptr<AST::TraitObjectType> ( | |
9372 | new AST::TraitObjectType (std::move (bounds), t->get_locus (), | |
9373 | has_dyn)); | |
9374 | } | |
9375 | } | |
9376 | default: | |
9377 | if (save_errors) | |
9378 | add_error (Error (t->get_locus (), "unrecognised token %qs in type", | |
9379 | t->get_token_description ())); | |
9380 | ||
9381 | return nullptr; | |
9382 | } | |
9383 | } | |
9384 | ||
9385 | /* Parses a type that has '(' as its first character. Returns a tuple type, | |
9386 | * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending | |
9387 | * on following characters. */ | |
9388 | template <typename ManagedTokenSource> | |
9389 | std::unique_ptr<AST::Type> | |
9390 | Parser<ManagedTokenSource>::parse_paren_prefixed_type () | |
9391 | { | |
9392 | /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered | |
9393 | * a trait bound, not a parenthesised type, so that it can still be used in | |
9394 | * type param bounds. */ | |
9395 | ||
9396 | /* NOTE: this implementation is really shit but I couldn't think of a better | |
9397 | * one. It requires essentially breaking polymorphism and downcasting via | |
9398 | * virtual method abuse, as it was copied from the rustc implementation (in | |
9399 | * which types are reified due to tagged union), after a more OOP attempt by | |
9400 | * me failed. */ | |
9401 | Location left_delim_locus = lexer.peek_token ()->get_locus (); | |
9402 | ||
9403 | // skip left delim | |
9404 | lexer.skip_token (); | |
9405 | /* while next token isn't close delim, parse comma-separated types, saving | |
9406 | * whether trailing comma happens */ | |
9407 | const_TokenPtr t = lexer.peek_token (); | |
9408 | bool trailing_comma = true; | |
9409 | std::vector<std::unique_ptr<AST::Type>> types; | |
9410 | ||
9411 | while (t->get_id () != RIGHT_PAREN) | |
9412 | { | |
9413 | std::unique_ptr<AST::Type> type = parse_type (); | |
9414 | if (type == nullptr) | |
9415 | { | |
9416 | Error error (t->get_locus (), | |
9417 | "failed to parse type inside parentheses (probably " | |
9418 | "tuple or parenthesised)"); | |
9419 | add_error (std::move (error)); | |
9420 | ||
9421 | return nullptr; | |
9422 | } | |
9423 | types.push_back (std::move (type)); | |
9424 | ||
9425 | t = lexer.peek_token (); | |
9426 | if (t->get_id () != COMMA) | |
9427 | { | |
9428 | trailing_comma = false; | |
9429 | break; | |
9430 | } | |
9431 | lexer.skip_token (); | |
9432 | ||
9433 | t = lexer.peek_token (); | |
9434 | } | |
9435 | ||
9436 | if (!skip_token (RIGHT_PAREN)) | |
9437 | { | |
9438 | return nullptr; | |
9439 | } | |
9440 | ||
9441 | // if only one type and no trailing comma, then not a tuple type | |
9442 | if (types.size () == 1 && !trailing_comma) | |
9443 | { | |
9444 | // must be a TraitObjectType (with more than one bound) | |
9445 | if (lexer.peek_token ()->get_id () == PLUS) | |
9446 | { | |
9447 | // create type param bounds vector | |
9448 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; | |
9449 | ||
9450 | // HACK: convert type to traitbound and add to bounds | |
9451 | std::unique_ptr<AST::Type> released_ptr = std::move (types[0]); | |
9452 | std::unique_ptr<AST::TraitBound> converted_bound ( | |
9453 | released_ptr->to_trait_bound (true)); | |
9454 | if (converted_bound == nullptr) | |
9455 | { | |
9456 | Error error ( | |
9457 | lexer.peek_token ()->get_locus (), | |
9458 | "failed to hackily converted parsed type to trait bound"); | |
9459 | add_error (std::move (error)); | |
9460 | ||
9461 | return nullptr; | |
9462 | } | |
9463 | bounds.push_back (std::move (converted_bound)); | |
9464 | ||
9465 | t = lexer.peek_token (); | |
9466 | while (t->get_id () == PLUS) | |
9467 | { | |
9468 | lexer.skip_token (); | |
9469 | ||
9470 | // attempt to parse typeparambound | |
9471 | std::unique_ptr<AST::TypeParamBound> bound | |
9472 | = parse_type_param_bound (); | |
9473 | if (bound == nullptr) | |
9474 | { | |
9475 | // not an error if null | |
9476 | break; | |
9477 | } | |
9478 | bounds.push_back (std::move (bound)); | |
9479 | ||
9480 | t = lexer.peek_token (); | |
9481 | } | |
9482 | ||
9483 | return std::unique_ptr<AST::TraitObjectType> ( | |
9484 | new AST::TraitObjectType (std::move (bounds), left_delim_locus, | |
9485 | false)); | |
9486 | } | |
9487 | else | |
9488 | { | |
9489 | // release vector pointer | |
9490 | std::unique_ptr<AST::Type> released_ptr = std::move (types[0]); | |
9491 | /* HACK: attempt to convert to trait bound. if fails, parenthesised | |
9492 | * type */ | |
9493 | std::unique_ptr<AST::TraitBound> converted_bound ( | |
9494 | released_ptr->to_trait_bound (true)); | |
9495 | if (converted_bound == nullptr) | |
9496 | { | |
9497 | // parenthesised type | |
9498 | return std::unique_ptr<AST::ParenthesisedType> ( | |
9499 | new AST::ParenthesisedType (std::move (released_ptr), | |
9500 | left_delim_locus)); | |
9501 | } | |
9502 | else | |
9503 | { | |
9504 | // trait object type (one bound) | |
9505 | ||
9506 | // get value semantics trait bound | |
9507 | AST::TraitBound value_bound (*converted_bound); | |
9508 | ||
9509 | return std::unique_ptr<AST::TraitObjectTypeOneBound> ( | |
9510 | new AST::TraitObjectTypeOneBound (value_bound, | |
9511 | left_delim_locus)); | |
9512 | } | |
9513 | } | |
9514 | } | |
9515 | else | |
9516 | { | |
9517 | return std::unique_ptr<AST::TupleType> ( | |
9518 | new AST::TupleType (std::move (types), left_delim_locus)); | |
9519 | } | |
9520 | /* TODO: ensure that this ensures that dynamic dispatch for traits is not | |
9521 | * lost somehow */ | |
9522 | } | |
9523 | ||
9524 | /* Parses a type that has 'for' as its first character. This means it has a | |
9525 | * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or | |
9526 | * TraitObjectTypeOneBound depending on following characters. */ | |
9527 | template <typename ManagedTokenSource> | |
9528 | std::unique_ptr<AST::Type> | |
9529 | Parser<ManagedTokenSource>::parse_for_prefixed_type () | |
9530 | { | |
9531 | Location for_locus = lexer.peek_token ()->get_locus (); | |
9532 | // parse for lifetimes in type | |
9533 | std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes (); | |
9534 | ||
9535 | // branch on next token - either function or a trait type | |
9536 | const_TokenPtr t = lexer.peek_token (); | |
9537 | switch (t->get_id ()) | |
9538 | { | |
9539 | case ASYNC: | |
9540 | case CONST: | |
9541 | case UNSAFE: | |
9542 | case EXTERN_TOK: | |
9543 | case FN_TOK: | |
9544 | return parse_bare_function_type (std::move (for_lifetimes)); | |
9545 | case SCOPE_RESOLUTION: | |
9546 | case IDENTIFIER: | |
9547 | case SUPER: | |
9548 | case SELF: | |
9549 | case SELF_ALIAS: | |
9550 | case CRATE: | |
9551 | case DOLLAR_SIGN: { | |
9552 | // path, so trait type | |
9553 | ||
9554 | // parse type path to finish parsing trait bound | |
9555 | AST::TypePath path = parse_type_path (); | |
9556 | ||
9557 | t = lexer.peek_token (); | |
9558 | if (t->get_id () != PLUS) | |
9559 | { | |
9560 | // must be one-bound trait type | |
9561 | // create trait bound value object | |
9562 | AST::TraitBound bound (std::move (path), for_locus, false, false, | |
9563 | std::move (for_lifetimes)); | |
9564 | ||
9565 | return std::unique_ptr<AST::TraitObjectTypeOneBound> ( | |
9566 | new AST::TraitObjectTypeOneBound (std::move (bound), for_locus)); | |
9567 | } | |
9568 | ||
9569 | /* more than one bound trait type (or at least parsed as it - could be | |
9570 | * trailing '+') create trait bound pointer and bounds */ | |
9571 | std::unique_ptr<AST::TraitBound> initial_bound ( | |
9572 | new AST::TraitBound (std::move (path), for_locus, false, false, | |
9573 | std::move (for_lifetimes))); | |
9574 | std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; | |
9575 | bounds.push_back (std::move (initial_bound)); | |
9576 | ||
9577 | while (t->get_id () == PLUS) | |
9578 | { | |
9579 | lexer.skip_token (); | |
9580 | ||
9581 | // parse type param bound if it exists | |
9582 | std::unique_ptr<AST::TypeParamBound> bound | |
9583 | = parse_type_param_bound (); | |
9584 | if (bound == nullptr) | |
9585 | { | |
9586 | // not an error - e.g. trailing plus | |
9587 | return nullptr; | |
9588 | } | |
9589 | bounds.push_back (std::move (bound)); | |
9590 | ||
9591 | t = lexer.peek_token (); | |
9592 | } | |
9593 | ||
9594 | return std::unique_ptr<AST::TraitObjectType> ( | |
9595 | new AST::TraitObjectType (std::move (bounds), for_locus, false)); | |
9596 | } | |
9597 | default: | |
9598 | // error | |
9599 | add_error (Error (t->get_locus (), | |
9600 | "unrecognised token %qs in bare function type or trait " | |
9601 | "object type or trait object type one bound", | |
9602 | t->get_token_description ())); | |
9603 | ||
9604 | return nullptr; | |
9605 | } | |
9606 | } | |
9607 | ||
9608 | // Parses a maybe named param used in bare function types. | |
9609 | template <typename ManagedTokenSource> | |
9610 | AST::MaybeNamedParam | |
9611 | Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs) | |
9612 | { | |
9613 | /* Basically guess that param is named if first token is identifier or | |
9614 | * underscore and second token is semicolon. This should probably have no | |
9615 | * exceptions. rustc uses backtracking to parse these, but at the time of | |
9616 | * writing gccrs has no backtracking capabilities. */ | |
9617 | const_TokenPtr current = lexer.peek_token (); | |
9618 | const_TokenPtr next = lexer.peek_token (1); | |
9619 | ||
9620 | Identifier name; | |
9621 | AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED; | |
9622 | ||
9623 | if (current->get_id () == IDENTIFIER && next->get_id () == COLON) | |
9624 | { | |
9625 | // named param | |
9626 | name = current->get_str (); | |
9627 | kind = AST::MaybeNamedParam::IDENTIFIER; | |
9628 | lexer.skip_token (1); | |
9629 | } | |
9630 | else if (current->get_id () == UNDERSCORE && next->get_id () == COLON) | |
9631 | { | |
9632 | // wildcard param | |
9633 | name = "_"; | |
9634 | kind = AST::MaybeNamedParam::WILDCARD; | |
9635 | lexer.skip_token (1); | |
9636 | } | |
9637 | ||
9638 | // parse type (required) | |
9639 | std::unique_ptr<AST::Type> type = parse_type (); | |
9640 | if (type == nullptr) | |
9641 | { | |
9642 | Error error (lexer.peek_token ()->get_locus (), | |
9643 | "failed to parse type in maybe named param"); | |
9644 | add_error (std::move (error)); | |
9645 | ||
9646 | return AST::MaybeNamedParam::create_error (); | |
9647 | } | |
9648 | ||
9649 | return AST::MaybeNamedParam (std::move (name), kind, std::move (type), | |
9650 | std::move (outer_attrs), current->get_locus ()); | |
9651 | } | |
9652 | ||
9653 | /* Parses a bare function type (with the given for lifetimes for convenience - | |
9654 | * does not parse them itself). */ | |
9655 | template <typename ManagedTokenSource> | |
9656 | std::unique_ptr<AST::BareFunctionType> | |
9657 | Parser<ManagedTokenSource>::parse_bare_function_type ( | |
9658 | std::vector<AST::LifetimeParam> for_lifetimes) | |
9659 | { | |
9660 | // TODO: pass in for lifetime location as param | |
9661 | Location best_try_locus = lexer.peek_token ()->get_locus (); | |
9662 | ||
9663 | AST::FunctionQualifiers qualifiers = parse_function_qualifiers (); | |
9664 | ||
9665 | if (!skip_token (FN_TOK)) | |
9666 | return nullptr; | |
9667 | ||
9668 | if (!skip_token (LEFT_PAREN)) | |
9669 | return nullptr; | |
9670 | ||
9671 | // parse function params, if they exist | |
9672 | std::vector<AST::MaybeNamedParam> params; | |
9673 | bool is_variadic = false; | |
9674 | AST::AttrVec variadic_attrs; | |
9675 | ||
9676 | const_TokenPtr t = lexer.peek_token (); | |
9677 | while (t->get_id () != RIGHT_PAREN) | |
9678 | { | |
9679 | AST::AttrVec temp_attrs = parse_outer_attributes (); | |
9680 | ||
9681 | if (lexer.peek_token ()->get_id () == ELLIPSIS) | |
9682 | { | |
9683 | lexer.skip_token (); | |
9684 | is_variadic = true; | |
9685 | variadic_attrs = std::move (temp_attrs); | |
9686 | ||
9687 | t = lexer.peek_token (); | |
9688 | ||
9689 | if (t->get_id () != RIGHT_PAREN) | |
9690 | { | |
9691 | Error error (t->get_locus (), | |
9692 | "expected right parentheses after variadic in maybe " | |
9693 | "named function " | |
9694 | "parameters, found %qs", | |
9695 | t->get_token_description ()); | |
9696 | add_error (std::move (error)); | |
9697 | ||
9698 | return nullptr; | |
9699 | } | |
9700 | ||
9701 | break; | |
9702 | } | |
9703 | ||
9704 | AST::MaybeNamedParam param | |
9705 | = parse_maybe_named_param (std::move (temp_attrs)); | |
9706 | if (param.is_error ()) | |
9707 | { | |
9708 | Error error ( | |
9709 | lexer.peek_token ()->get_locus (), | |
9710 | "failed to parse maybe named param in bare function type"); | |
9711 | add_error (std::move (error)); | |
9712 | ||
9713 | return nullptr; | |
9714 | } | |
9715 | params.push_back (std::move (param)); | |
9716 | ||
9717 | if (lexer.peek_token ()->get_id () != COMMA) | |
9718 | break; | |
9719 | ||
9720 | lexer.skip_token (); | |
9721 | t = lexer.peek_token (); | |
9722 | } | |
9723 | ||
9724 | if (!skip_token (RIGHT_PAREN)) | |
9725 | return nullptr; | |
9726 | ||
9727 | // bare function return type, if exists | |
9728 | std::unique_ptr<AST::TypeNoBounds> return_type = nullptr; | |
9729 | if (lexer.peek_token ()->get_id () == RETURN_TYPE) | |
9730 | { | |
9731 | lexer.skip_token (); | |
9732 | ||
9733 | // parse required TypeNoBounds | |
9734 | return_type = parse_type_no_bounds (); | |
9735 | if (return_type == nullptr) | |
9736 | { | |
9737 | Error error (lexer.peek_token ()->get_locus (), | |
9738 | "failed to parse return type (type no bounds) in bare " | |
9739 | "function type"); | |
9740 | add_error (std::move (error)); | |
9741 | ||
9742 | return nullptr; | |
9743 | } | |
9744 | } | |
9745 | ||
9746 | return std::unique_ptr<AST::BareFunctionType> ( | |
9747 | new AST::BareFunctionType (std::move (for_lifetimes), | |
9748 | std::move (qualifiers), std::move (params), | |
9749 | is_variadic, std::move (variadic_attrs), | |
9750 | std::move (return_type), best_try_locus)); | |
9751 | } | |
9752 | ||
9753 | // Parses a reference type (mutable or immutable, with given lifetime). | |
9754 | template <typename ManagedTokenSource> | |
9755 | std::unique_ptr<AST::ReferenceType> | |
9756 | Parser<ManagedTokenSource>::parse_reference_type () | |
9757 | { | |
9758 | Location locus = lexer.peek_token ()->get_locus (); | |
9759 | skip_token (AMP); | |
9760 | ||
9761 | // parse optional lifetime | |
9762 | AST::Lifetime lifetime = AST::Lifetime::error (); | |
9763 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
9764 | { | |
9765 | lifetime = parse_lifetime (); | |
9766 | if (lifetime.is_error ()) | |
9767 | { | |
9768 | Error error (lexer.peek_token ()->get_locus (), | |
9769 | "failed to parse lifetime in reference type"); | |
9770 | add_error (std::move (error)); | |
9771 | ||
9772 | return nullptr; | |
9773 | } | |
9774 | } | |
9775 | ||
9776 | bool is_mut = false; | |
9777 | if (lexer.peek_token ()->get_id () == MUT) | |
9778 | { | |
9779 | lexer.skip_token (); | |
9780 | is_mut = true; | |
9781 | } | |
9782 | ||
9783 | // parse type no bounds, which is required | |
9784 | std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds (); | |
9785 | if (type == nullptr) | |
9786 | { | |
9787 | Error error (lexer.peek_token ()->get_locus (), | |
9788 | "failed to parse referenced type in reference type"); | |
9789 | add_error (std::move (error)); | |
9790 | ||
9791 | return nullptr; | |
9792 | } | |
9793 | ||
9794 | return std::unique_ptr<AST::ReferenceType> ( | |
9795 | new AST::ReferenceType (is_mut, std::move (type), locus, | |
9796 | std::move (lifetime))); | |
9797 | } | |
9798 | ||
9799 | // Parses a raw (unsafe) pointer type. | |
9800 | template <typename ManagedTokenSource> | |
9801 | std::unique_ptr<AST::RawPointerType> | |
9802 | Parser<ManagedTokenSource>::parse_raw_pointer_type () | |
9803 | { | |
9804 | Location locus = lexer.peek_token ()->get_locus (); | |
9805 | skip_token (ASTERISK); | |
9806 | ||
9807 | AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST; | |
9808 | ||
9809 | // branch on next token for pointer kind info | |
9810 | const_TokenPtr t = lexer.peek_token (); | |
9811 | switch (t->get_id ()) | |
9812 | { | |
9813 | case MUT: | |
9814 | kind = AST::RawPointerType::MUT; | |
9815 | lexer.skip_token (); | |
9816 | break; | |
9817 | case CONST: | |
9818 | kind = AST::RawPointerType::CONST; | |
9819 | lexer.skip_token (); | |
9820 | break; | |
9821 | default: | |
9822 | add_error (Error (t->get_locus (), | |
9823 | "unrecognised token %qs in raw pointer type", | |
9824 | t->get_token_description ())); | |
9825 | ||
9826 | return nullptr; | |
9827 | } | |
9828 | ||
9829 | // parse type no bounds (required) | |
9830 | std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds (); | |
9831 | if (type == nullptr) | |
9832 | { | |
9833 | Error error (lexer.peek_token ()->get_locus (), | |
9834 | "failed to parse pointed type of raw pointer type"); | |
9835 | add_error (std::move (error)); | |
9836 | ||
9837 | return nullptr; | |
9838 | } | |
9839 | ||
9840 | return std::unique_ptr<AST::RawPointerType> ( | |
9841 | new AST::RawPointerType (kind, std::move (type), locus)); | |
9842 | } | |
9843 | ||
9844 | /* Parses a slice or array type, depending on following arguments (as | |
9845 | * lookahead is not possible). */ | |
9846 | template <typename ManagedTokenSource> | |
9847 | std::unique_ptr<AST::TypeNoBounds> | |
9848 | Parser<ManagedTokenSource>::parse_slice_or_array_type () | |
9849 | { | |
9850 | Location locus = lexer.peek_token ()->get_locus (); | |
9851 | skip_token (LEFT_SQUARE); | |
9852 | ||
9853 | // parse inner type (required) | |
9854 | std::unique_ptr<AST::Type> inner_type = parse_type (); | |
9855 | if (inner_type == nullptr) | |
9856 | { | |
9857 | Error error (lexer.peek_token ()->get_locus (), | |
9858 | "failed to parse inner type in slice or array type"); | |
9859 | add_error (std::move (error)); | |
9860 | ||
9861 | return nullptr; | |
9862 | } | |
9863 | ||
9864 | // branch on next token | |
9865 | const_TokenPtr t = lexer.peek_token (); | |
9866 | switch (t->get_id ()) | |
9867 | { | |
9868 | case RIGHT_SQUARE: | |
9869 | // slice type | |
9870 | lexer.skip_token (); | |
9871 | ||
9872 | return std::unique_ptr<AST::SliceType> ( | |
9873 | new AST::SliceType (std::move (inner_type), locus)); | |
9874 | case SEMICOLON: { | |
9875 | // array type | |
9876 | lexer.skip_token (); | |
9877 | ||
9878 | // parse required array size expression | |
9879 | std::unique_ptr<AST::Expr> size = parse_expr (); | |
9880 | if (size == nullptr) | |
9881 | { | |
9882 | Error error (lexer.peek_token ()->get_locus (), | |
9883 | "failed to parse size expression in array type"); | |
9884 | add_error (std::move (error)); | |
9885 | ||
9886 | return nullptr; | |
9887 | } | |
9888 | ||
9889 | if (!skip_token (RIGHT_SQUARE)) | |
9890 | { | |
9891 | return nullptr; | |
9892 | } | |
9893 | ||
9894 | return std::unique_ptr<AST::ArrayType> ( | |
9895 | new AST::ArrayType (std::move (inner_type), std::move (size), locus)); | |
9896 | } | |
9897 | default: | |
9898 | // error | |
9899 | add_error ( | |
9900 | Error (t->get_locus (), | |
9901 | "unrecognised token %qs in slice or array type after inner type", | |
9902 | t->get_token_description ())); | |
9903 | ||
9904 | return nullptr; | |
9905 | } | |
9906 | } | |
9907 | ||
9908 | // Parses a type, taking into account type boundary disambiguation. | |
9909 | template <typename ManagedTokenSource> | |
9910 | std::unique_ptr<AST::TypeNoBounds> | |
9911 | Parser<ManagedTokenSource>::parse_type_no_bounds () | |
9912 | { | |
9913 | const_TokenPtr t = lexer.peek_token (); | |
9914 | switch (t->get_id ()) | |
9915 | { | |
9916 | case EXCLAM: | |
9917 | // never type - can't be macro as no path beforehand | |
9918 | lexer.skip_token (); | |
9919 | return std::unique_ptr<AST::NeverType> ( | |
9920 | new AST::NeverType (t->get_locus ())); | |
9921 | case LEFT_SQUARE: | |
9922 | // slice type or array type - requires further disambiguation | |
9923 | return parse_slice_or_array_type (); | |
9924 | case LEFT_ANGLE: { | |
9925 | // qualified path in type | |
9926 | AST::QualifiedPathInType path = parse_qualified_path_in_type (); | |
9927 | if (path.is_error ()) | |
9928 | { | |
9929 | Error error (t->get_locus (), | |
9930 | "failed to parse qualified path in type"); | |
9931 | add_error (std::move (error)); | |
9932 | ||
9933 | return nullptr; | |
9934 | } | |
9935 | return std::unique_ptr<AST::QualifiedPathInType> ( | |
9936 | new AST::QualifiedPathInType (std::move (path))); | |
9937 | } | |
9938 | case UNDERSCORE: | |
9939 | // inferred type | |
9940 | lexer.skip_token (); | |
9941 | return std::unique_ptr<AST::InferredType> ( | |
9942 | new AST::InferredType (t->get_locus ())); | |
9943 | case ASTERISK: | |
9944 | // raw pointer type | |
9945 | return parse_raw_pointer_type (); | |
9946 | case AMP: // does this also include AMP_AMP? | |
9947 | // reference type | |
9948 | return parse_reference_type (); | |
9949 | case LIFETIME: | |
9950 | /* probably a lifetime bound, so probably type param bounds in | |
9951 | * TraitObjectType. this is not allowed, but detection here for error | |
9952 | * message */ | |
9953 | add_error (Error (t->get_locus (), | |
9954 | "lifetime bounds (i.e. in type param bounds, in " | |
9955 | "TraitObjectType) are not allowed as TypeNoBounds")); | |
9956 | ||
9957 | return nullptr; | |
9958 | case IDENTIFIER: | |
9959 | case SUPER: | |
9960 | case SELF: | |
9961 | case SELF_ALIAS: | |
9962 | case CRATE: | |
9963 | case DOLLAR_SIGN: | |
9964 | case SCOPE_RESOLUTION: { | |
9965 | // macro invocation or type path - requires further disambiguation. | |
9966 | /* for parsing path component of each rule, perhaps parse it as a | |
9967 | * typepath and attempt conversion to simplepath if a trailing '!' is | |
9968 | * found */ | |
9969 | /* Type path also includes TraitObjectTypeOneBound BUT if it starts | |
9970 | * with it, it is exactly the same as a TypePath syntactically, so | |
9971 | * this is a syntactical ambiguity. As such, the parser will parse it | |
9972 | * as a TypePath. This, however, does not prevent TraitObjectType from | |
9973 | * starting with a typepath. */ | |
9974 | ||
9975 | // parse path as type path | |
9976 | AST::TypePath path = parse_type_path (); | |
9977 | if (path.is_error ()) | |
9978 | { | |
9979 | Error error ( | |
9980 | t->get_locus (), | |
9981 | "failed to parse path as first component of type no bounds"); | |
9982 | add_error (std::move (error)); | |
9983 | ||
9984 | return nullptr; | |
9985 | } | |
9986 | Location locus = path.get_locus (); | |
9987 | ||
9988 | // branch on next token | |
9989 | t = lexer.peek_token (); | |
9990 | switch (t->get_id ()) | |
9991 | { | |
9992 | case EXCLAM: { | |
9993 | // macro invocation | |
9994 | // convert to simple path | |
9995 | AST::SimplePath macro_path = path.as_simple_path (); | |
9996 | if (macro_path.is_empty ()) | |
9997 | { | |
9998 | Error error (t->get_locus (), | |
9999 | "failed to parse simple path in macro " | |
10000 | "invocation (for type)"); | |
10001 | add_error (std::move (error)); | |
10002 | ||
10003 | return nullptr; | |
10004 | } | |
10005 | ||
10006 | lexer.skip_token (); | |
10007 | ||
10008 | AST::DelimTokenTree tok_tree = parse_delim_token_tree (); | |
10009 | ||
10010 | return std::unique_ptr<AST::MacroInvocation> ( | |
10011 | new AST::MacroInvocation ( | |
10012 | AST::MacroInvocData (std::move (macro_path), | |
10013 | std::move (tok_tree)), | |
10014 | {}, locus)); | |
10015 | } | |
10016 | default: | |
10017 | // assume that this is a type path and not an error | |
10018 | return std::unique_ptr<AST::TypePath> ( | |
10019 | new AST::TypePath (std::move (path))); | |
10020 | } | |
10021 | } | |
10022 | case LEFT_PAREN: | |
10023 | /* tuple type or parenthesised type - requires further disambiguation | |
10024 | * (the usual). ok apparently can be a parenthesised TraitBound too, so | |
10025 | * could be TraitObjectTypeOneBound */ | |
10026 | return parse_paren_prefixed_type_no_bounds (); | |
10027 | case FOR: | |
10028 | case ASYNC: | |
10029 | case CONST: | |
10030 | case UNSAFE: | |
10031 | case EXTERN_TOK: | |
10032 | case FN_TOK: | |
10033 | // bare function type (with no for lifetimes) | |
10034 | return parse_bare_function_type (std::vector<AST::LifetimeParam> ()); | |
10035 | case IMPL: | |
10036 | lexer.skip_token (); | |
10037 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
10038 | { | |
10039 | /* cannot be one bound because lifetime prevents it from being | |
10040 | * traitbound not allowed as type no bounds, only here for error | |
10041 | * message */ | |
10042 | Error error ( | |
10043 | lexer.peek_token ()->get_locus (), | |
10044 | "lifetime (probably lifetime bound, in type param " | |
10045 | "bounds, in ImplTraitType) is not allowed in TypeNoBounds"); | |
10046 | add_error (std::move (error)); | |
10047 | ||
10048 | return nullptr; | |
10049 | } | |
10050 | else | |
10051 | { | |
10052 | // should be trait bound, so parse trait bound | |
10053 | std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound (); | |
10054 | if (initial_bound == nullptr) | |
10055 | { | |
10056 | Error error (lexer.peek_token ()->get_locus (), | |
10057 | "failed to parse ImplTraitTypeOneBound bound"); | |
10058 | add_error (std::move (error)); | |
10059 | ||
10060 | return nullptr; | |
10061 | } | |
10062 | ||
10063 | Location locus = t->get_locus (); | |
10064 | ||
10065 | // ensure not a trait with multiple bounds | |
10066 | t = lexer.peek_token (); | |
10067 | if (t->get_id () == PLUS) | |
10068 | { | |
10069 | Error error (t->get_locus (), | |
10070 | "plus after trait bound means an ImplTraitType, " | |
10071 | "which is not allowed as a TypeNoBounds"); | |
10072 | add_error (std::move (error)); | |
10073 | ||
10074 | return nullptr; | |
10075 | } | |
10076 | ||
10077 | // convert trait bound to value object | |
10078 | AST::TraitBound value_bound (*initial_bound); | |
10079 | ||
10080 | return std::unique_ptr<AST::ImplTraitTypeOneBound> ( | |
10081 | new AST::ImplTraitTypeOneBound (std::move (value_bound), locus)); | |
10082 | } | |
10083 | case DYN: | |
10084 | case QUESTION_MARK: { | |
10085 | // either TraitObjectTypeOneBound | |
10086 | bool has_dyn = false; | |
10087 | if (t->get_id () == DYN) | |
10088 | { | |
10089 | lexer.skip_token (); | |
10090 | has_dyn = true; | |
10091 | } | |
10092 | ||
10093 | if (lexer.peek_token ()->get_id () == LIFETIME) | |
10094 | { | |
10095 | /* means that cannot be TraitObjectTypeOneBound - so here for | |
10096 | * error message */ | |
10097 | Error error (lexer.peek_token ()->get_locus (), | |
10098 | "lifetime as bound in TraitObjectTypeOneBound " | |
10099 | "is not allowed, so cannot be TypeNoBounds"); | |
10100 | add_error (std::move (error)); | |
10101 | ||
10102 | return nullptr; | |
10103 | } | |
10104 | ||
10105 | // should be trait bound, so parse trait bound | |
10106 | std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound (); | |
10107 | if (initial_bound == nullptr) | |
10108 | { | |
10109 | Error error ( | |
10110 | lexer.peek_token ()->get_locus (), | |
10111 | "failed to parse TraitObjectTypeOneBound initial bound"); | |
10112 | add_error (std::move (error)); | |
10113 | ||
10114 | return nullptr; | |
10115 | } | |
10116 | ||
10117 | Location locus = t->get_locus (); | |
10118 | ||
10119 | // detect error with plus as next token | |
10120 | t = lexer.peek_token (); | |
10121 | if (t->get_id () == PLUS) | |
10122 | { | |
10123 | Error error (t->get_locus (), | |
10124 | "plus after trait bound means a TraitObjectType, " | |
10125 | "which is not allowed as a TypeNoBounds"); | |
10126 | add_error (std::move (error)); | |
10127 | ||
10128 | return nullptr; | |
10129 | } | |
10130 | ||
10131 | // convert trait bound to value object | |
10132 | AST::TraitBound value_bound (*initial_bound); | |
10133 | ||
10134 | return std::unique_ptr<AST::TraitObjectTypeOneBound> ( | |
10135 | new AST::TraitObjectTypeOneBound (std::move (value_bound), locus, | |
10136 | has_dyn)); | |
10137 | } | |
10138 | default: | |
10139 | add_error (Error (t->get_locus (), | |
10140 | "unrecognised token %qs in type no bounds", | |
10141 | t->get_token_description ())); | |
10142 | ||
10143 | return nullptr; | |
10144 | } | |
10145 | } | |
10146 | ||
10147 | // Parses a type no bounds beginning with '('. | |
10148 | template <typename ManagedTokenSource> | |
10149 | std::unique_ptr<AST::TypeNoBounds> | |
10150 | Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds () | |
10151 | { | |
10152 | /* NOTE: this could probably be parsed without the HACK solution of | |
10153 | * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/ | |
10154 | ||
10155 | /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is | |
10156 | * considered a trait bound, not a parenthesised type, so that it can still | |
10157 | * be used in type param bounds. */ | |
10158 | ||
10159 | Location left_paren_locus = lexer.peek_token ()->get_locus (); | |
10160 | ||
10161 | // skip left delim | |
10162 | lexer.skip_token (); | |
10163 | /* while next token isn't close delim, parse comma-separated types, saving | |
10164 | * whether trailing comma happens */ | |
10165 | const_TokenPtr t = lexer.peek_token (); | |
10166 | bool trailing_comma = true; | |
10167 | std::vector<std::unique_ptr<AST::Type>> types; | |
10168 | ||
10169 | while (t->get_id () != RIGHT_PAREN) | |
10170 | { | |
10171 | std::unique_ptr<AST::Type> type = parse_type (); | |
10172 | if (type == nullptr) | |
10173 | { | |
10174 | Error error (t->get_locus (), | |
10175 | "failed to parse type inside parentheses (probably " | |
10176 | "tuple or parenthesised)"); | |
10177 | add_error (std::move (error)); | |
10178 | ||
10179 | return nullptr; | |
10180 | } | |
10181 | types.push_back (std::move (type)); | |
10182 | ||
10183 | t = lexer.peek_token (); | |
10184 | if (t->get_id () != COMMA) | |
10185 | { | |
10186 | trailing_comma = false; | |
10187 | break; | |
10188 | } | |
10189 | lexer.skip_token (); | |
10190 | ||
10191 | t = lexer.peek_token (); | |
10192 | } | |
10193 | ||
10194 | if (!skip_token (RIGHT_PAREN)) | |
10195 | { | |
10196 | return nullptr; | |
10197 | } | |
10198 | ||
10199 | // if only one type and no trailing comma, then not a tuple type | |
10200 | if (types.size () == 1 && !trailing_comma) | |
10201 | { | |
10202 | // must be a TraitObjectType (with more than one bound) | |
10203 | if (lexer.peek_token ()->get_id () == PLUS) | |
10204 | { | |
10205 | // error - this is not allowed for type no bounds | |
10206 | Error error (lexer.peek_token ()->get_locus (), | |
10207 | "plus (implying TraitObjectType as type param " | |
10208 | "bounds) is not allowed in type no bounds"); | |
10209 | add_error (std::move (error)); | |
10210 | ||
10211 | return nullptr; | |
10212 | } | |
10213 | else | |
10214 | { | |
10215 | // release vector pointer | |
10216 | std::unique_ptr<AST::Type> released_ptr = std::move (types[0]); | |
10217 | /* HACK: attempt to convert to trait bound. if fails, parenthesised | |
10218 | * type */ | |
10219 | std::unique_ptr<AST::TraitBound> converted_bound ( | |
10220 | released_ptr->to_trait_bound (true)); | |
10221 | if (converted_bound == nullptr) | |
10222 | { | |
10223 | // parenthesised type | |
10224 | return std::unique_ptr<AST::ParenthesisedType> ( | |
10225 | new AST::ParenthesisedType (std::move (released_ptr), | |
10226 | left_paren_locus)); | |
10227 | } | |
10228 | else | |
10229 | { | |
10230 | // trait object type (one bound) | |
10231 | ||
10232 | // get value semantics trait bound | |
10233 | AST::TraitBound value_bound (*converted_bound); | |
10234 | ||
10235 | return std::unique_ptr<AST::TraitObjectTypeOneBound> ( | |
10236 | new AST::TraitObjectTypeOneBound (value_bound, | |
10237 | left_paren_locus)); | |
10238 | } | |
10239 | } | |
10240 | } | |
10241 | else | |
10242 | { | |
10243 | return std::unique_ptr<AST::TupleType> ( | |
10244 | new AST::TupleType (std::move (types), left_paren_locus)); | |
10245 | } | |
10246 | /* TODO: ensure that this ensures that dynamic dispatch for traits is not | |
10247 | * lost somehow */ | |
10248 | } | |
10249 | ||
10250 | /* Parses a literal pattern or range pattern. Assumes that literals passed in | |
10251 | * are valid range pattern bounds. Do not pass in paths in expressions, for | |
10252 | * instance. */ | |
10253 | template <typename ManagedTokenSource> | |
10254 | std::unique_ptr<AST::Pattern> | |
10255 | Parser<ManagedTokenSource>::parse_literal_or_range_pattern () | |
10256 | { | |
10257 | const_TokenPtr range_lower = lexer.peek_token (); | |
10258 | AST::Literal::LitType type = AST::Literal::STRING; | |
10259 | bool has_minus = false; | |
10260 | ||
10261 | // get lit type | |
10262 | switch (range_lower->get_id ()) | |
10263 | { | |
10264 | case CHAR_LITERAL: | |
10265 | type = AST::Literal::CHAR; | |
10266 | lexer.skip_token (); | |
10267 | break; | |
10268 | case BYTE_CHAR_LITERAL: | |
10269 | type = AST::Literal::BYTE; | |
10270 | lexer.skip_token (); | |
10271 | break; | |
10272 | case INT_LITERAL: | |
10273 | type = AST::Literal::INT; | |
10274 | lexer.skip_token (); | |
10275 | break; | |
10276 | case FLOAT_LITERAL: | |
10277 | type = AST::Literal::FLOAT; | |
10278 | lexer.skip_token (); | |
10279 | break; | |
10280 | case MINUS: | |
10281 | // branch on next token | |
10282 | range_lower = lexer.peek_token (1); | |
10283 | switch (range_lower->get_id ()) | |
10284 | { | |
10285 | case INT_LITERAL: | |
10286 | type = AST::Literal::INT; | |
10287 | has_minus = true; | |
10288 | lexer.skip_token (1); | |
10289 | break; | |
10290 | case FLOAT_LITERAL: | |
10291 | type = AST::Literal::FLOAT; | |
10292 | has_minus = true; | |
10293 | lexer.skip_token (1); | |
10294 | break; | |
10295 | default: | |
10296 | add_error (Error (range_lower->get_locus (), | |
10297 | "token type %qs cannot be parsed as range pattern " | |
10298 | "bound or literal after minus symbol", | |
10299 | range_lower->get_token_description ())); | |
10300 | ||
10301 | return nullptr; | |
10302 | } | |
10303 | break; | |
10304 | default: | |
10305 | add_error ( | |
10306 | Error (range_lower->get_locus (), | |
10307 | "token type %qs cannot be parsed as range pattern bound", | |
10308 | range_lower->get_token_description ())); | |
10309 | ||
10310 | return nullptr; | |
10311 | } | |
10312 | ||
10313 | const_TokenPtr next = lexer.peek_token (); | |
10314 | if (next->get_id () == DOT_DOT_EQ || next->get_id () == ELLIPSIS) | |
10315 | { | |
10316 | // range pattern | |
10317 | lexer.skip_token (); | |
10318 | std::unique_ptr<AST::RangePatternBound> lower ( | |
10319 | new AST::RangePatternBoundLiteral ( | |
10320 | AST::Literal (range_lower->get_str (), type, | |
10321 | PrimitiveCoreType::CORETYPE_UNKNOWN), | |
10322 | range_lower->get_locus (), has_minus)); | |
10323 | ||
10324 | std::unique_ptr<AST::RangePatternBound> upper | |
10325 | = parse_range_pattern_bound (); | |
10326 | if (upper == nullptr) | |
10327 | { | |
10328 | Error error (next->get_locus (), | |
10329 | "failed to parse range pattern bound in range pattern"); | |
10330 | add_error (std::move (error)); | |
10331 | ||
10332 | return nullptr; | |
10333 | } | |
10334 | ||
10335 | return std::unique_ptr<AST::RangePattern> ( | |
10336 | new AST::RangePattern (std::move (lower), std::move (upper), | |
10337 | range_lower->get_locus ())); | |
10338 | } | |
10339 | else | |
10340 | { | |
10341 | // literal pattern | |
10342 | return std::unique_ptr<AST::LiteralPattern> ( | |
10343 | new AST::LiteralPattern (range_lower->get_str (), type, | |
10344 | range_lower->get_locus ())); | |
10345 | } | |
10346 | } | |
10347 | ||
10348 | // Parses a range pattern bound (value only). | |
10349 | template <typename ManagedTokenSource> | |
10350 | std::unique_ptr<AST::RangePatternBound> | |
10351 | Parser<ManagedTokenSource>::parse_range_pattern_bound () | |
10352 | { | |
10353 | const_TokenPtr range_lower = lexer.peek_token (); | |
10354 | Location range_lower_locus = range_lower->get_locus (); | |
10355 | ||
10356 | // get lit type | |
10357 | switch (range_lower->get_id ()) | |
10358 | { | |
10359 | case CHAR_LITERAL: | |
10360 | lexer.skip_token (); | |
10361 | return std::unique_ptr<AST::RangePatternBoundLiteral> ( | |
10362 | new AST::RangePatternBoundLiteral ( | |
10363 | AST::Literal (range_lower->get_str (), AST::Literal::CHAR, | |
10364 | range_lower->get_type_hint ()), | |
10365 | range_lower_locus)); | |
10366 | case BYTE_CHAR_LITERAL: | |
10367 | lexer.skip_token (); | |
10368 | return std::unique_ptr<AST::RangePatternBoundLiteral> ( | |
10369 | new AST::RangePatternBoundLiteral ( | |
10370 | AST::Literal (range_lower->get_str (), AST::Literal::BYTE, | |
10371 | range_lower->get_type_hint ()), | |
10372 | range_lower_locus)); | |
10373 | case INT_LITERAL: | |
10374 | lexer.skip_token (); | |
10375 | return std::unique_ptr<AST::RangePatternBoundLiteral> ( | |
10376 | new AST::RangePatternBoundLiteral ( | |
10377 | AST::Literal (range_lower->get_str (), AST::Literal::INT, | |
10378 | range_lower->get_type_hint ()), | |
10379 | range_lower_locus)); | |
10380 | case FLOAT_LITERAL: | |
10381 | lexer.skip_token (); | |
10382 | rust_debug ("warning: used deprecated float range pattern bound"); | |
10383 | return std::unique_ptr<AST::RangePatternBoundLiteral> ( | |
10384 | new AST::RangePatternBoundLiteral ( | |
10385 | AST::Literal (range_lower->get_str (), AST::Literal::FLOAT, | |
10386 | range_lower->get_type_hint ()), | |
10387 | range_lower_locus)); | |
10388 | case MINUS: | |
10389 | // branch on next token | |
10390 | range_lower = lexer.peek_token (1); | |
10391 | switch (range_lower->get_id ()) | |
10392 | { | |
10393 | case INT_LITERAL: | |
10394 | lexer.skip_token (1); | |
10395 | return std::unique_ptr<AST::RangePatternBoundLiteral> ( | |
10396 | new AST::RangePatternBoundLiteral ( | |
10397 | AST::Literal (range_lower->get_str (), AST::Literal::INT, | |
10398 | range_lower->get_type_hint ()), | |
10399 | range_lower_locus, true)); | |
10400 | case FLOAT_LITERAL: | |
10401 | lexer.skip_token (1); | |
10402 | rust_debug ("warning: used deprecated float range pattern bound"); | |
10403 | return std::unique_ptr<AST::RangePatternBoundLiteral> ( | |
10404 | new AST::RangePatternBoundLiteral ( | |
10405 | AST::Literal (range_lower->get_str (), AST::Literal::FLOAT, | |
10406 | range_lower->get_type_hint ()), | |
10407 | range_lower_locus, true)); | |
10408 | default: | |
10409 | add_error (Error (range_lower->get_locus (), | |
10410 | "token type %qs cannot be parsed as range pattern " | |
10411 | "bound after minus symbol", | |
10412 | range_lower->get_token_description ())); | |
10413 | ||
10414 | return nullptr; | |
10415 | } | |
10416 | case IDENTIFIER: | |
10417 | case SUPER: | |
10418 | case SELF: | |
10419 | case SELF_ALIAS: | |
10420 | case CRATE: | |
10421 | case SCOPE_RESOLUTION: | |
10422 | case DOLLAR_SIGN: { | |
10423 | // path in expression | |
10424 | AST::PathInExpression path = parse_path_in_expression (); | |
10425 | if (path.is_error ()) | |
10426 | { | |
10427 | Error error ( | |
10428 | range_lower->get_locus (), | |
10429 | "failed to parse path in expression range pattern bound"); | |
10430 | add_error (std::move (error)); | |
10431 | ||
10432 | return nullptr; | |
10433 | } | |
10434 | return std::unique_ptr<AST::RangePatternBoundPath> ( | |
10435 | new AST::RangePatternBoundPath (std::move (path))); | |
10436 | } | |
10437 | case LEFT_ANGLE: { | |
10438 | // qualified path in expression | |
10439 | AST::QualifiedPathInExpression path | |
10440 | = parse_qualified_path_in_expression (); | |
10441 | if (path.is_error ()) | |
10442 | { | |
10443 | Error error (range_lower->get_locus (), | |
10444 | "failed to parse qualified path in expression range " | |
10445 | "pattern bound"); | |
10446 | add_error (std::move (error)); | |
10447 | ||
10448 | return nullptr; | |
10449 | } | |
10450 | return std::unique_ptr<AST::RangePatternBoundQualPath> ( | |
10451 | new AST::RangePatternBoundQualPath (std::move (path))); | |
10452 | } | |
10453 | default: | |
10454 | add_error ( | |
10455 | Error (range_lower->get_locus (), | |
10456 | "token type %qs cannot be parsed as range pattern bound", | |
10457 | range_lower->get_token_description ())); | |
10458 | ||
10459 | return nullptr; | |
10460 | } | |
10461 | } | |
10462 | ||
10463 | // Parses a pattern (will further disambiguate any pattern). | |
10464 | template <typename ManagedTokenSource> | |
10465 | std::unique_ptr<AST::Pattern> | |
10466 | Parser<ManagedTokenSource>::parse_pattern () | |
10467 | { | |
10468 | const_TokenPtr t = lexer.peek_token (); | |
10469 | switch (t->get_id ()) | |
10470 | { | |
10471 | case TRUE_LITERAL: | |
10472 | lexer.skip_token (); | |
10473 | return std::unique_ptr<AST::LiteralPattern> ( | |
10474 | new AST::LiteralPattern ("true", AST::Literal::BOOL, t->get_locus ())); | |
10475 | case FALSE_LITERAL: | |
10476 | lexer.skip_token (); | |
10477 | return std::unique_ptr<AST::LiteralPattern> ( | |
10478 | new AST::LiteralPattern ("false", AST::Literal::BOOL, t->get_locus ())); | |
10479 | case CHAR_LITERAL: | |
10480 | case BYTE_CHAR_LITERAL: | |
10481 | case INT_LITERAL: | |
10482 | case FLOAT_LITERAL: | |
10483 | return parse_literal_or_range_pattern (); | |
10484 | case STRING_LITERAL: | |
10485 | lexer.skip_token (); | |
10486 | return std::unique_ptr<AST::LiteralPattern> ( | |
10487 | new AST::LiteralPattern (t->get_str (), AST::Literal::STRING, | |
10488 | t->get_locus ())); | |
10489 | case BYTE_STRING_LITERAL: | |
10490 | lexer.skip_token (); | |
10491 | return std::unique_ptr<AST::LiteralPattern> ( | |
10492 | new AST::LiteralPattern (t->get_str (), AST::Literal::BYTE_STRING, | |
10493 | t->get_locus ())); | |
10494 | // raw string and raw byte string literals too if they are readded to | |
10495 | // lexer | |
10496 | case MINUS: | |
10497 | if (lexer.peek_token (1)->get_id () == INT_LITERAL) | |
10498 | { | |
10499 | return parse_literal_or_range_pattern (); | |
10500 | } | |
10501 | else if (lexer.peek_token (1)->get_id () == FLOAT_LITERAL) | |
10502 | { | |
10503 | return parse_literal_or_range_pattern (); | |
10504 | } | |
10505 | else | |
10506 | { | |
10507 | Error error (t->get_locus (), "unexpected token %<-%> in pattern - " | |
10508 | "did you forget an integer literal"); | |
10509 | add_error (std::move (error)); | |
10510 | ||
10511 | return nullptr; | |
10512 | } | |
10513 | case UNDERSCORE: | |
10514 | lexer.skip_token (); | |
10515 | return std::unique_ptr<AST::WildcardPattern> ( | |
10516 | new AST::WildcardPattern (t->get_locus ())); | |
10517 | case REF: | |
10518 | case MUT: | |
10519 | return parse_identifier_pattern (); | |
10520 | case IDENTIFIER: | |
10521 | /* if identifier with no scope resolution afterwards, identifier | |
10522 | * pattern. if scope resolution afterwards, path pattern (or range | |
10523 | * pattern or struct pattern or tuple struct pattern) or macro | |
10524 | * invocation */ | |
10525 | return parse_ident_leading_pattern (); | |
10526 | case AMP: | |
10527 | case LOGICAL_AND: | |
10528 | // reference pattern | |
10529 | return parse_reference_pattern (); | |
10530 | case LEFT_PAREN: | |
10531 | // tuple pattern or grouped pattern | |
10532 | return parse_grouped_or_tuple_pattern (); | |
10533 | case LEFT_SQUARE: | |
10534 | // slice pattern | |
10535 | return parse_slice_pattern (); | |
10536 | case LEFT_ANGLE: { | |
10537 | // qualified path in expression or qualified range pattern bound | |
10538 | AST::QualifiedPathInExpression path | |
10539 | = parse_qualified_path_in_expression (); | |
10540 | ||
10541 | if (lexer.peek_token ()->get_id () == DOT_DOT_EQ | |
10542 | || lexer.peek_token ()->get_id () == ELLIPSIS) | |
10543 | { | |
10544 | // qualified range pattern bound, so parse rest of range pattern | |
10545 | bool has_ellipsis_syntax | |
10546 | = lexer.peek_token ()->get_id () == ELLIPSIS; | |
10547 | lexer.skip_token (); | |
10548 | ||
10549 | std::unique_ptr<AST::RangePatternBoundQualPath> lower_bound ( | |
10550 | new AST::RangePatternBoundQualPath (std::move (path))); | |
10551 | std::unique_ptr<AST::RangePatternBound> upper_bound | |
10552 | = parse_range_pattern_bound (); | |
10553 | ||
10554 | return std::unique_ptr<AST::RangePattern> ( | |
10555 | new AST::RangePattern (std::move (lower_bound), | |
10556 | std::move (upper_bound), t->get_locus (), | |
10557 | has_ellipsis_syntax)); | |
10558 | } | |
10559 | else | |
10560 | { | |
10561 | // just qualified path in expression | |
10562 | return std::unique_ptr<AST::QualifiedPathInExpression> ( | |
10563 | new AST::QualifiedPathInExpression (std::move (path))); | |
10564 | } | |
10565 | } | |
10566 | case SUPER: | |
10567 | case SELF: | |
10568 | case SELF_ALIAS: | |
10569 | case CRATE: | |
10570 | case SCOPE_RESOLUTION: | |
10571 | case DOLLAR_SIGN: { | |
10572 | // path in expression or range pattern bound | |
10573 | AST::PathInExpression path = parse_path_in_expression (); | |
10574 | ||
10575 | const_TokenPtr next = lexer.peek_token (); | |
10576 | switch (next->get_id ()) | |
10577 | { | |
10578 | case DOT_DOT_EQ: | |
10579 | case ELLIPSIS: { | |
10580 | // qualified range pattern bound, so parse rest of range pattern | |
10581 | bool has_ellipsis_syntax | |
10582 | = lexer.peek_token ()->get_id () == ELLIPSIS; | |
10583 | lexer.skip_token (); | |
10584 | ||
10585 | std::unique_ptr<AST::RangePatternBoundPath> lower_bound ( | |
10586 | new AST::RangePatternBoundPath (std::move (path))); | |
10587 | std::unique_ptr<AST::RangePatternBound> upper_bound | |
10588 | = parse_range_pattern_bound (); | |
10589 | ||
10590 | return std::unique_ptr<AST::RangePattern> (new AST::RangePattern ( | |
10591 | std::move (lower_bound), std::move (upper_bound), | |
10592 | Linemap::unknown_location (), has_ellipsis_syntax)); | |
10593 | } | |
10594 | case EXCLAM: | |
10595 | return parse_macro_invocation_partial (std::move (path), | |
10596 | AST::AttrVec ()); | |
10597 | case LEFT_PAREN: { | |
10598 | // tuple struct | |
10599 | lexer.skip_token (); | |
10600 | ||
10601 | // check if empty tuple | |
10602 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
10603 | { | |
10604 | lexer.skip_token (); | |
10605 | return std::unique_ptr<AST::TupleStructPattern> ( | |
10606 | new AST::TupleStructPattern (std::move (path), nullptr)); | |
10607 | } | |
10608 | ||
10609 | // parse items | |
10610 | std::unique_ptr<AST::TupleStructItems> items | |
10611 | = parse_tuple_struct_items (); | |
10612 | if (items == nullptr) | |
10613 | { | |
10614 | Error error (lexer.peek_token ()->get_locus (), | |
10615 | "failed to parse tuple struct items"); | |
10616 | add_error (std::move (error)); | |
10617 | ||
10618 | return nullptr; | |
10619 | } | |
10620 | ||
10621 | if (!skip_token (RIGHT_PAREN)) | |
10622 | { | |
10623 | return nullptr; | |
10624 | } | |
10625 | ||
10626 | return std::unique_ptr<AST::TupleStructPattern> ( | |
10627 | new AST::TupleStructPattern (std::move (path), | |
10628 | std::move (items))); | |
10629 | } | |
10630 | case LEFT_CURLY: { | |
10631 | // struct | |
10632 | lexer.skip_token (); | |
10633 | ||
10634 | // parse elements (optional) | |
10635 | AST::StructPatternElements elems = parse_struct_pattern_elems (); | |
10636 | ||
10637 | if (!skip_token (RIGHT_CURLY)) | |
10638 | { | |
10639 | return nullptr; | |
10640 | } | |
10641 | ||
10642 | return std::unique_ptr<AST::StructPattern> ( | |
10643 | new AST::StructPattern (std::move (path), t->get_locus (), | |
10644 | std::move (elems))); | |
10645 | } | |
10646 | default: | |
10647 | // assume path in expression | |
10648 | return std::unique_ptr<AST::PathInExpression> ( | |
10649 | new AST::PathInExpression (std::move (path))); | |
10650 | } | |
10651 | } | |
10652 | default: | |
10653 | add_error (Error (t->get_locus (), "unexpected token %qs in pattern", | |
10654 | t->get_token_description ())); | |
10655 | ||
10656 | return nullptr; | |
10657 | } | |
10658 | } | |
10659 | ||
10660 | // Parses a single or double reference pattern. | |
10661 | template <typename ManagedTokenSource> | |
10662 | std::unique_ptr<AST::ReferencePattern> | |
10663 | Parser<ManagedTokenSource>::parse_reference_pattern () | |
10664 | { | |
10665 | // parse double or single ref | |
10666 | bool is_double_ref = false; | |
10667 | const_TokenPtr t = lexer.peek_token (); | |
10668 | switch (t->get_id ()) | |
10669 | { | |
10670 | case AMP: | |
10671 | // still false | |
10672 | lexer.skip_token (); | |
10673 | break; | |
10674 | case LOGICAL_AND: | |
10675 | is_double_ref = true; | |
10676 | lexer.skip_token (); | |
10677 | break; | |
10678 | default: | |
10679 | add_error (Error (t->get_locus (), | |
10680 | "unexpected token %qs in reference pattern", | |
10681 | t->get_token_description ())); | |
10682 | ||
10683 | return nullptr; | |
10684 | } | |
10685 | ||
10686 | // parse mut (if it exists) | |
10687 | bool is_mut = false; | |
10688 | if (lexer.peek_token ()->get_id () == MUT) | |
10689 | { | |
10690 | is_mut = true; | |
10691 | lexer.skip_token (); | |
10692 | } | |
10693 | ||
10694 | // parse pattern to get reference of (required) | |
10695 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
10696 | if (pattern == nullptr) | |
10697 | { | |
10698 | Error error (lexer.peek_token ()->get_locus (), | |
10699 | "failed to parse pattern in reference pattern"); | |
10700 | add_error (std::move (error)); | |
10701 | ||
10702 | // skip somewhere? | |
10703 | return nullptr; | |
10704 | } | |
10705 | ||
10706 | return std::unique_ptr<AST::ReferencePattern> ( | |
10707 | new AST::ReferencePattern (std::move (pattern), is_mut, is_double_ref, | |
10708 | t->get_locus ())); | |
10709 | } | |
10710 | ||
10711 | /* Parses a grouped pattern or tuple pattern. Prefers grouped over tuple if | |
10712 | * only a single element with no commas. */ | |
10713 | template <typename ManagedTokenSource> | |
10714 | std::unique_ptr<AST::Pattern> | |
10715 | Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern () | |
10716 | { | |
10717 | Location paren_locus = lexer.peek_token ()->get_locus (); | |
10718 | skip_token (LEFT_PAREN); | |
10719 | ||
10720 | // detect '..' token (ranged with no lower range) | |
10721 | if (lexer.peek_token ()->get_id () == DOT_DOT) | |
10722 | { | |
10723 | lexer.skip_token (); | |
10724 | ||
10725 | // parse new patterns while next token is a comma | |
10726 | std::vector<std::unique_ptr<AST::Pattern>> patterns; | |
10727 | ||
10728 | const_TokenPtr t = lexer.peek_token (); | |
10729 | while (t->get_id () == COMMA) | |
10730 | { | |
10731 | lexer.skip_token (); | |
10732 | ||
10733 | // break if next token is ')' | |
10734 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
10735 | { | |
10736 | break; | |
10737 | } | |
10738 | ||
10739 | // parse pattern, which is required | |
10740 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
10741 | if (pattern == nullptr) | |
10742 | { | |
10743 | Error error ( | |
10744 | lexer.peek_token ()->get_locus (), | |
10745 | "failed to parse pattern inside ranged tuple pattern"); | |
10746 | add_error (std::move (error)); | |
10747 | ||
10748 | // skip somewhere? | |
10749 | return nullptr; | |
10750 | } | |
10751 | patterns.push_back (std::move (pattern)); | |
10752 | ||
10753 | t = lexer.peek_token (); | |
10754 | } | |
10755 | ||
10756 | if (!skip_token (RIGHT_PAREN)) | |
10757 | { | |
10758 | // skip somewhere? | |
10759 | return nullptr; | |
10760 | } | |
10761 | ||
10762 | // create ranged tuple pattern items with only upper items | |
10763 | std::unique_ptr<AST::TuplePatternItemsRanged> items ( | |
10764 | new AST::TuplePatternItemsRanged ( | |
10765 | std::vector<std::unique_ptr<AST::Pattern>> (), std::move (patterns))); | |
10766 | return std::unique_ptr<AST::TuplePattern> ( | |
10767 | new AST::TuplePattern (std::move (items), paren_locus)); | |
10768 | } | |
10769 | ||
10770 | // parse initial pattern (required) | |
10771 | std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern (); | |
10772 | if (initial_pattern == nullptr) | |
10773 | { | |
10774 | Error error (lexer.peek_token ()->get_locus (), | |
10775 | "failed to parse pattern in grouped or tuple pattern"); | |
10776 | add_error (std::move (error)); | |
10777 | ||
10778 | return nullptr; | |
10779 | } | |
10780 | ||
10781 | // branch on whether next token is a comma or not | |
10782 | const_TokenPtr t = lexer.peek_token (); | |
10783 | switch (t->get_id ()) | |
10784 | { | |
10785 | case RIGHT_PAREN: | |
10786 | // grouped pattern | |
10787 | lexer.skip_token (); | |
10788 | ||
10789 | return std::unique_ptr<AST::GroupedPattern> ( | |
10790 | new AST::GroupedPattern (std::move (initial_pattern), paren_locus)); | |
10791 | case COMMA: { | |
10792 | // tuple pattern | |
10793 | lexer.skip_token (); | |
10794 | ||
10795 | // create vector of patterns | |
10796 | std::vector<std::unique_ptr<AST::Pattern>> patterns; | |
10797 | patterns.push_back (std::move (initial_pattern)); | |
10798 | ||
10799 | t = lexer.peek_token (); | |
10800 | while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT) | |
10801 | { | |
10802 | // parse pattern (required) | |
10803 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
10804 | if (pattern == nullptr) | |
10805 | { | |
10806 | Error error (t->get_locus (), | |
10807 | "failed to parse pattern in tuple pattern"); | |
10808 | add_error (std::move (error)); | |
10809 | ||
10810 | return nullptr; | |
10811 | } | |
10812 | patterns.push_back (std::move (pattern)); | |
10813 | ||
10814 | if (lexer.peek_token ()->get_id () != COMMA) | |
10815 | break; | |
10816 | ||
10817 | lexer.skip_token (); | |
10818 | t = lexer.peek_token (); | |
10819 | } | |
10820 | ||
10821 | t = lexer.peek_token (); | |
10822 | if (t->get_id () == RIGHT_PAREN) | |
10823 | { | |
10824 | // non-ranged tuple pattern | |
10825 | lexer.skip_token (); | |
10826 | ||
10827 | std::unique_ptr<AST::TuplePatternItemsMultiple> items ( | |
10828 | new AST::TuplePatternItemsMultiple (std::move (patterns))); | |
10829 | return std::unique_ptr<AST::TuplePattern> ( | |
10830 | new AST::TuplePattern (std::move (items), paren_locus)); | |
10831 | } | |
10832 | else if (t->get_id () == DOT_DOT) | |
10833 | { | |
10834 | // ranged tuple pattern | |
10835 | lexer.skip_token (); | |
10836 | ||
10837 | // parse upper patterns | |
10838 | std::vector<std::unique_ptr<AST::Pattern>> upper_patterns; | |
10839 | t = lexer.peek_token (); | |
10840 | while (t->get_id () == COMMA) | |
10841 | { | |
10842 | lexer.skip_token (); | |
10843 | ||
10844 | // break if end | |
10845 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
10846 | break; | |
10847 | ||
10848 | // parse pattern (required) | |
10849 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
10850 | if (pattern == nullptr) | |
10851 | { | |
10852 | Error error (lexer.peek_token ()->get_locus (), | |
10853 | "failed to parse pattern in tuple pattern"); | |
10854 | add_error (std::move (error)); | |
10855 | ||
10856 | return nullptr; | |
10857 | } | |
10858 | upper_patterns.push_back (std::move (pattern)); | |
10859 | ||
10860 | t = lexer.peek_token (); | |
10861 | } | |
10862 | ||
10863 | if (!skip_token (RIGHT_PAREN)) | |
10864 | { | |
10865 | return nullptr; | |
10866 | } | |
10867 | ||
10868 | std::unique_ptr<AST::TuplePatternItemsRanged> items ( | |
10869 | new AST::TuplePatternItemsRanged (std::move (patterns), | |
10870 | std::move (upper_patterns))); | |
10871 | return std::unique_ptr<AST::TuplePattern> ( | |
10872 | new AST::TuplePattern (std::move (items), paren_locus)); | |
10873 | } | |
10874 | else | |
10875 | { | |
10876 | // some kind of error | |
10877 | Error error (t->get_locus (), | |
10878 | "failed to parse tuple pattern (probably) or maybe " | |
10879 | "grouped pattern"); | |
10880 | add_error (std::move (error)); | |
10881 | ||
10882 | return nullptr; | |
10883 | } | |
10884 | } | |
10885 | default: | |
10886 | // error | |
10887 | add_error (Error (t->get_locus (), | |
10888 | "unrecognised token %qs in grouped or tuple pattern " | |
10889 | "after first pattern", | |
10890 | t->get_token_description ())); | |
10891 | ||
10892 | return nullptr; | |
10893 | } | |
10894 | } | |
10895 | ||
10896 | /* Parses a slice pattern that can match arrays or slices. Parses the square | |
10897 | * brackets too. */ | |
10898 | template <typename ManagedTokenSource> | |
10899 | std::unique_ptr<AST::SlicePattern> | |
10900 | Parser<ManagedTokenSource>::parse_slice_pattern () | |
10901 | { | |
10902 | Location square_locus = lexer.peek_token ()->get_locus (); | |
10903 | skip_token (LEFT_SQUARE); | |
10904 | ||
10905 | // parse initial pattern (required) | |
10906 | std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern (); | |
10907 | if (initial_pattern == nullptr) | |
10908 | { | |
10909 | Error error (lexer.peek_token ()->get_locus (), | |
10910 | "failed to parse initial pattern in slice pattern"); | |
10911 | add_error (std::move (error)); | |
10912 | ||
10913 | return nullptr; | |
10914 | } | |
10915 | ||
10916 | std::vector<std::unique_ptr<AST::Pattern>> patterns; | |
10917 | patterns.push_back (std::move (initial_pattern)); | |
10918 | ||
10919 | const_TokenPtr t = lexer.peek_token (); | |
10920 | while (t->get_id () == COMMA) | |
10921 | { | |
10922 | lexer.skip_token (); | |
10923 | ||
10924 | // break if end bracket | |
10925 | if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) | |
10926 | break; | |
10927 | ||
10928 | // parse pattern (required) | |
10929 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
10930 | if (pattern == nullptr) | |
10931 | { | |
10932 | Error error (lexer.peek_token ()->get_locus (), | |
10933 | "failed to parse pattern in slice pattern"); | |
10934 | add_error (std::move (error)); | |
10935 | ||
10936 | return nullptr; | |
10937 | } | |
10938 | patterns.push_back (std::move (pattern)); | |
10939 | ||
10940 | t = lexer.peek_token (); | |
10941 | } | |
10942 | ||
10943 | if (!skip_token (RIGHT_SQUARE)) | |
10944 | { | |
10945 | return nullptr; | |
10946 | } | |
10947 | ||
10948 | return std::unique_ptr<AST::SlicePattern> ( | |
10949 | new AST::SlicePattern (std::move (patterns), square_locus)); | |
10950 | } | |
10951 | ||
10952 | /* Parses an identifier pattern (pattern that binds a value matched to a | |
10953 | * variable). */ | |
10954 | template <typename ManagedTokenSource> | |
10955 | std::unique_ptr<AST::IdentifierPattern> | |
10956 | Parser<ManagedTokenSource>::parse_identifier_pattern () | |
10957 | { | |
10958 | Location locus = lexer.peek_token ()->get_locus (); | |
10959 | ||
10960 | bool has_ref = false; | |
10961 | if (lexer.peek_token ()->get_id () == REF) | |
10962 | { | |
10963 | has_ref = true; | |
10964 | lexer.skip_token (); | |
10965 | ||
10966 | // DEBUG | |
10967 | rust_debug ("parsed ref in identifier pattern"); | |
10968 | } | |
10969 | ||
10970 | bool has_mut = false; | |
10971 | if (lexer.peek_token ()->get_id () == MUT) | |
10972 | { | |
10973 | has_mut = true; | |
10974 | lexer.skip_token (); | |
10975 | } | |
10976 | ||
10977 | // parse identifier (required) | |
10978 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
10979 | if (ident_tok == nullptr) | |
10980 | { | |
10981 | // skip somewhere? | |
10982 | return nullptr; | |
10983 | } | |
10984 | Identifier ident = ident_tok->get_str (); | |
10985 | ||
10986 | // DEBUG | |
10987 | rust_debug ("parsed identifier in identifier pattern"); | |
10988 | ||
10989 | // parse optional pattern binding thing | |
10990 | std::unique_ptr<AST::Pattern> bind_pattern = nullptr; | |
10991 | if (lexer.peek_token ()->get_id () == PATTERN_BIND) | |
10992 | { | |
10993 | lexer.skip_token (); | |
10994 | ||
10995 | // parse required pattern to bind | |
10996 | bind_pattern = parse_pattern (); | |
10997 | if (bind_pattern == nullptr) | |
10998 | { | |
10999 | Error error (lexer.peek_token ()->get_locus (), | |
11000 | "failed to parse pattern to bind in identifier pattern"); | |
11001 | add_error (std::move (error)); | |
11002 | ||
11003 | return nullptr; | |
11004 | } | |
11005 | } | |
11006 | ||
11007 | // DEBUG | |
11008 | rust_debug ("about to return identifier pattern"); | |
11009 | ||
11010 | return std::unique_ptr<AST::IdentifierPattern> ( | |
11011 | new AST::IdentifierPattern (std::move (ident), locus, has_ref, has_mut, | |
11012 | std::move (bind_pattern))); | |
11013 | } | |
11014 | ||
11015 | /* Parses a pattern that opens with an identifier. This includes identifier | |
11016 | * patterns, path patterns (and derivatives such as struct patterns, tuple | |
11017 | * struct patterns, and macro invocations), and ranges. */ | |
11018 | template <typename ManagedTokenSource> | |
11019 | std::unique_ptr<AST::Pattern> | |
11020 | Parser<ManagedTokenSource>::parse_ident_leading_pattern () | |
11021 | { | |
11022 | // ensure first token is actually identifier | |
11023 | const_TokenPtr initial_tok = lexer.peek_token (); | |
11024 | if (initial_tok->get_id () != IDENTIFIER) | |
11025 | { | |
11026 | return nullptr; | |
11027 | } | |
11028 | ||
11029 | // save initial identifier as it may be useful (but don't skip) | |
11030 | std::string initial_ident = initial_tok->get_str (); | |
11031 | ||
11032 | // parse next tokens as a PathInExpression | |
11033 | AST::PathInExpression path = parse_path_in_expression (); | |
11034 | ||
11035 | // branch on next token | |
11036 | const_TokenPtr t = lexer.peek_token (); | |
11037 | switch (t->get_id ()) | |
11038 | { | |
11039 | case EXCLAM: | |
11040 | return parse_macro_invocation_partial (std::move (path), AST::AttrVec ()); | |
11041 | case LEFT_PAREN: { | |
11042 | // tuple struct | |
11043 | lexer.skip_token (); | |
11044 | ||
11045 | // DEBUG | |
11046 | rust_debug ("parsing tuple struct pattern"); | |
11047 | ||
11048 | // check if empty tuple | |
11049 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
11050 | { | |
11051 | lexer.skip_token (); | |
11052 | return std::unique_ptr<AST::TupleStructPattern> ( | |
11053 | new AST::TupleStructPattern (std::move (path), nullptr)); | |
11054 | } | |
11055 | ||
11056 | // parse items | |
11057 | std::unique_ptr<AST::TupleStructItems> items | |
11058 | = parse_tuple_struct_items (); | |
11059 | if (items == nullptr) | |
11060 | { | |
11061 | Error error (lexer.peek_token ()->get_locus (), | |
11062 | "failed to parse tuple struct items"); | |
11063 | add_error (std::move (error)); | |
11064 | ||
11065 | return nullptr; | |
11066 | } | |
11067 | ||
11068 | // DEBUG | |
11069 | rust_debug ("successfully parsed tuple struct items"); | |
11070 | ||
11071 | if (!skip_token (RIGHT_PAREN)) | |
11072 | { | |
11073 | return nullptr; | |
11074 | } | |
11075 | ||
11076 | // DEBUG | |
11077 | rust_debug ("successfully parsed tuple struct pattern"); | |
11078 | ||
11079 | return std::unique_ptr<AST::TupleStructPattern> ( | |
11080 | new AST::TupleStructPattern (std::move (path), std::move (items))); | |
11081 | } | |
11082 | case LEFT_CURLY: { | |
11083 | // struct | |
11084 | lexer.skip_token (); | |
11085 | ||
11086 | // parse elements (optional) | |
11087 | AST::StructPatternElements elems = parse_struct_pattern_elems (); | |
11088 | ||
11089 | if (!skip_token (RIGHT_CURLY)) | |
11090 | { | |
11091 | return nullptr; | |
11092 | } | |
11093 | ||
11094 | // DEBUG | |
11095 | rust_debug ("successfully parsed struct pattern"); | |
11096 | ||
11097 | return std::unique_ptr<AST::StructPattern> ( | |
11098 | new AST::StructPattern (std::move (path), initial_tok->get_locus (), | |
11099 | std::move (elems))); | |
11100 | } | |
11101 | case DOT_DOT_EQ: | |
11102 | case ELLIPSIS: { | |
11103 | // range | |
11104 | bool has_ellipsis_syntax = lexer.peek_token ()->get_id () == ELLIPSIS; | |
11105 | ||
11106 | lexer.skip_token (); | |
11107 | ||
11108 | std::unique_ptr<AST::RangePatternBoundPath> lower_bound ( | |
11109 | new AST::RangePatternBoundPath (std::move (path))); | |
11110 | std::unique_ptr<AST::RangePatternBound> upper_bound | |
11111 | = parse_range_pattern_bound (); | |
11112 | ||
11113 | return std::unique_ptr<AST::RangePattern> (new AST::RangePattern ( | |
11114 | std::move (lower_bound), std::move (upper_bound), | |
11115 | Linemap::unknown_location (), has_ellipsis_syntax)); | |
11116 | } | |
11117 | case PATTERN_BIND: { | |
11118 | // only allow on single-segment paths | |
11119 | if (path.is_single_segment ()) | |
11120 | { | |
11121 | // identifier with pattern bind | |
11122 | lexer.skip_token (); | |
11123 | ||
11124 | std::unique_ptr<AST::Pattern> bind_pattern = parse_pattern (); | |
11125 | if (bind_pattern == nullptr) | |
11126 | { | |
11127 | Error error ( | |
11128 | t->get_locus (), | |
11129 | "failed to parse pattern to bind to identifier pattern"); | |
11130 | add_error (std::move (error)); | |
11131 | ||
11132 | return nullptr; | |
11133 | } | |
11134 | return std::unique_ptr<AST::IdentifierPattern> ( | |
11135 | new AST::IdentifierPattern (std::move (initial_ident), | |
11136 | initial_tok->get_locus (), false, | |
11137 | false, std::move (bind_pattern))); | |
11138 | } | |
11139 | Error error ( | |
11140 | t->get_locus (), | |
11141 | "failed to parse pattern bind to a path, not an identifier"); | |
11142 | add_error (std::move (error)); | |
11143 | ||
11144 | return nullptr; | |
11145 | } | |
11146 | default: | |
11147 | // assume identifier if single segment | |
11148 | if (path.is_single_segment ()) | |
11149 | { | |
11150 | return std::unique_ptr<AST::IdentifierPattern> ( | |
11151 | new AST::IdentifierPattern (std::move (initial_ident), | |
11152 | initial_tok->get_locus ())); | |
11153 | } | |
11154 | // return path otherwise | |
11155 | return std::unique_ptr<AST::PathInExpression> ( | |
11156 | new AST::PathInExpression (std::move (path))); | |
11157 | } | |
11158 | } | |
11159 | ||
11160 | // Parses tuple struct items if they exist. Does not parse parentheses. | |
11161 | template <typename ManagedTokenSource> | |
11162 | std::unique_ptr<AST::TupleStructItems> | |
11163 | Parser<ManagedTokenSource>::parse_tuple_struct_items () | |
11164 | { | |
11165 | std::vector<std::unique_ptr<AST::Pattern>> lower_patterns; | |
11166 | ||
11167 | // DEBUG | |
11168 | rust_debug ("started parsing tuple struct items"); | |
11169 | ||
11170 | // check for '..' at front | |
11171 | if (lexer.peek_token ()->get_id () == DOT_DOT) | |
11172 | { | |
11173 | // only parse upper patterns | |
11174 | lexer.skip_token (); | |
11175 | ||
11176 | // DEBUG | |
11177 | rust_debug ("'..' at front in tuple struct items detected"); | |
11178 | ||
11179 | std::vector<std::unique_ptr<AST::Pattern>> upper_patterns; | |
11180 | ||
11181 | const_TokenPtr t = lexer.peek_token (); | |
11182 | while (t->get_id () == COMMA) | |
11183 | { | |
11184 | lexer.skip_token (); | |
11185 | ||
11186 | // break if right paren | |
11187 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
11188 | break; | |
11189 | ||
11190 | // parse pattern, which is now required | |
11191 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
11192 | if (pattern == nullptr) | |
11193 | { | |
11194 | Error error (lexer.peek_token ()->get_locus (), | |
11195 | "failed to parse pattern in tuple struct items"); | |
11196 | add_error (std::move (error)); | |
11197 | ||
11198 | return nullptr; | |
11199 | } | |
11200 | upper_patterns.push_back (std::move (pattern)); | |
11201 | ||
11202 | t = lexer.peek_token (); | |
11203 | } | |
11204 | ||
11205 | // DEBUG | |
11206 | rust_debug ( | |
11207 | "finished parsing tuple struct items ranged (upper/none only)"); | |
11208 | ||
11209 | return std::unique_ptr<AST::TupleStructItemsRange> ( | |
11210 | new AST::TupleStructItemsRange (std::move (lower_patterns), | |
11211 | std::move (upper_patterns))); | |
11212 | } | |
11213 | ||
11214 | // has at least some lower patterns | |
11215 | const_TokenPtr t = lexer.peek_token (); | |
11216 | while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT) | |
11217 | { | |
11218 | // DEBUG | |
11219 | rust_debug ("about to parse pattern in tuple struct items"); | |
11220 | ||
11221 | // parse pattern, which is required | |
11222 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
11223 | if (pattern == nullptr) | |
11224 | { | |
11225 | Error error (t->get_locus (), | |
11226 | "failed to parse pattern in tuple struct items"); | |
11227 | add_error (std::move (error)); | |
11228 | ||
11229 | return nullptr; | |
11230 | } | |
11231 | lower_patterns.push_back (std::move (pattern)); | |
11232 | ||
11233 | // DEBUG | |
11234 | rust_debug ("successfully parsed pattern in tuple struct items"); | |
11235 | ||
11236 | if (lexer.peek_token ()->get_id () != COMMA) | |
11237 | { | |
11238 | // DEBUG | |
11239 | rust_debug ("broke out of parsing patterns in tuple struct " | |
11240 | "items as no comma"); | |
11241 | ||
11242 | break; | |
11243 | } | |
11244 | lexer.skip_token (); | |
11245 | t = lexer.peek_token (); | |
11246 | } | |
11247 | ||
11248 | // branch on next token | |
11249 | t = lexer.peek_token (); | |
11250 | switch (t->get_id ()) | |
11251 | { | |
11252 | case RIGHT_PAREN: | |
11253 | return std::unique_ptr<AST::TupleStructItemsNoRange> ( | |
11254 | new AST::TupleStructItemsNoRange (std::move (lower_patterns))); | |
11255 | case DOT_DOT: { | |
11256 | // has an upper range that must be parsed separately | |
11257 | lexer.skip_token (); | |
11258 | ||
11259 | std::vector<std::unique_ptr<AST::Pattern>> upper_patterns; | |
11260 | ||
11261 | t = lexer.peek_token (); | |
11262 | while (t->get_id () == COMMA) | |
11263 | { | |
11264 | lexer.skip_token (); | |
11265 | ||
11266 | // break if next token is right paren | |
11267 | if (lexer.peek_token ()->get_id () == RIGHT_PAREN) | |
11268 | break; | |
11269 | ||
11270 | // parse pattern, which is required | |
11271 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
11272 | if (pattern == nullptr) | |
11273 | { | |
11274 | Error error (lexer.peek_token ()->get_locus (), | |
11275 | "failed to parse pattern in tuple struct items"); | |
11276 | add_error (std::move (error)); | |
11277 | ||
11278 | return nullptr; | |
11279 | } | |
11280 | upper_patterns.push_back (std::move (pattern)); | |
11281 | ||
11282 | t = lexer.peek_token (); | |
11283 | } | |
11284 | ||
11285 | return std::unique_ptr<AST::TupleStructItemsRange> ( | |
11286 | new AST::TupleStructItemsRange (std::move (lower_patterns), | |
11287 | std::move (upper_patterns))); | |
11288 | } | |
11289 | default: | |
11290 | // error | |
11291 | add_error (Error (t->get_locus (), | |
11292 | "unexpected token %qs in tuple struct items", | |
11293 | t->get_token_description ())); | |
11294 | ||
11295 | return nullptr; | |
11296 | } | |
11297 | } | |
11298 | ||
11299 | // Parses struct pattern elements if they exist. | |
11300 | template <typename ManagedTokenSource> | |
11301 | AST::StructPatternElements | |
11302 | Parser<ManagedTokenSource>::parse_struct_pattern_elems () | |
11303 | { | |
11304 | std::vector<std::unique_ptr<AST::StructPatternField>> fields; | |
11305 | ||
11306 | AST::AttrVec etc_attrs; | |
11307 | bool has_etc = false; | |
11308 | ||
11309 | // try parsing struct pattern fields | |
11310 | const_TokenPtr t = lexer.peek_token (); | |
11311 | while (t->get_id () != RIGHT_CURLY) | |
11312 | { | |
11313 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
11314 | ||
11315 | // parse etc (must be last in struct pattern, so breaks) | |
11316 | if (lexer.peek_token ()->get_id () == DOT_DOT) | |
11317 | { | |
11318 | lexer.skip_token (); | |
11319 | etc_attrs = std::move (outer_attrs); | |
11320 | has_etc = true; | |
11321 | break; | |
11322 | } | |
11323 | ||
11324 | std::unique_ptr<AST::StructPatternField> field | |
11325 | = parse_struct_pattern_field_partial (std::move (outer_attrs)); | |
11326 | if (field == nullptr) | |
11327 | { | |
11328 | Error error (lexer.peek_token ()->get_locus (), | |
11329 | "failed to parse struct pattern field"); | |
11330 | add_error (std::move (error)); | |
11331 | ||
11332 | // skip after somewhere? | |
11333 | return AST::StructPatternElements::create_empty (); | |
11334 | } | |
11335 | fields.push_back (std::move (field)); | |
11336 | ||
11337 | if (lexer.peek_token ()->get_id () != COMMA) | |
11338 | break; | |
11339 | ||
11340 | // skip comma | |
11341 | lexer.skip_token (); | |
11342 | t = lexer.peek_token (); | |
11343 | } | |
11344 | ||
11345 | if (has_etc) | |
11346 | return AST::StructPatternElements (std::move (fields), | |
11347 | std::move (etc_attrs)); | |
11348 | else | |
11349 | return AST::StructPatternElements (std::move (fields)); | |
11350 | } | |
11351 | ||
11352 | /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or | |
11353 | * identifier). */ | |
11354 | template <typename ManagedTokenSource> | |
11355 | std::unique_ptr<AST::StructPatternField> | |
11356 | Parser<ManagedTokenSource>::parse_struct_pattern_field () | |
11357 | { | |
11358 | // parse outer attributes (if they exist) | |
11359 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
11360 | ||
11361 | return parse_struct_pattern_field_partial (std::move (outer_attrs)); | |
11362 | } | |
11363 | ||
11364 | /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or | |
11365 | * identifier), with outer attributes passed in. */ | |
11366 | template <typename ManagedTokenSource> | |
11367 | std::unique_ptr<AST::StructPatternField> | |
11368 | Parser<ManagedTokenSource>::parse_struct_pattern_field_partial ( | |
11369 | AST::AttrVec outer_attrs) | |
11370 | { | |
11371 | // branch based on next token | |
11372 | const_TokenPtr t = lexer.peek_token (); | |
11373 | switch (t->get_id ()) | |
11374 | { | |
11375 | case INT_LITERAL: { | |
11376 | // tuple index | |
11377 | std::string index_str = t->get_str (); | |
11378 | int index = atoi (index_str.c_str ()); | |
11379 | ||
11380 | if (!skip_token (COLON)) | |
11381 | { | |
11382 | return nullptr; | |
11383 | } | |
11384 | ||
11385 | // parse required pattern | |
11386 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
11387 | if (pattern == nullptr) | |
11388 | { | |
11389 | Error error ( | |
11390 | t->get_locus (), | |
11391 | "failed to parse pattern in tuple index struct pattern field"); | |
11392 | add_error (std::move (error)); | |
11393 | ||
11394 | return nullptr; | |
11395 | } | |
11396 | ||
11397 | return std::unique_ptr<AST::StructPatternFieldTuplePat> ( | |
11398 | new AST::StructPatternFieldTuplePat (index, std::move (pattern), | |
11399 | std::move (outer_attrs), | |
11400 | t->get_locus ())); | |
11401 | } | |
11402 | case IDENTIFIER: | |
11403 | // identifier-pattern OR only identifier | |
11404 | // branch on next token | |
11405 | switch (lexer.peek_token (1)->get_id ()) | |
11406 | { | |
11407 | case COLON: { | |
11408 | // identifier-pattern | |
11409 | Identifier ident = t->get_str (); | |
11410 | lexer.skip_token (); | |
11411 | ||
11412 | skip_token (COLON); | |
11413 | ||
11414 | // parse required pattern | |
11415 | std::unique_ptr<AST::Pattern> pattern = parse_pattern (); | |
11416 | if (pattern == nullptr) | |
11417 | { | |
11418 | Error error (t->get_locus (), | |
11419 | "failed to parse pattern in struct pattern field"); | |
11420 | add_error (std::move (error)); | |
11421 | ||
11422 | return nullptr; | |
11423 | } | |
11424 | ||
11425 | return std::unique_ptr<AST::StructPatternFieldIdentPat> ( | |
11426 | new AST::StructPatternFieldIdentPat (std::move (ident), | |
11427 | std::move (pattern), | |
11428 | std::move (outer_attrs), | |
11429 | t->get_locus ())); | |
11430 | } | |
11431 | case COMMA: | |
11432 | case RIGHT_CURLY: { | |
11433 | // identifier only | |
11434 | Identifier ident = t->get_str (); | |
11435 | lexer.skip_token (); | |
11436 | ||
11437 | return std::unique_ptr<AST::StructPatternFieldIdent> ( | |
11438 | new AST::StructPatternFieldIdent (std::move (ident), false, false, | |
11439 | std::move (outer_attrs), | |
11440 | t->get_locus ())); | |
11441 | } | |
11442 | default: | |
11443 | // error | |
11444 | add_error (Error (t->get_locus (), | |
11445 | "unrecognised token %qs in struct pattern field", | |
11446 | t->get_token_description ())); | |
11447 | ||
11448 | return nullptr; | |
11449 | } | |
11450 | case REF: | |
11451 | case MUT: { | |
11452 | // only identifier | |
11453 | bool has_ref = false; | |
11454 | if (t->get_id () == REF) | |
11455 | { | |
11456 | has_ref = true; | |
11457 | lexer.skip_token (); | |
11458 | } | |
11459 | ||
11460 | bool has_mut = false; | |
11461 | if (lexer.peek_token ()->get_id () == MUT) | |
11462 | { | |
11463 | has_mut = true; | |
11464 | lexer.skip_token (); | |
11465 | } | |
11466 | ||
11467 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
11468 | if (ident_tok == nullptr) | |
11469 | { | |
11470 | return nullptr; | |
11471 | } | |
11472 | Identifier ident = ident_tok->get_str (); | |
11473 | ||
11474 | return std::unique_ptr<AST::StructPatternFieldIdent> ( | |
11475 | new AST::StructPatternFieldIdent (std::move (ident), has_ref, has_mut, | |
11476 | std::move (outer_attrs), | |
11477 | t->get_locus ())); | |
11478 | } | |
11479 | default: | |
11480 | // not necessarily an error | |
11481 | return nullptr; | |
11482 | } | |
11483 | } | |
11484 | ||
11485 | template <typename ManagedTokenSource> | |
11486 | ExprOrStmt | |
11487 | Parser<ManagedTokenSource>::parse_stmt_or_expr_with_block ( | |
11488 | AST::AttrVec outer_attrs) | |
11489 | { | |
11490 | auto expr = parse_expr_with_block (std::move (outer_attrs)); | |
11491 | if (expr == nullptr) | |
11492 | return ExprOrStmt::create_error (); | |
11493 | ||
11494 | auto tok = lexer.peek_token (); | |
11495 | ||
11496 | // tail expr in a block expr | |
11497 | if (tok->get_id () == RIGHT_CURLY) | |
11498 | return ExprOrStmt (std::move (expr)); | |
11499 | ||
11500 | // internal block expr must either have semicolons followed, or evaluate to | |
11501 | // () | |
11502 | auto locus = expr->get_locus (); | |
11503 | std::unique_ptr<AST::ExprStmtWithBlock> stmt ( | |
11504 | new AST::ExprStmtWithBlock (std::move (expr), locus, | |
11505 | tok->get_id () == SEMICOLON)); | |
11506 | if (tok->get_id () == SEMICOLON) | |
11507 | lexer.skip_token (); | |
11508 | ||
11509 | return ExprOrStmt (std::move (stmt)); | |
11510 | } | |
11511 | ||
11512 | /* Parses a statement or expression (depending on whether a trailing semicolon | |
11513 | * exists). Useful for block expressions where it cannot be determined through | |
11514 | * lookahead whether it is a statement or expression to be parsed. */ | |
11515 | template <typename ManagedTokenSource> | |
11516 | ExprOrStmt | |
11517 | Parser<ManagedTokenSource>::parse_stmt_or_expr_without_block () | |
11518 | { | |
11519 | // quick exit for empty statement | |
11520 | const_TokenPtr t = lexer.peek_token (); | |
11521 | if (t->get_id () == SEMICOLON) | |
11522 | { | |
11523 | lexer.skip_token (); | |
11524 | std::unique_ptr<AST::EmptyStmt> stmt ( | |
11525 | new AST::EmptyStmt (t->get_locus ())); | |
11526 | return ExprOrStmt (std::move (stmt)); | |
11527 | } | |
11528 | ||
11529 | // parse outer attributes | |
11530 | AST::AttrVec outer_attrs = parse_outer_attributes (); | |
11531 | ||
11532 | // parsing this will be annoying because of the many different possibilities | |
11533 | /* best may be just to copy paste in parse_item switch, and failing that try | |
11534 | * to parse outer attributes, and then pass them in to either a let | |
11535 | * statement or (fallback) expression statement. */ | |
11536 | // FIXME: think of a way to do this without such a large switch? | |
11537 | ||
11538 | /* FIXME: for expressions at least, the only way that they can really be | |
11539 | * parsed properly in this way is if they don't support operators on them. | |
11540 | * They must be pratt-parsed otherwise. As such due to composability, only | |
11541 | * explicit statements will have special cases here. This should roughly | |
11542 | * correspond to "expr-with-block", but this warning is here in case it | |
11543 | * isn't the case. */ | |
11544 | t = lexer.peek_token (); | |
11545 | switch (t->get_id ()) | |
11546 | { | |
11547 | case LET: { | |
11548 | // let statement | |
11549 | std::unique_ptr<AST::LetStmt> stmt ( | |
11550 | parse_let_stmt (std::move (outer_attrs))); | |
11551 | return ExprOrStmt (std::move (stmt)); | |
11552 | } | |
11553 | case PUB: | |
11554 | case MOD: | |
11555 | case EXTERN_TOK: | |
11556 | case USE: | |
11557 | case FN_TOK: | |
11558 | case TYPE: | |
11559 | case STRUCT_TOK: | |
11560 | case ENUM_TOK: | |
11561 | case CONST: | |
11562 | case STATIC_TOK: | |
11563 | case TRAIT: | |
11564 | case IMPL: { | |
11565 | std::unique_ptr<AST::VisItem> item ( | |
11566 | parse_vis_item (std::move (outer_attrs))); | |
11567 | return ExprOrStmt (std::move (item)); | |
11568 | } | |
11569 | /* TODO: implement union keyword but not really because of | |
11570 | * context-dependence crappy hack way to parse a union written below to | |
11571 | * separate it from the good code. */ | |
11572 | // case UNION: | |
11573 | case UNSAFE: { // maybe - unsafe traits are a thing | |
11574 | /* if any of these (should be all possible VisItem prefixes), parse a | |
11575 | * VisItem - can't parse item because would require reparsing outer | |
11576 | * attributes */ | |
11577 | const_TokenPtr t2 = lexer.peek_token (1); | |
11578 | switch (t2->get_id ()) | |
11579 | { | |
11580 | case LEFT_CURLY: { | |
11581 | // unsafe block | |
11582 | return parse_stmt_or_expr_with_block (std::move (outer_attrs)); | |
11583 | } | |
11584 | case TRAIT: { | |
11585 | // unsafe trait | |
11586 | std::unique_ptr<AST::VisItem> item ( | |
11587 | parse_vis_item (std::move (outer_attrs))); | |
11588 | return ExprOrStmt (std::move (item)); | |
11589 | } | |
11590 | case EXTERN_TOK: | |
11591 | case FN_TOK: { | |
11592 | // unsafe function | |
11593 | std::unique_ptr<AST::VisItem> item ( | |
11594 | parse_vis_item (std::move (outer_attrs))); | |
11595 | return ExprOrStmt (std::move (item)); | |
11596 | } | |
11597 | case IMPL: { | |
11598 | // unsafe trait impl | |
11599 | std::unique_ptr<AST::VisItem> item ( | |
11600 | parse_vis_item (std::move (outer_attrs))); | |
11601 | return ExprOrStmt (std::move (item)); | |
11602 | } | |
11603 | default: | |
11604 | add_error (Error (t2->get_locus (), | |
11605 | "unrecognised token %qs after parsing unsafe - " | |
11606 | "expected beginning of expression or statement", | |
11607 | t->get_token_description ())); | |
11608 | ||
11609 | // skip somewhere? | |
11610 | return ExprOrStmt::create_error (); | |
11611 | } | |
11612 | } | |
11613 | case SUPER: | |
11614 | case SELF: | |
11615 | case CRATE: | |
11616 | case DOLLAR_SIGN: { | |
11617 | /* path-based thing so struct/enum or path or macro invocation of a | |
11618 | * kind. however, the expressions are composable (i think) */ | |
11619 | ||
11620 | std::unique_ptr<AST::ExprWithoutBlock> expr | |
11621 | = parse_expr_without_block (); | |
11622 | ||
11623 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
11624 | { | |
11625 | // must be expression statement | |
11626 | lexer.skip_token (); | |
11627 | ||
11628 | std::unique_ptr<AST::ExprStmtWithoutBlock> stmt ( | |
11629 | new AST::ExprStmtWithoutBlock (std::move (expr), | |
11630 | t->get_locus ())); | |
11631 | return ExprOrStmt (std::move (stmt)); | |
11632 | } | |
11633 | ||
11634 | // return expression | |
11635 | return ExprOrStmt (std::move (expr)); | |
11636 | } | |
11637 | /* FIXME: this is either a macro invocation or macro invocation semi. | |
11638 | * start parsing to determine which one it is. */ | |
11639 | // FIXME: or this is another path-based thing - struct/enum or path | |
11640 | // itself return parse_path_based_stmt_or_expr(std::move(outer_attrs)); | |
11641 | // FIXME: old code there | |
11642 | case LOOP: | |
11643 | case WHILE: | |
11644 | case FOR: | |
11645 | case IF: | |
11646 | case MATCH_TOK: | |
11647 | case LEFT_CURLY: | |
11648 | case ASYNC: { | |
11649 | return parse_stmt_or_expr_with_block (std::move (outer_attrs)); | |
11650 | } | |
11651 | case LIFETIME: { | |
11652 | /* FIXME: are there any expressions without blocks that can have | |
11653 | * lifetime as their first token? Or is loop expr the only one? */ | |
11654 | // safe side for now: | |
11655 | const_TokenPtr t2 = lexer.peek_token (2); | |
11656 | if (lexer.peek_token (1)->get_id () == COLON | |
11657 | && (t2->get_id () == LOOP || t2->get_id () == WHILE | |
11658 | || t2->get_id () == FOR)) | |
11659 | { | |
11660 | return parse_stmt_or_expr_with_block (std::move (outer_attrs)); | |
11661 | } | |
11662 | else | |
11663 | { | |
11664 | // should be expr without block | |
11665 | std::unique_ptr<AST::ExprWithoutBlock> expr | |
11666 | = parse_expr_without_block (std::move (outer_attrs)); | |
11667 | ||
11668 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
11669 | { | |
11670 | // must be expression statement | |
11671 | lexer.skip_token (); | |
11672 | ||
11673 | std::unique_ptr<AST::ExprStmtWithoutBlock> stmt ( | |
11674 | new AST::ExprStmtWithoutBlock (std::move (expr), | |
11675 | t->get_locus ())); | |
11676 | return ExprOrStmt (std::move (stmt)); | |
11677 | } | |
11678 | ||
11679 | // return expression | |
11680 | return ExprOrStmt (std::move (expr)); | |
11681 | } | |
11682 | } | |
11683 | // crappy hack to do union "keyword" | |
11684 | case IDENTIFIER: | |
11685 | if (t->get_str () == "union" | |
11686 | && lexer.peek_token (1)->get_id () == IDENTIFIER) | |
11687 | { | |
11688 | std::unique_ptr<AST::VisItem> item ( | |
11689 | parse_vis_item (std::move (outer_attrs))); | |
11690 | return ExprOrStmt (std::move (item)); | |
11691 | // or should this go straight to parsing union? | |
11692 | } | |
11693 | else if (t->get_str () == "macro_rules") | |
11694 | { | |
11695 | // macro_rules! macro item | |
11696 | std::unique_ptr<AST::MacroItem> item ( | |
11697 | parse_macro_item (std::move (outer_attrs))); | |
11698 | return ExprOrStmt (std::move (item)); | |
11699 | } | |
11700 | else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION | |
11701 | || lexer.peek_token (1)->get_id () == EXCLAM | |
11702 | || lexer.peek_token (1)->get_id () == LEFT_CURLY) | |
11703 | { | |
11704 | /* path (probably) or macro invocation or struct or enum, so | |
11705 | * probably a macro invocation semi decide how to parse - probably | |
11706 | * parse path and then get macro from it */ | |
11707 | ||
11708 | // FIXME: old code was good until composability was required | |
11709 | // return parse_path_based_stmt_or_expr(std::move(outer_attrs)); | |
11710 | std::unique_ptr<AST::ExprWithoutBlock> expr | |
11711 | = parse_expr_without_block (std::move (outer_attrs)); | |
11712 | ||
11713 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
11714 | { | |
11715 | // must be expression statement | |
11716 | lexer.skip_token (); | |
11717 | ||
11718 | std::unique_ptr<AST::ExprStmtWithoutBlock> stmt ( | |
11719 | new AST::ExprStmtWithoutBlock (std::move (expr), | |
11720 | t->get_locus ())); | |
11721 | return ExprOrStmt (std::move (stmt)); | |
11722 | } | |
11723 | ||
11724 | // return expression | |
11725 | return ExprOrStmt (std::move (expr)); | |
11726 | } | |
11727 | gcc_fallthrough (); | |
11728 | // TODO: find out how to disable gcc "implicit fallthrough" warning | |
11729 | default: { | |
11730 | /* expression statement (without block) or expression itself - parse | |
11731 | * expression then make it statement if semi afterwards */ | |
11732 | ||
11733 | std::unique_ptr<AST::ExprWithoutBlock> expr | |
11734 | = parse_expr_without_block (std::move (outer_attrs)); | |
11735 | ||
11736 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
11737 | { | |
11738 | // must be expression statement | |
11739 | lexer.skip_token (); | |
11740 | ||
11741 | std::unique_ptr<AST::ExprStmtWithoutBlock> stmt ( | |
11742 | new AST::ExprStmtWithoutBlock (std::move (expr), | |
11743 | t->get_locus ())); | |
11744 | return ExprOrStmt (std::move (stmt)); | |
11745 | } | |
11746 | ||
11747 | // return expression | |
11748 | return ExprOrStmt (std::move (expr)); | |
11749 | } | |
11750 | } | |
11751 | } | |
11752 | ||
11753 | /* Parses a statement or expression beginning with a path (i.e. macro, | |
11754 | * struct/enum, or path expr) */ | |
11755 | template <typename ManagedTokenSource> | |
11756 | ExprOrStmt | |
11757 | Parser<ManagedTokenSource>::parse_path_based_stmt_or_expr ( | |
11758 | AST::AttrVec outer_attrs) | |
11759 | { | |
11760 | // attempt to parse path | |
11761 | Location stmt_or_expr_loc = lexer.peek_token ()->get_locus (); | |
11762 | AST::PathInExpression path = parse_path_in_expression (); | |
11763 | ||
11764 | // branch on next token | |
11765 | const_TokenPtr t2 = lexer.peek_token (); | |
11766 | switch (t2->get_id ()) | |
11767 | { | |
11768 | case EXCLAM: { | |
11769 | /* macro invocation or macro invocation semi - depends on whether | |
11770 | * there is a final ';' */ | |
11771 | // convert path in expr to simple path (as that is used in macros) | |
11772 | AST::SimplePath macro_path = path.as_simple_path (); | |
11773 | if (macro_path.is_empty ()) | |
11774 | { | |
11775 | Error error (t2->get_locus (), | |
11776 | "failed to convert parsed path to simple " | |
11777 | "path (for macro invocation or semi)"); | |
11778 | add_error (std::move (error)); | |
11779 | ||
11780 | return ExprOrStmt::create_error (); | |
11781 | } | |
11782 | ||
11783 | // skip exclamation mark | |
11784 | lexer.skip_token (); | |
11785 | ||
11786 | const_TokenPtr t3 = lexer.peek_token (); | |
11787 | Location tok_tree_loc = t3->get_locus (); | |
11788 | ||
11789 | AST::DelimType type = AST::PARENS; | |
11790 | switch (t3->get_id ()) | |
11791 | { | |
11792 | case LEFT_PAREN: | |
11793 | type = AST::PARENS; | |
11794 | break; | |
11795 | case LEFT_SQUARE: | |
11796 | type = AST::SQUARE; | |
11797 | break; | |
11798 | case LEFT_CURLY: | |
11799 | type = AST::CURLY; | |
11800 | break; | |
11801 | default: | |
11802 | add_error ( | |
11803 | Error (t3->get_locus (), | |
11804 | "unrecognised token %qs in macro invocation - (opening) " | |
11805 | "delimiter expected", | |
11806 | t3->get_token_description ())); | |
11807 | ||
11808 | return ExprOrStmt::create_error (); | |
11809 | } | |
11810 | lexer.skip_token (); | |
11811 | ||
11812 | // parse actual token trees | |
11813 | std::vector<std::unique_ptr<AST::TokenTree>> token_trees; | |
11814 | auto delim_open | |
11815 | = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3))); | |
11816 | token_trees.push_back (std::move (delim_open)); | |
11817 | ||
11818 | t3 = lexer.peek_token (); | |
11819 | // parse token trees until the initial delimiter token is found again | |
11820 | while (!token_id_matches_delims (t3->get_id (), type)) | |
11821 | { | |
11822 | std::unique_ptr<AST::TokenTree> tree = parse_token_tree (); | |
11823 | ||
11824 | if (tree == nullptr) | |
11825 | { | |
11826 | Error error (t3->get_locus (), | |
11827 | "failed to parse token tree for macro " | |
11828 | "invocation (or semi) - " | |
11829 | "found %qs", | |
11830 | t3->get_token_description ()); | |
11831 | add_error (std::move (error)); | |
11832 | ||
11833 | return ExprOrStmt::create_error (); | |
11834 | } | |
11835 | ||
11836 | token_trees.push_back (std::move (tree)); | |
11837 | ||
11838 | t3 = lexer.peek_token (); | |
11839 | } | |
11840 | ||
11841 | auto delim_close | |
11842 | = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3))); | |
11843 | token_trees.push_back (std::move (delim_close)); | |
11844 | ||
11845 | // parse end delimiters | |
11846 | t3 = lexer.peek_token (); | |
11847 | if (token_id_matches_delims (t3->get_id (), type)) | |
11848 | { | |
11849 | // tokens match opening delimiter, so skip. | |
11850 | lexer.skip_token (); | |
11851 | ||
11852 | /* with curly bracketed macros, assume it is a macro invocation | |
11853 | * unless a semicolon is explicitly put at the end. this is not | |
11854 | * necessarily true (i.e. context-dependence) and so may have to | |
11855 | * be fixed up via HACKs in semantic analysis (by checking whether | |
11856 | * it is the last elem in the vector). */ | |
11857 | ||
11858 | AST::DelimTokenTree delim_tok_tree (type, std::move (token_trees), | |
11859 | tok_tree_loc); | |
11860 | AST::MacroInvocData invoc_data (std::move (macro_path), | |
11861 | std::move (delim_tok_tree)); | |
11862 | ||
11863 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
11864 | { | |
11865 | lexer.skip_token (); | |
11866 | ||
11867 | std::unique_ptr<AST::MacroInvocation> stmt ( | |
11868 | new AST::MacroInvocation (std::move (invoc_data), | |
11869 | std::move (outer_attrs), | |
11870 | stmt_or_expr_loc, true)); | |
11871 | return ExprOrStmt (std::move (stmt)); | |
11872 | } | |
11873 | ||
11874 | // otherwise, create macro invocation | |
11875 | std::unique_ptr<AST::MacroInvocation> expr ( | |
11876 | new AST::MacroInvocation (std::move (invoc_data), | |
11877 | std::move (outer_attrs), | |
11878 | stmt_or_expr_loc, false)); | |
11879 | return ExprOrStmt (std::move (expr)); | |
11880 | } | |
11881 | else | |
11882 | { | |
11883 | // tokens don't match opening delimiters, so produce error | |
11884 | Error error ( | |
11885 | t2->get_locus (), | |
11886 | "unexpected token %qs - expecting closing delimiter %qs (for a " | |
11887 | "macro invocation)", | |
11888 | t2->get_token_description (), | |
11889 | (type == AST::PARENS ? ")" : (type == AST::SQUARE ? "]" : "}"))); | |
11890 | add_error (std::move (error)); | |
11891 | ||
11892 | return ExprOrStmt::create_error (); | |
11893 | } | |
11894 | } | |
11895 | case LEFT_CURLY: { | |
11896 | /* definitely not a block: | |
11897 | * path '{' ident ',' | |
11898 | * path '{' ident ':' [anything] ',' | |
11899 | * path '{' ident ':' [not a type] | |
11900 | * otherwise, assume block expr and thus path */ | |
11901 | bool not_a_block = lexer.peek_token (1)->get_id () == IDENTIFIER | |
11902 | && (lexer.peek_token (2)->get_id () == COMMA | |
11903 | || (lexer.peek_token (2)->get_id () == COLON | |
11904 | && (lexer.peek_token (4)->get_id () == COMMA | |
11905 | || !can_tok_start_type ( | |
11906 | lexer.peek_token (3)->get_id ())))); | |
11907 | std::unique_ptr<AST::ExprWithoutBlock> expr = nullptr; | |
11908 | ||
11909 | if (not_a_block) | |
11910 | { | |
11911 | /* assume struct expr struct (as struct-enum disambiguation | |
11912 | * requires name lookup) again, make statement if final ';' */ | |
11913 | expr = parse_struct_expr_struct_partial (std::move (path), | |
11914 | std::move (outer_attrs)); | |
11915 | if (expr == nullptr) | |
11916 | { | |
11917 | Error error (t2->get_locus (), | |
11918 | "failed to parse struct expr struct"); | |
11919 | add_error (std::move (error)); | |
11920 | ||
11921 | return ExprOrStmt::create_error (); | |
11922 | } | |
11923 | } | |
11924 | else | |
11925 | { | |
11926 | // assume path - make statement if final ';' | |
11927 | // lexer.skip_token(); | |
11928 | ||
11929 | // HACK: add outer attrs to path | |
11930 | path.set_outer_attrs (std::move (outer_attrs)); | |
11931 | expr = std::unique_ptr<AST::PathInExpression> ( | |
11932 | new AST::PathInExpression (std::move (path))); | |
11933 | } | |
11934 | ||
11935 | // determine if statement if ends with semicolon | |
11936 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
11937 | { | |
11938 | // statement | |
11939 | lexer.skip_token (); | |
11940 | std::unique_ptr<AST::ExprStmtWithoutBlock> stmt ( | |
11941 | new AST::ExprStmtWithoutBlock (std::move (expr), | |
11942 | stmt_or_expr_loc)); | |
11943 | return ExprOrStmt (std::move (stmt)); | |
11944 | } | |
11945 | ||
11946 | // otherwise, expression | |
11947 | return ExprOrStmt (std::move (expr)); | |
11948 | } | |
11949 | case LEFT_PAREN: { | |
11950 | /* assume struct expr tuple (as struct-enum disambiguation requires | |
11951 | * name lookup) again, make statement if final ';' */ | |
11952 | std::unique_ptr<AST::CallExpr> struct_expr | |
11953 | = parse_struct_expr_tuple_partial (std::move (path), | |
11954 | std::move (outer_attrs)); | |
11955 | if (struct_expr == nullptr) | |
11956 | { | |
11957 | Error error (t2->get_locus (), "failed to parse struct expr tuple"); | |
11958 | add_error (std::move (error)); | |
11959 | ||
11960 | return ExprOrStmt::create_error (); | |
11961 | } | |
11962 | ||
11963 | // determine if statement if ends with semicolon | |
11964 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
11965 | { | |
11966 | // statement | |
11967 | lexer.skip_token (); | |
11968 | std::unique_ptr<AST::ExprStmtWithoutBlock> stmt ( | |
11969 | new AST::ExprStmtWithoutBlock (std::move (struct_expr), | |
11970 | stmt_or_expr_loc)); | |
11971 | return ExprOrStmt (std::move (stmt)); | |
11972 | } | |
11973 | ||
11974 | // otherwise, expression | |
11975 | return ExprOrStmt (std::move (struct_expr)); | |
11976 | } | |
11977 | default: { | |
11978 | // assume path - make statement if final ';' | |
11979 | // lexer.skip_token(); | |
11980 | ||
11981 | // HACK: replace outer attributes in path | |
11982 | path.set_outer_attrs (std::move (outer_attrs)); | |
11983 | std::unique_ptr<AST::PathInExpression> expr ( | |
11984 | new AST::PathInExpression (std::move (path))); | |
11985 | ||
11986 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
11987 | { | |
11988 | lexer.skip_token (); | |
11989 | ||
11990 | std::unique_ptr<AST::ExprStmtWithoutBlock> stmt ( | |
11991 | new AST::ExprStmtWithoutBlock (std::move (expr), | |
11992 | stmt_or_expr_loc)); | |
11993 | return ExprOrStmt (std::move (stmt)); | |
11994 | } | |
11995 | ||
11996 | return ExprOrStmt (std::move (expr)); | |
11997 | } | |
11998 | } | |
11999 | } | |
12000 | ||
12001 | // Parses a struct expression field. | |
12002 | template <typename ManagedTokenSource> | |
12003 | std::unique_ptr<AST::StructExprField> | |
12004 | Parser<ManagedTokenSource>::parse_struct_expr_field () | |
12005 | { | |
12006 | const_TokenPtr t = lexer.peek_token (); | |
12007 | switch (t->get_id ()) | |
12008 | { | |
12009 | case IDENTIFIER: | |
12010 | if (lexer.peek_token (1)->get_id () == COLON) | |
12011 | { | |
12012 | // struct expr field with identifier and expr | |
12013 | Identifier ident = t->get_str (); | |
12014 | lexer.skip_token (1); | |
12015 | ||
12016 | // parse expression (required) | |
12017 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
12018 | if (expr == nullptr) | |
12019 | { | |
12020 | Error error (t->get_locus (), | |
12021 | "failed to parse struct expression field with " | |
12022 | "identifier and expression"); | |
12023 | add_error (std::move (error)); | |
12024 | ||
12025 | return nullptr; | |
12026 | } | |
12027 | ||
12028 | return std::unique_ptr<AST::StructExprFieldIdentifierValue> ( | |
12029 | new AST::StructExprFieldIdentifierValue (std::move (ident), | |
12030 | std::move (expr), | |
12031 | t->get_locus ())); | |
12032 | } | |
12033 | else | |
12034 | { | |
12035 | // struct expr field with identifier only | |
12036 | Identifier ident = t->get_str (); | |
12037 | lexer.skip_token (); | |
12038 | ||
12039 | return std::unique_ptr<AST::StructExprFieldIdentifier> ( | |
12040 | new AST::StructExprFieldIdentifier (std::move (ident), | |
12041 | t->get_locus ())); | |
12042 | } | |
12043 | case INT_LITERAL: { | |
12044 | // parse tuple index field | |
12045 | int index = atoi (t->get_str ().c_str ()); | |
12046 | lexer.skip_token (); | |
12047 | ||
12048 | if (!skip_token (COLON)) | |
12049 | { | |
12050 | // skip somewhere? | |
12051 | return nullptr; | |
12052 | } | |
12053 | ||
12054 | // parse field expression (required) | |
12055 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
12056 | if (expr == nullptr) | |
12057 | { | |
12058 | Error error (t->get_locus (), | |
12059 | "failed to parse expr in struct (or enum) expr " | |
12060 | "field with tuple index"); | |
12061 | add_error (std::move (error)); | |
12062 | ||
12063 | return nullptr; | |
12064 | } | |
12065 | ||
12066 | return std::unique_ptr<AST::StructExprFieldIndexValue> ( | |
12067 | new AST::StructExprFieldIndexValue (index, std::move (expr), | |
12068 | t->get_locus ())); | |
12069 | } | |
12070 | case DOT_DOT: | |
12071 | /* this is a struct base and can't be parsed here, so just return | |
12072 | * nothing without erroring */ | |
12073 | ||
12074 | return nullptr; | |
12075 | default: | |
12076 | add_error ( | |
12077 | Error (t->get_locus (), | |
12078 | "unrecognised token %qs as first token of struct expr field - " | |
12079 | "expected identifier or integer literal", | |
12080 | t->get_token_description ())); | |
12081 | ||
12082 | return nullptr; | |
12083 | } | |
12084 | } | |
12085 | ||
12086 | // Parses a macro invocation or macro invocation semi. | |
12087 | template <typename ManagedTokenSource> | |
12088 | ExprOrStmt | |
12089 | Parser<ManagedTokenSource>::parse_macro_invocation_maybe_semi ( | |
12090 | AST::AttrVec outer_attrs) | |
12091 | { | |
12092 | Location macro_locus = lexer.peek_token ()->get_locus (); | |
12093 | AST::SimplePath macro_path = parse_simple_path (); | |
12094 | if (macro_path.is_empty ()) | |
12095 | { | |
12096 | Error error (lexer.peek_token ()->get_locus (), | |
12097 | "failed to parse simple path in macro invocation or semi"); | |
12098 | add_error (std::move (error)); | |
12099 | ||
12100 | return ExprOrStmt::create_error (); | |
12101 | } | |
12102 | ||
12103 | if (!skip_token (EXCLAM)) | |
12104 | { | |
12105 | return ExprOrStmt::create_error (); | |
12106 | } | |
12107 | ||
12108 | const_TokenPtr t3 = lexer.peek_token (); | |
12109 | Location tok_tree_loc = t3->get_locus (); | |
12110 | ||
12111 | AST::DelimType type = AST::PARENS; | |
12112 | switch (t3->get_id ()) | |
12113 | { | |
12114 | case LEFT_PAREN: | |
12115 | type = AST::PARENS; | |
12116 | break; | |
12117 | case LEFT_SQUARE: | |
12118 | type = AST::SQUARE; | |
12119 | break; | |
12120 | case LEFT_CURLY: | |
12121 | type = AST::CURLY; | |
12122 | break; | |
12123 | default: | |
12124 | add_error ( | |
12125 | Error (t3->get_locus (), | |
12126 | "unrecognised token %qs in macro invocation - (opening) " | |
12127 | "delimiter expected", | |
12128 | t3->get_token_description ())); | |
12129 | ||
12130 | return ExprOrStmt::create_error (); | |
12131 | } | |
12132 | lexer.skip_token (); | |
12133 | ||
12134 | // parse actual token trees | |
12135 | std::vector<std::unique_ptr<AST::TokenTree>> token_trees; | |
12136 | auto delim_open | |
12137 | = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3))); | |
12138 | token_trees.push_back (std::move (delim_open)); | |
12139 | ||
12140 | t3 = lexer.peek_token (); | |
12141 | // parse token trees until the initial delimiter token is found again | |
12142 | while (!token_id_matches_delims (t3->get_id (), type)) | |
12143 | { | |
12144 | std::unique_ptr<AST::TokenTree> tree = parse_token_tree (); | |
12145 | ||
12146 | if (tree == nullptr) | |
12147 | { | |
12148 | Error error (t3->get_locus (), | |
12149 | "failed to parse token tree for macro invocation (or " | |
12150 | "semi) - found %qs", | |
12151 | t3->get_token_description ()); | |
12152 | add_error (std::move (error)); | |
12153 | ||
12154 | return ExprOrStmt::create_error (); | |
12155 | } | |
12156 | ||
12157 | token_trees.push_back (std::move (tree)); | |
12158 | ||
12159 | t3 = lexer.peek_token (); | |
12160 | } | |
12161 | auto delim_close | |
12162 | = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3))); | |
12163 | token_trees.push_back (std::move (delim_close)); | |
12164 | ||
12165 | // parse end delimiters | |
12166 | t3 = lexer.peek_token (); | |
12167 | if (token_id_matches_delims (t3->get_id (), type)) | |
12168 | { | |
12169 | // tokens match opening delimiter, so skip. | |
12170 | lexer.skip_token (); | |
12171 | ||
12172 | /* with curly bracketed macros, assume it is a macro invocation unless | |
12173 | * a semicolon is explicitly put at the end. this is not necessarily | |
12174 | * true (i.e. context-dependence) and so may have to be fixed up via | |
12175 | * HACKs in semantic analysis (by checking whether it is the last elem | |
12176 | * in the vector). */ | |
12177 | ||
12178 | AST::DelimTokenTree delim_tok_tree (type, std::move (token_trees), | |
12179 | tok_tree_loc); | |
12180 | AST::MacroInvocData invoc_data (std::move (macro_path), | |
12181 | std::move (delim_tok_tree)); | |
12182 | ||
12183 | if (lexer.peek_token ()->get_id () == SEMICOLON) | |
12184 | { | |
12185 | lexer.skip_token (); | |
12186 | ||
12187 | std::unique_ptr<AST::MacroInvocation> stmt ( | |
12188 | new AST::MacroInvocation (std::move (invoc_data), | |
12189 | std::move (outer_attrs), macro_locus, | |
12190 | true)); | |
12191 | return ExprOrStmt (std::move (stmt)); | |
12192 | } | |
12193 | ||
12194 | // otherwise, create macro invocation | |
12195 | std::unique_ptr<AST::MacroInvocation> expr ( | |
12196 | new AST::MacroInvocation (std::move (invoc_data), | |
12197 | std::move (outer_attrs), macro_locus)); | |
12198 | return ExprOrStmt (std::move (expr)); | |
12199 | } | |
12200 | else | |
12201 | { | |
12202 | const_TokenPtr t = lexer.peek_token (); | |
12203 | // tokens don't match opening delimiters, so produce error | |
12204 | Error error ( | |
12205 | t->get_locus (), | |
12206 | "unexpected token %qs - expecting closing delimiter %qs (for a " | |
12207 | "macro invocation)", | |
12208 | t->get_token_description (), | |
12209 | (type == AST::PARENS ? ")" : (type == AST::SQUARE ? "]" : "}"))); | |
12210 | add_error (std::move (error)); | |
12211 | ||
12212 | return ExprOrStmt::create_error (); | |
12213 | } | |
12214 | } | |
12215 | ||
12216 | // "Unexpected token" panic mode - flags gcc error at unexpected token | |
12217 | template <typename ManagedTokenSource> | |
12218 | void | |
12219 | Parser<ManagedTokenSource>::unexpected_token (const_TokenPtr t) | |
12220 | { | |
12221 | Error error (t->get_locus (), "unexpected token %qs\n", | |
12222 | t->get_token_description ()); | |
12223 | add_error (std::move (error)); | |
12224 | } | |
12225 | ||
12226 | /* Crappy "error recovery" performed after error by skipping tokens until a | |
12227 | * semi-colon is found */ | |
12228 | template <typename ManagedTokenSource> | |
12229 | void | |
12230 | Parser<ManagedTokenSource>::skip_after_semicolon () | |
12231 | { | |
12232 | const_TokenPtr t = lexer.peek_token (); | |
12233 | ||
12234 | while (t->get_id () != END_OF_FILE && t->get_id () != SEMICOLON) | |
12235 | { | |
12236 | lexer.skip_token (); | |
12237 | t = lexer.peek_token (); | |
12238 | } | |
12239 | ||
12240 | if (t->get_id () == SEMICOLON) | |
12241 | lexer.skip_token (); | |
12242 | } | |
12243 | ||
12244 | /* Checks if current token has inputted id - skips it and returns true if so, | |
12245 | * diagnoses an error and returns false otherwise. */ | |
12246 | template <typename ManagedTokenSource> | |
12247 | bool | |
12248 | Parser<ManagedTokenSource>::skip_token (TokenId token_id) | |
12249 | { | |
12250 | return expect_token (token_id) != const_TokenPtr (); | |
12251 | } | |
12252 | ||
12253 | /* Checks if current token has inputted id - skips it and returns true if so, | |
12254 | * returns false otherwise without diagnosing an error */ | |
12255 | template <typename ManagedTokenSource> | |
12256 | bool | |
12257 | Parser<ManagedTokenSource>::maybe_skip_token (TokenId token_id) | |
12258 | { | |
12259 | if (lexer.peek_token ()->get_id () != token_id) | |
12260 | return false; | |
12261 | else | |
12262 | return skip_token (token_id); | |
12263 | } | |
12264 | ||
12265 | /* Checks the current token - if id is same as expected, skips and returns it, | |
12266 | * otherwise diagnoses error and returns null. */ | |
12267 | template <typename ManagedTokenSource> | |
12268 | const_TokenPtr | |
12269 | Parser<ManagedTokenSource>::expect_token (TokenId token_id) | |
12270 | { | |
12271 | const_TokenPtr t = lexer.peek_token (); | |
12272 | if (t->get_id () == token_id) | |
12273 | { | |
12274 | lexer.skip_token (); | |
12275 | return t; | |
12276 | } | |
12277 | else | |
12278 | { | |
12279 | Error error (t->get_locus (), "expecting %qs but %qs found", | |
12280 | get_token_description (token_id), | |
12281 | t->get_token_description ()); | |
12282 | add_error (std::move (error)); | |
12283 | ||
12284 | return const_TokenPtr (); | |
12285 | } | |
12286 | } | |
12287 | ||
12288 | // Skips all tokens until EOF or }. Don't use. | |
12289 | template <typename ManagedTokenSource> | |
12290 | void | |
12291 | Parser<ManagedTokenSource>::skip_after_end () | |
12292 | { | |
12293 | const_TokenPtr t = lexer.peek_token (); | |
12294 | ||
12295 | while (t->get_id () != END_OF_FILE && t->get_id () != RIGHT_CURLY) | |
12296 | { | |
12297 | lexer.skip_token (); | |
12298 | t = lexer.peek_token (); | |
12299 | } | |
12300 | ||
12301 | if (t->get_id () == RIGHT_CURLY) | |
12302 | { | |
12303 | lexer.skip_token (); | |
12304 | } | |
12305 | } | |
12306 | ||
12307 | /* A slightly more aware error-handler that skips all tokens until it reaches | |
12308 | * the end of the block scope (i.e. when left curly brackets = right curly | |
12309 | * brackets). Note: assumes currently in the middle of a block. Use | |
12310 | * skip_after_next_block to skip based on the assumption that the block | |
12311 | * has not been entered yet. */ | |
12312 | template <typename ManagedTokenSource> | |
12313 | void | |
12314 | Parser<ManagedTokenSource>::skip_after_end_block () | |
12315 | { | |
12316 | const_TokenPtr t = lexer.peek_token (); | |
12317 | int curly_count = 1; | |
12318 | ||
12319 | while (curly_count > 0 && t->get_id () != END_OF_FILE) | |
12320 | { | |
12321 | switch (t->get_id ()) | |
12322 | { | |
12323 | case LEFT_CURLY: | |
12324 | curly_count++; | |
12325 | break; | |
12326 | case RIGHT_CURLY: | |
12327 | curly_count--; | |
12328 | break; | |
12329 | default: | |
12330 | break; | |
12331 | } | |
12332 | lexer.skip_token (); | |
12333 | t = lexer.peek_token (); | |
12334 | } | |
12335 | } | |
12336 | ||
12337 | /* Skips tokens until the end of the next block. i.e. assumes that the block | |
12338 | * has not been entered yet. */ | |
12339 | template <typename ManagedTokenSource> | |
12340 | void | |
12341 | Parser<ManagedTokenSource>::skip_after_next_block () | |
12342 | { | |
12343 | const_TokenPtr t = lexer.peek_token (); | |
12344 | ||
12345 | // initial loop - skip until EOF if no left curlies encountered | |
12346 | while (t->get_id () != END_OF_FILE && t->get_id () != LEFT_CURLY) | |
12347 | { | |
12348 | lexer.skip_token (); | |
12349 | ||
12350 | t = lexer.peek_token (); | |
12351 | } | |
12352 | ||
12353 | // if next token is left, skip it and then skip after the block ends | |
12354 | if (t->get_id () == LEFT_CURLY) | |
12355 | { | |
12356 | lexer.skip_token (); | |
12357 | ||
12358 | skip_after_end_block (); | |
12359 | } | |
12360 | // otherwise, do nothing as EOF | |
12361 | } | |
12362 | ||
12363 | /* Skips all tokens until ] (the end of an attribute) - does not skip the ] | |
12364 | * (as designed for attribute body use) */ | |
12365 | template <typename ManagedTokenSource> | |
12366 | void | |
12367 | Parser<ManagedTokenSource>::skip_after_end_attribute () | |
12368 | { | |
12369 | const_TokenPtr t = lexer.peek_token (); | |
12370 | ||
12371 | while (t->get_id () != RIGHT_SQUARE) | |
12372 | { | |
12373 | lexer.skip_token (); | |
12374 | t = lexer.peek_token (); | |
12375 | } | |
12376 | ||
12377 | // Don't skip the RIGHT_SQUARE token | |
12378 | } | |
12379 | ||
12380 | /* Pratt parser impl of parse_expr. FIXME: this is only provisional and | |
12381 | * probably will be changed. | |
12382 | * FIXME: this may only parse expressions without blocks as they are the only | |
12383 | * expressions to have precedence? */ | |
12384 | template <typename ManagedTokenSource> | |
12385 | std::unique_ptr<AST::Expr> | |
12386 | Parser<ManagedTokenSource>::parse_expr (int right_binding_power, | |
12387 | AST::AttrVec outer_attrs, | |
12388 | ParseRestrictions restrictions) | |
12389 | { | |
12390 | const_TokenPtr current_token = lexer.peek_token (); | |
12391 | // Special hack because we are allowed to return nullptr, in that case we | |
12392 | // don't want to skip the token, since we don't actually parse it. But if | |
12393 | // null isn't allowed it indicates an error, and we want to skip past that. | |
12394 | // So return early if it is one of the tokens that ends an expression | |
12395 | // (or at least cannot start a new expression). | |
12396 | if (restrictions.expr_can_be_null) | |
12397 | { | |
12398 | TokenId id = current_token->get_id (); | |
12399 | if (id == SEMICOLON || id == RIGHT_PAREN || id == RIGHT_CURLY | |
12400 | || id == RIGHT_SQUARE) | |
12401 | return nullptr; | |
12402 | } | |
12403 | lexer.skip_token (); | |
12404 | ||
12405 | // parse null denotation (unary part of expression) | |
12406 | std::unique_ptr<AST::Expr> expr | |
12407 | = null_denotation (current_token, {}, restrictions); | |
12408 | ||
12409 | if (expr == nullptr) | |
12410 | { | |
12411 | // DEBUG | |
12412 | rust_debug ("null denotation is null; returning null for parse_expr"); | |
12413 | return nullptr; | |
12414 | } | |
12415 | ||
12416 | // stop parsing if find lower priority token - parse higher priority first | |
12417 | while (right_binding_power < left_binding_power (lexer.peek_token ())) | |
12418 | { | |
12419 | current_token = lexer.peek_token (); | |
12420 | lexer.skip_token (); | |
12421 | ||
12422 | expr = left_denotation (current_token, std::move (expr), | |
12423 | std::move (outer_attrs), restrictions); | |
12424 | ||
12425 | if (expr == nullptr) | |
12426 | { | |
12427 | // DEBUG | |
12428 | rust_debug ("left denotation is null; returning null for parse_expr"); | |
12429 | ||
12430 | return nullptr; | |
12431 | } | |
12432 | } | |
12433 | ||
12434 | return expr; | |
12435 | } | |
12436 | ||
12437 | // Parse expression with lowest left binding power. | |
12438 | template <typename ManagedTokenSource> | |
12439 | std::unique_ptr<AST::Expr> | |
12440 | Parser<ManagedTokenSource>::parse_expr (AST::AttrVec outer_attrs, | |
12441 | ParseRestrictions restrictions) | |
12442 | { | |
12443 | return parse_expr (LBP_LOWEST, std::move (outer_attrs), restrictions); | |
12444 | } | |
12445 | ||
12446 | /* Determines action to take when finding token at beginning of expression. | |
12447 | * FIXME: this may only apply to precedence-capable expressions (which are all | |
12448 | * expressions without blocks), so make return type ExprWithoutBlock? It would | |
12449 | * simplify stuff. */ | |
12450 | template <typename ManagedTokenSource> | |
12451 | std::unique_ptr<AST::Expr> | |
12452 | Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok, | |
12453 | AST::AttrVec outer_attrs, | |
12454 | ParseRestrictions restrictions) | |
12455 | { | |
12456 | /* note: tok is previous character in input stream, not current one, as | |
12457 | * parse_expr skips it before passing it in */ | |
12458 | ||
12459 | /* as a Pratt parser (which works by decomposing expressions into a null | |
12460 | * denotation and then a left denotation), null denotations handle primaries | |
12461 | * and unary operands (but only prefix unary operands) */ | |
12462 | ||
12463 | switch (tok->get_id ()) | |
12464 | { | |
12465 | case IDENTIFIER: { | |
12466 | // DEBUG | |
12467 | rust_debug ("beginning null denotation identifier handling"); | |
12468 | ||
12469 | /* best option: parse as path, then extract identifier, macro, | |
12470 | * struct/enum, or just path info from it */ | |
12471 | AST::PathInExpression path = parse_path_in_expression_pratt (tok); | |
12472 | ||
12473 | // DEBUG: | |
12474 | rust_debug ("finished null denotation identifier path parsing - " | |
12475 | "next is branching"); | |
12476 | ||
12477 | // branch on next token | |
12478 | const_TokenPtr t = lexer.peek_token (); | |
12479 | switch (t->get_id ()) | |
12480 | { | |
12481 | case EXCLAM: | |
12482 | // macro | |
12483 | return parse_macro_invocation_partial (std::move (path), | |
12484 | std::move (outer_attrs), | |
12485 | restrictions); | |
12486 | case LEFT_CURLY: { | |
12487 | bool not_a_block | |
12488 | = lexer.peek_token (1)->get_id () == IDENTIFIER | |
12489 | && (lexer.peek_token (2)->get_id () == COMMA | |
12490 | || (lexer.peek_token (2)->get_id () == COLON | |
12491 | && (lexer.peek_token (4)->get_id () == COMMA | |
12492 | || !can_tok_start_type ( | |
12493 | lexer.peek_token (3)->get_id ())))); | |
12494 | ||
12495 | /* definitely not a block: | |
12496 | * path '{' ident ',' | |
12497 | * path '{' ident ':' [anything] ',' | |
12498 | * path '{' ident ':' [not a type] | |
12499 | * otherwise, assume block expr and thus path */ | |
12500 | // DEBUG | |
12501 | rust_debug ("values of lookahead: '%s' '%s' '%s' '%s' ", | |
12502 | lexer.peek_token (1)->get_token_description (), | |
12503 | lexer.peek_token (2)->get_token_description (), | |
12504 | lexer.peek_token (3)->get_token_description (), | |
12505 | lexer.peek_token (4)->get_token_description ()); | |
12506 | ||
12507 | rust_debug ("can be struct expr: '%s', not a block: '%s'", | |
12508 | restrictions.can_be_struct_expr ? "true" : "false", | |
12509 | not_a_block ? "true" : "false"); | |
12510 | ||
12511 | // struct/enum expr struct | |
12512 | if (!restrictions.can_be_struct_expr && !not_a_block) | |
12513 | { | |
12514 | // HACK: add outer attrs to path | |
12515 | path.set_outer_attrs (std::move (outer_attrs)); | |
12516 | return std::unique_ptr<AST::PathInExpression> ( | |
12517 | new AST::PathInExpression (std::move (path))); | |
12518 | } | |
12519 | return parse_struct_expr_struct_partial (std::move (path), | |
12520 | std::move (outer_attrs)); | |
12521 | } | |
12522 | case LEFT_PAREN: | |
12523 | // struct/enum expr tuple | |
12524 | if (!restrictions.can_be_struct_expr) | |
12525 | { | |
12526 | // HACK: add outer attrs to path | |
12527 | path.set_outer_attrs (std::move (outer_attrs)); | |
12528 | return std::unique_ptr<AST::PathInExpression> ( | |
12529 | new AST::PathInExpression (std::move (path))); | |
12530 | } | |
12531 | return parse_struct_expr_tuple_partial (std::move (path), | |
12532 | std::move (outer_attrs)); | |
12533 | default: | |
12534 | // assume path is returned if not single segment | |
12535 | if (path.is_single_segment ()) | |
12536 | { | |
12537 | // have to return an identifier expression or something, idk | |
12538 | /* HACK: may have to become permanent, but this is my current | |
12539 | * identifier expression */ | |
12540 | return std::unique_ptr<AST::IdentifierExpr> ( | |
12541 | new AST::IdentifierExpr (tok->get_str (), {}, | |
12542 | tok->get_locus ())); | |
12543 | } | |
12544 | // HACK: add outer attrs to path | |
12545 | path.set_outer_attrs (std::move (outer_attrs)); | |
12546 | return std::unique_ptr<AST::PathInExpression> ( | |
12547 | new AST::PathInExpression (std::move (path))); | |
12548 | } | |
12549 | gcc_unreachable (); | |
12550 | } | |
12551 | /* FIXME: delegate to parse_literal_expr instead? would have to rejig | |
12552 | * tokens and whatever. */ | |
12553 | /* FIXME: could also be path expression (and hence macro expression, | |
12554 | * struct/enum expr) */ | |
12555 | case LEFT_ANGLE: { | |
12556 | // qualified path | |
12557 | // HACK: add outer attrs to path | |
12558 | AST::QualifiedPathInExpression path | |
12559 | = parse_qualified_path_in_expression (tok->get_locus ()); | |
12560 | path.set_outer_attrs (std::move (outer_attrs)); | |
12561 | return std::unique_ptr<AST::QualifiedPathInExpression> ( | |
12562 | new AST::QualifiedPathInExpression (std::move (path))); | |
12563 | } | |
12564 | // FIXME: for literal exprs, should outer attrs be passed in or just | |
12565 | // ignored? | |
12566 | case INT_LITERAL: | |
12567 | // we should check the range, but ignore for now | |
12568 | // encode as int? | |
12569 | return std::unique_ptr<AST::LiteralExpr> ( | |
12570 | new AST::LiteralExpr (tok->get_str (), AST::Literal::INT, | |
12571 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12572 | case FLOAT_LITERAL: | |
12573 | // encode as float? | |
12574 | return std::unique_ptr<AST::LiteralExpr> ( | |
12575 | new AST::LiteralExpr (tok->get_str (), AST::Literal::FLOAT, | |
12576 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12577 | case STRING_LITERAL: | |
12578 | return std::unique_ptr<AST::LiteralExpr> ( | |
12579 | new AST::LiteralExpr (tok->get_str (), AST::Literal::STRING, | |
12580 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12581 | case BYTE_STRING_LITERAL: | |
12582 | return std::unique_ptr<AST::LiteralExpr> ( | |
12583 | new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE_STRING, | |
12584 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12585 | case CHAR_LITERAL: | |
12586 | return std::unique_ptr<AST::LiteralExpr> ( | |
12587 | new AST::LiteralExpr (tok->get_str (), AST::Literal::CHAR, | |
12588 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12589 | case BYTE_CHAR_LITERAL: | |
12590 | return std::unique_ptr<AST::LiteralExpr> ( | |
12591 | new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE, | |
12592 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12593 | case TRUE_LITERAL: | |
12594 | return std::unique_ptr<AST::LiteralExpr> ( | |
12595 | new AST::LiteralExpr ("true", AST::Literal::BOOL, tok->get_type_hint (), | |
12596 | {}, tok->get_locus ())); | |
12597 | case FALSE_LITERAL: | |
12598 | return std::unique_ptr<AST::LiteralExpr> ( | |
12599 | new AST::LiteralExpr ("false", AST::Literal::BOOL, | |
12600 | tok->get_type_hint (), {}, tok->get_locus ())); | |
12601 | case LEFT_PAREN: | |
12602 | return parse_grouped_or_tuple_expr (std::move (outer_attrs), | |
12603 | tok->get_locus ()); | |
12604 | ||
12605 | /*case PLUS: { // unary plus operator | |
12606 | // invoke parse_expr recursively with appropriate priority, etc. for | |
12607 | below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS); | |
12608 | ||
12609 | if (expr == nullptr) | |
12610 | return nullptr; | |
12611 | // can only apply to integer and float expressions | |
12612 | if (expr->get_type() != integer_type_node || expr->get_type() != | |
12613 | float_type_node) { rust_error_at(tok->get_locus(), "operand of unary | |
12614 | plus must be int or float but it is %s", print_type(expr->get_type())); | |
12615 | return nullptr; | |
12616 | } | |
12617 | ||
12618 | return Tree(expr, tok->get_locus()); | |
12619 | }*/ | |
12620 | // Rust has no unary plus operator | |
12621 | case MINUS: { // unary minus | |
12622 | ParseRestrictions entered_from_unary; | |
12623 | entered_from_unary.entered_from_unary = true; | |
12624 | if (!restrictions.can_be_struct_expr) | |
12625 | entered_from_unary.can_be_struct_expr = false; | |
12626 | std::unique_ptr<AST::Expr> expr | |
12627 | = parse_expr (LBP_UNARY_MINUS, {}, entered_from_unary); | |
12628 | ||
12629 | if (expr == nullptr) | |
12630 | return nullptr; | |
12631 | // can only apply to integer and float expressions | |
12632 | /*if (expr.get_type() != integer_type_node || expr.get_type() != | |
12633 | float_type_node) { rust_error_at(tok->get_locus(), "operand of unary | |
12634 | minus must be int or float but it is %s", | |
12635 | print_type(expr.get_type())); return Tree::error(); | |
12636 | }*/ | |
12637 | /* FIXME: when implemented the "get type" method on expr, ensure it is | |
12638 | * int or float type (except unsigned int). Actually, this would | |
12639 | * probably have to be done in semantic analysis (as type checking). | |
12640 | */ | |
12641 | ||
12642 | /* FIXME: allow outer attributes on these expressions by having an | |
12643 | * outer attrs parameter in function*/ | |
12644 | return std::unique_ptr<AST::NegationExpr> ( | |
12645 | new AST::NegationExpr (std::move (expr), NegationOperator::NEGATE, | |
12646 | std::move (outer_attrs), tok->get_locus ())); | |
12647 | } | |
12648 | case EXCLAM: { // logical or bitwise not | |
12649 | ParseRestrictions entered_from_unary; | |
12650 | entered_from_unary.entered_from_unary = true; | |
12651 | if (!restrictions.can_be_struct_expr) | |
12652 | entered_from_unary.can_be_struct_expr = false; | |
12653 | std::unique_ptr<AST::Expr> expr | |
12654 | = parse_expr (LBP_UNARY_EXCLAM, {}, entered_from_unary); | |
12655 | ||
12656 | if (expr == nullptr) | |
12657 | return nullptr; | |
12658 | // can only apply to boolean expressions | |
12659 | /*if (expr.get_type() != boolean_type_node) { | |
12660 | rust_error_at(tok->get_locus(), | |
12661 | "operand of logical not must be a boolean but it is %s", | |
12662 | print_type(expr.get_type())); | |
12663 | return Tree::error(); | |
12664 | }*/ | |
12665 | /* FIXME: type checking for boolean or integer expressions in semantic | |
12666 | * analysis */ | |
12667 | ||
12668 | // FIXME: allow outer attributes on these expressions | |
12669 | return std::unique_ptr<AST::NegationExpr> ( | |
12670 | new AST::NegationExpr (std::move (expr), NegationOperator::NOT, | |
12671 | std::move (outer_attrs), tok->get_locus ())); | |
12672 | } | |
12673 | case ASTERISK: { | |
12674 | /* pointer dereference only - HACK: as struct expressions should | |
12675 | * always be value expressions, cannot be dereferenced */ | |
12676 | ParseRestrictions entered_from_unary; | |
12677 | entered_from_unary.entered_from_unary = true; | |
12678 | entered_from_unary.can_be_struct_expr = false; | |
12679 | std::unique_ptr<AST::Expr> expr | |
12680 | = parse_expr (LBP_UNARY_ASTERISK, {}, entered_from_unary); | |
12681 | // FIXME: allow outer attributes on expression | |
12682 | return std::unique_ptr<AST::DereferenceExpr> ( | |
12683 | new AST::DereferenceExpr (std::move (expr), std::move (outer_attrs), | |
12684 | tok->get_locus ())); | |
12685 | } | |
12686 | case AMP: { | |
12687 | // (single) "borrow" expression - shared (mutable) or immutable | |
12688 | std::unique_ptr<AST::Expr> expr = nullptr; | |
12689 | bool is_mut_borrow = false; | |
12690 | ||
12691 | /* HACK: as struct expressions should always be value expressions, | |
12692 | * cannot be referenced */ | |
12693 | ParseRestrictions entered_from_unary; | |
12694 | entered_from_unary.entered_from_unary = true; | |
12695 | entered_from_unary.can_be_struct_expr = false; | |
12696 | ||
12697 | if (lexer.peek_token ()->get_id () == MUT) | |
12698 | { | |
12699 | lexer.skip_token (); | |
12700 | expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary); | |
12701 | is_mut_borrow = true; | |
12702 | } | |
12703 | else | |
12704 | { | |
12705 | expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary); | |
12706 | } | |
12707 | ||
12708 | // FIXME: allow outer attributes on expression | |
12709 | return std::unique_ptr<AST::BorrowExpr> ( | |
12710 | new AST::BorrowExpr (std::move (expr), is_mut_borrow, false, | |
12711 | std::move (outer_attrs), tok->get_locus ())); | |
12712 | } | |
12713 | case LOGICAL_AND: { | |
12714 | // (double) "borrow" expression - shared (mutable) or immutable | |
12715 | std::unique_ptr<AST::Expr> expr = nullptr; | |
12716 | bool is_mut_borrow = false; | |
12717 | ||
12718 | ParseRestrictions entered_from_unary; | |
12719 | entered_from_unary.entered_from_unary = true; | |
12720 | ||
12721 | if (lexer.peek_token ()->get_id () == MUT) | |
12722 | { | |
12723 | lexer.skip_token (); | |
12724 | expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary); | |
12725 | is_mut_borrow = true; | |
12726 | } | |
12727 | else | |
12728 | { | |
12729 | expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary); | |
12730 | } | |
12731 | ||
12732 | // FIXME: allow outer attributes on expression | |
12733 | return std::unique_ptr<AST::BorrowExpr> ( | |
12734 | new AST::BorrowExpr (std::move (expr), is_mut_borrow, true, | |
12735 | std::move (outer_attrs), tok->get_locus ())); | |
12736 | } | |
12737 | case SCOPE_RESOLUTION: { | |
12738 | // TODO: fix: this is for global paths, i.e. std::string::whatever | |
12739 | Error error (tok->get_locus (), | |
12740 | "found null denotation scope resolution operator, and " | |
12741 | "have not written handling for it"); | |
12742 | add_error (std::move (error)); | |
12743 | ||
12744 | return nullptr; | |
12745 | } | |
12746 | case SELF: | |
12747 | case SELF_ALIAS: | |
12748 | case DOLLAR_SIGN: | |
12749 | case CRATE: | |
12750 | case SUPER: { | |
12751 | // DEBUG | |
12752 | rust_debug ("beginning null denotation " | |
12753 | "self/self-alias/dollar/crate/super handling"); | |
12754 | ||
12755 | /* best option: parse as path, then extract identifier, macro, | |
12756 | * struct/enum, or just path info from it */ | |
12757 | AST::PathInExpression path = parse_path_in_expression_pratt (tok); | |
12758 | ||
12759 | // DEBUG | |
12760 | rust_debug ( | |
12761 | "just finished parsing path (going to disambiguate) - peeked " | |
12762 | "token is '%s'", | |
12763 | lexer.peek_token ()->get_token_description ()); | |
12764 | ||
12765 | // HACK: always make "self" by itself a path (regardless of next | |
12766 | // tokens) | |
12767 | if (tok->get_id () == SELF && path.is_single_segment ()) | |
12768 | { | |
12769 | // HACK: add outer attrs to path | |
12770 | path.set_outer_attrs (std::move (outer_attrs)); | |
12771 | return std::unique_ptr<AST::PathInExpression> ( | |
12772 | new AST::PathInExpression (std::move (path))); | |
12773 | } | |
12774 | ||
12775 | // branch on next token | |
12776 | const_TokenPtr t = lexer.peek_token (); | |
12777 | switch (t->get_id ()) | |
12778 | { | |
12779 | case EXCLAM: | |
12780 | // macro | |
12781 | return parse_macro_invocation_partial (std::move (path), | |
12782 | std::move (outer_attrs)); | |
12783 | case LEFT_CURLY: { | |
12784 | // struct/enum expr struct | |
12785 | rust_debug ("can_be_struct_expr: %s", | |
12786 | restrictions.can_be_struct_expr ? "true" : "false"); | |
12787 | ||
12788 | bool not_a_block | |
12789 | = lexer.peek_token (1)->get_id () == IDENTIFIER | |
12790 | && (lexer.peek_token (2)->get_id () == COMMA | |
12791 | || (lexer.peek_token (2)->get_id () == COLON | |
12792 | && (lexer.peek_token (4)->get_id () == COMMA | |
12793 | || !can_tok_start_type ( | |
12794 | lexer.peek_token (3)->get_id ())))); | |
12795 | ||
12796 | if (!restrictions.can_be_struct_expr && !not_a_block) | |
12797 | { | |
12798 | // assume path is returned | |
12799 | // HACK: add outer attributes to path | |
12800 | path.set_outer_attrs (std::move (outer_attrs)); | |
12801 | return std::unique_ptr<AST::PathInExpression> ( | |
12802 | new AST::PathInExpression (std::move (path))); | |
12803 | } | |
12804 | return parse_struct_expr_struct_partial (std::move (path), | |
12805 | std::move (outer_attrs)); | |
12806 | } | |
12807 | case LEFT_PAREN: | |
12808 | // struct/enum expr tuple | |
12809 | if (!restrictions.can_be_struct_expr) | |
12810 | { | |
12811 | // assume path is returned | |
12812 | // HACK: add outer attributes to path | |
12813 | path.set_outer_attrs (std::move (outer_attrs)); | |
12814 | return std::unique_ptr<AST::PathInExpression> ( | |
12815 | new AST::PathInExpression (std::move (path))); | |
12816 | } | |
12817 | return parse_struct_expr_tuple_partial (std::move (path), | |
12818 | std::move (outer_attrs)); | |
12819 | default: | |
12820 | // assume path is returned | |
12821 | // HACK: add outer attributes to path | |
12822 | path.set_outer_attrs (std::move (outer_attrs)); | |
12823 | return std::unique_ptr<AST::PathInExpression> ( | |
12824 | new AST::PathInExpression (std::move (path))); | |
12825 | } | |
12826 | gcc_unreachable (); | |
12827 | } | |
12828 | case OR: | |
12829 | case PIPE: | |
12830 | case MOVE: | |
12831 | // closure expression | |
12832 | return parse_closure_expr_pratt (tok, std::move (outer_attrs)); | |
12833 | case DOT_DOT: | |
12834 | // either "range to" or "range full" expressions | |
12835 | return parse_nud_range_exclusive_expr (tok, std::move (outer_attrs)); | |
12836 | case DOT_DOT_EQ: | |
12837 | // range to inclusive expr | |
12838 | return parse_range_to_inclusive_expr (tok, std::move (outer_attrs)); | |
12839 | case RETURN_TOK: | |
12840 | // FIXME: is this really a null denotation expression? | |
12841 | return parse_return_expr (std::move (outer_attrs), tok->get_locus ()); | |
12842 | case BREAK: | |
12843 | // FIXME: is this really a null denotation expression? | |
12844 | return parse_break_expr (std::move (outer_attrs), tok->get_locus ()); | |
12845 | case CONTINUE: | |
12846 | return parse_continue_expr (std::move (outer_attrs), tok->get_locus ()); | |
12847 | case LEFT_CURLY: | |
12848 | // ok - this is an expression with block for once. | |
12849 | return parse_block_expr (std::move (outer_attrs), tok->get_locus ()); | |
12850 | case IF: | |
12851 | // if or if let, so more lookahead to find out | |
12852 | if (lexer.peek_token (1)->get_id () == LET) | |
12853 | { | |
12854 | // if let expr | |
12855 | return parse_if_let_expr (std::move (outer_attrs), tok->get_locus ()); | |
12856 | } | |
12857 | else | |
12858 | { | |
12859 | // if expr | |
12860 | return parse_if_expr (std::move (outer_attrs), tok->get_locus ()); | |
12861 | } | |
12862 | case LOOP: | |
12863 | return parse_loop_expr (std::move (outer_attrs), AST::LoopLabel::error (), | |
12864 | tok->get_locus ()); | |
12865 | case WHILE: | |
12866 | return parse_while_loop_expr (std::move (outer_attrs), | |
12867 | AST::LoopLabel::error (), | |
12868 | tok->get_locus ()); | |
12869 | case MATCH_TOK: | |
12870 | // also an expression with block | |
12871 | return parse_match_expr (std::move (outer_attrs), tok->get_locus ()); | |
12872 | case LEFT_SQUARE: | |
12873 | // array definition expr (not indexing) | |
12874 | return parse_array_expr (std::move (outer_attrs), tok->get_locus ()); | |
12875 | case UNSAFE: | |
12876 | return parse_unsafe_block_expr (std::move (outer_attrs), | |
12877 | tok->get_locus ()); | |
12878 | default: | |
12879 | if (!restrictions.expr_can_be_null) | |
12880 | add_error (Error (tok->get_locus (), | |
12881 | "found unexpected token %qs in null denotation", | |
12882 | tok->get_token_description ())); | |
12883 | return nullptr; | |
12884 | } | |
12885 | } | |
12886 | ||
12887 | /* Called for each token that can appear in infix (between) position. Can be | |
12888 | * operators or other punctuation. Returns a function pointer to member | |
12889 | * function that implements the left denotation for the token given. */ | |
12890 | template <typename ManagedTokenSource> | |
12891 | std::unique_ptr<AST::Expr> | |
12892 | Parser<ManagedTokenSource>::left_denotation (const_TokenPtr tok, | |
12893 | std::unique_ptr<AST::Expr> left, | |
12894 | AST::AttrVec outer_attrs, | |
12895 | ParseRestrictions restrictions) | |
12896 | { | |
12897 | // Token passed in has already been skipped, so peek gives "next" token | |
12898 | switch (tok->get_id ()) | |
12899 | { | |
12900 | // FIXME: allow for outer attributes to be applied | |
12901 | case QUESTION_MARK: { | |
12902 | Location left_locus = left->get_locus (); | |
12903 | // error propagation expression - unary postfix | |
12904 | return std::unique_ptr<AST::ErrorPropagationExpr> ( | |
12905 | new AST::ErrorPropagationExpr (std::move (left), | |
12906 | std::move (outer_attrs), left_locus)); | |
12907 | } | |
12908 | case PLUS: | |
12909 | // sum expression - binary infix | |
12910 | /*return parse_binary_plus_expr (tok, std::move (left), | |
12911 | std::move (outer_attrs), restrictions);*/ | |
12912 | return parse_arithmetic_or_logical_expr (tok, std::move (left), | |
12913 | std::move (outer_attrs), | |
12914 | ArithmeticOrLogicalOperator::ADD, | |
12915 | restrictions); | |
12916 | case MINUS: | |
12917 | // difference expression - binary infix | |
12918 | /*return parse_binary_minus_expr (tok, std::move (left), | |
12919 | std::move (outer_attrs), | |
12920 | restrictions);*/ | |
12921 | return parse_arithmetic_or_logical_expr ( | |
12922 | tok, std::move (left), std::move (outer_attrs), | |
12923 | ArithmeticOrLogicalOperator::SUBTRACT, restrictions); | |
12924 | case ASTERISK: | |
12925 | // product expression - binary infix | |
12926 | /*return parse_binary_mult_expr (tok, std::move (left), | |
12927 | std::move (outer_attrs), restrictions);*/ | |
12928 | return parse_arithmetic_or_logical_expr ( | |
12929 | tok, std::move (left), std::move (outer_attrs), | |
12930 | ArithmeticOrLogicalOperator::MULTIPLY, restrictions); | |
12931 | case DIV: | |
12932 | // quotient expression - binary infix | |
12933 | /*return parse_binary_div_expr (tok, std::move (left), | |
12934 | std::move (outer_attrs), restrictions);*/ | |
12935 | return parse_arithmetic_or_logical_expr ( | |
12936 | tok, std::move (left), std::move (outer_attrs), | |
12937 | ArithmeticOrLogicalOperator::DIVIDE, restrictions); | |
12938 | case PERCENT: | |
12939 | // modulo expression - binary infix | |
12940 | /*return parse_binary_mod_expr (tok, std::move (left), | |
12941 | std::move (outer_attrs), restrictions);*/ | |
12942 | return parse_arithmetic_or_logical_expr ( | |
12943 | tok, std::move (left), std::move (outer_attrs), | |
12944 | ArithmeticOrLogicalOperator::MODULUS, restrictions); | |
12945 | case AMP: | |
12946 | // logical or bitwise and expression - binary infix | |
12947 | /*return parse_bitwise_and_expr (tok, std::move (left), | |
12948 | std::move (outer_attrs), restrictions);*/ | |
12949 | return parse_arithmetic_or_logical_expr ( | |
12950 | tok, std::move (left), std::move (outer_attrs), | |
12951 | ArithmeticOrLogicalOperator::BITWISE_AND, restrictions); | |
12952 | case PIPE: | |
12953 | // logical or bitwise or expression - binary infix | |
12954 | /*return parse_bitwise_or_expr (tok, std::move (left), | |
12955 | std::move (outer_attrs), restrictions);*/ | |
12956 | return parse_arithmetic_or_logical_expr ( | |
12957 | tok, std::move (left), std::move (outer_attrs), | |
12958 | ArithmeticOrLogicalOperator::BITWISE_OR, restrictions); | |
12959 | case CARET: | |
12960 | // logical or bitwise xor expression - binary infix | |
12961 | /*return parse_bitwise_xor_expr (tok, std::move (left), | |
12962 | std::move (outer_attrs), restrictions);*/ | |
12963 | return parse_arithmetic_or_logical_expr ( | |
12964 | tok, std::move (left), std::move (outer_attrs), | |
12965 | ArithmeticOrLogicalOperator::BITWISE_XOR, restrictions); | |
12966 | case LEFT_SHIFT: | |
12967 | // left shift expression - binary infix | |
12968 | /*return parse_left_shift_expr (tok, std::move (left), | |
12969 | std::move (outer_attrs), restrictions);*/ | |
12970 | return parse_arithmetic_or_logical_expr ( | |
12971 | tok, std::move (left), std::move (outer_attrs), | |
12972 | ArithmeticOrLogicalOperator::LEFT_SHIFT, restrictions); | |
12973 | case RIGHT_SHIFT: | |
12974 | // right shift expression - binary infix | |
12975 | /*return parse_right_shift_expr (tok, std::move (left), | |
12976 | std::move (outer_attrs), restrictions);*/ | |
12977 | return parse_arithmetic_or_logical_expr ( | |
12978 | tok, std::move (left), std::move (outer_attrs), | |
12979 | ArithmeticOrLogicalOperator::RIGHT_SHIFT, restrictions); | |
12980 | case EQUAL_EQUAL: | |
12981 | // equal to expression - binary infix (no associativity) | |
12982 | /*return parse_binary_equal_expr (tok, std::move (left), | |
12983 | std::move (outer_attrs), | |
12984 | restrictions);*/ | |
12985 | return parse_comparison_expr (tok, std::move (left), | |
12986 | std::move (outer_attrs), | |
12987 | ComparisonOperator::EQUAL, restrictions); | |
12988 | case NOT_EQUAL: | |
12989 | // not equal to expression - binary infix (no associativity) | |
12990 | /*return parse_binary_not_equal_expr (tok, std::move (left), | |
12991 | std::move (outer_attrs), | |
12992 | restrictions);*/ | |
12993 | return parse_comparison_expr (tok, std::move (left), | |
12994 | std::move (outer_attrs), | |
12995 | ComparisonOperator::NOT_EQUAL, | |
12996 | restrictions); | |
12997 | case RIGHT_ANGLE: | |
12998 | // greater than expression - binary infix (no associativity) | |
12999 | /*return parse_binary_greater_than_expr (tok, std::move (left), | |
13000 | std::move (outer_attrs), | |
13001 | restrictions);*/ | |
13002 | return parse_comparison_expr (tok, std::move (left), | |
13003 | std::move (outer_attrs), | |
13004 | ComparisonOperator::GREATER_THAN, | |
13005 | restrictions); | |
13006 | case LEFT_ANGLE: | |
13007 | // less than expression - binary infix (no associativity) | |
13008 | /*return parse_binary_less_than_expr (tok, std::move (left), | |
13009 | std::move (outer_attrs), | |
13010 | restrictions);*/ | |
13011 | return parse_comparison_expr (tok, std::move (left), | |
13012 | std::move (outer_attrs), | |
13013 | ComparisonOperator::LESS_THAN, | |
13014 | restrictions); | |
13015 | case GREATER_OR_EQUAL: | |
13016 | // greater than or equal to expression - binary infix (no associativity) | |
13017 | /*return parse_binary_greater_equal_expr (tok, std::move (left), | |
13018 | std::move (outer_attrs), | |
13019 | restrictions);*/ | |
13020 | return parse_comparison_expr (tok, std::move (left), | |
13021 | std::move (outer_attrs), | |
13022 | ComparisonOperator::GREATER_OR_EQUAL, | |
13023 | restrictions); | |
13024 | case LESS_OR_EQUAL: | |
13025 | // less than or equal to expression - binary infix (no associativity) | |
13026 | /*return parse_binary_less_equal_expr (tok, std::move (left), | |
13027 | std::move (outer_attrs), | |
13028 | restrictions);*/ | |
13029 | return parse_comparison_expr (tok, std::move (left), | |
13030 | std::move (outer_attrs), | |
13031 | ComparisonOperator::LESS_OR_EQUAL, | |
13032 | restrictions); | |
13033 | case OR: | |
13034 | // lazy logical or expression - binary infix | |
13035 | return parse_lazy_or_expr (tok, std::move (left), std::move (outer_attrs), | |
13036 | restrictions); | |
13037 | case LOGICAL_AND: | |
13038 | // lazy logical and expression - binary infix | |
13039 | return parse_lazy_and_expr (tok, std::move (left), | |
13040 | std::move (outer_attrs), restrictions); | |
13041 | case AS: | |
13042 | /* type cast expression - kind of binary infix (RHS is actually a | |
13043 | * TypeNoBounds) */ | |
13044 | return parse_type_cast_expr (tok, std::move (left), | |
13045 | std::move (outer_attrs), restrictions); | |
13046 | case EQUAL: | |
13047 | // assignment expression - binary infix (note right-to-left | |
13048 | // associativity) | |
13049 | return parse_assig_expr (tok, std::move (left), std::move (outer_attrs), | |
13050 | restrictions); | |
13051 | case PLUS_EQ: | |
13052 | /* plus-assignment expression - binary infix (note right-to-left | |
13053 | * associativity) */ | |
13054 | /*return parse_plus_assig_expr (tok, std::move (left), | |
13055 | std::move (outer_attrs), restrictions);*/ | |
13056 | return parse_compound_assignment_expr (tok, std::move (left), | |
13057 | std::move (outer_attrs), | |
13058 | CompoundAssignmentOperator::ADD, | |
13059 | restrictions); | |
13060 | case MINUS_EQ: | |
13061 | /* minus-assignment expression - binary infix (note right-to-left | |
13062 | * associativity) */ | |
13063 | /*return parse_minus_assig_expr (tok, std::move (left), | |
13064 | std::move (outer_attrs), restrictions);*/ | |
13065 | return parse_compound_assignment_expr ( | |
13066 | tok, std::move (left), std::move (outer_attrs), | |
13067 | CompoundAssignmentOperator::SUBTRACT, restrictions); | |
13068 | case ASTERISK_EQ: | |
13069 | /* multiply-assignment expression - binary infix (note right-to-left | |
13070 | * associativity) */ | |
13071 | /*return parse_mult_assig_expr (tok, std::move (left), | |
13072 | std::move (outer_attrs), restrictions);*/ | |
13073 | return parse_compound_assignment_expr ( | |
13074 | tok, std::move (left), std::move (outer_attrs), | |
13075 | CompoundAssignmentOperator::MULTIPLY, restrictions); | |
13076 | case DIV_EQ: | |
13077 | /* division-assignment expression - binary infix (note right-to-left | |
13078 | * associativity) */ | |
13079 | /*return parse_div_assig_expr (tok, std::move (left), | |
13080 | std::move (outer_attrs), restrictions);*/ | |
13081 | return parse_compound_assignment_expr (tok, std::move (left), | |
13082 | std::move (outer_attrs), | |
13083 | CompoundAssignmentOperator::DIVIDE, | |
13084 | restrictions); | |
13085 | case PERCENT_EQ: | |
13086 | /* modulo-assignment expression - binary infix (note right-to-left | |
13087 | * associativity) */ | |
13088 | /*return parse_mod_assig_expr (tok, std::move (left), | |
13089 | std::move (outer_attrs), restrictions);*/ | |
13090 | return parse_compound_assignment_expr ( | |
13091 | tok, std::move (left), std::move (outer_attrs), | |
13092 | CompoundAssignmentOperator::MODULUS, restrictions); | |
13093 | case AMP_EQ: | |
13094 | /* bitwise and-assignment expression - binary infix (note right-to-left | |
13095 | * associativity) */ | |
13096 | /*return parse_and_assig_expr (tok, std::move (left), | |
13097 | std::move (outer_attrs), restrictions);*/ | |
13098 | return parse_compound_assignment_expr ( | |
13099 | tok, std::move (left), std::move (outer_attrs), | |
13100 | CompoundAssignmentOperator::BITWISE_AND, restrictions); | |
13101 | case PIPE_EQ: | |
13102 | /* bitwise or-assignment expression - binary infix (note right-to-left | |
13103 | * associativity) */ | |
13104 | /*return parse_or_assig_expr (tok, std::move (left), | |
13105 | std::move (outer_attrs), restrictions);*/ | |
13106 | return parse_compound_assignment_expr ( | |
13107 | tok, std::move (left), std::move (outer_attrs), | |
13108 | CompoundAssignmentOperator::BITWISE_OR, restrictions); | |
13109 | case CARET_EQ: | |
13110 | /* bitwise xor-assignment expression - binary infix (note right-to-left | |
13111 | * associativity) */ | |
13112 | /*return parse_xor_assig_expr (tok, std::move (left), | |
13113 | std::move (outer_attrs), restrictions);*/ | |
13114 | return parse_compound_assignment_expr ( | |
13115 | tok, std::move (left), std::move (outer_attrs), | |
13116 | CompoundAssignmentOperator::BITWISE_XOR, restrictions); | |
13117 | case LEFT_SHIFT_EQ: | |
13118 | /* left shift-assignment expression - binary infix (note right-to-left | |
13119 | * associativity) */ | |
13120 | /*return parse_left_shift_assig_expr (tok, std::move (left), | |
13121 | std::move (outer_attrs), | |
13122 | restrictions);*/ | |
13123 | return parse_compound_assignment_expr ( | |
13124 | tok, std::move (left), std::move (outer_attrs), | |
13125 | CompoundAssignmentOperator::LEFT_SHIFT, restrictions); | |
13126 | case RIGHT_SHIFT_EQ: | |
13127 | /* right shift-assignment expression - binary infix (note right-to-left | |
13128 | * associativity) */ | |
13129 | /*return parse_right_shift_assig_expr (tok, std::move (left), | |
13130 | std::move (outer_attrs), | |
13131 | restrictions);*/ | |
13132 | return parse_compound_assignment_expr ( | |
13133 | tok, std::move (left), std::move (outer_attrs), | |
13134 | CompoundAssignmentOperator::RIGHT_SHIFT, restrictions); | |
13135 | case DOT_DOT: | |
13136 | /* range exclusive expression - binary infix (no associativity) | |
13137 | * either "range" or "range from" */ | |
13138 | return parse_led_range_exclusive_expr (tok, std::move (left), | |
13139 | std::move (outer_attrs), | |
13140 | restrictions); | |
13141 | case DOT_DOT_EQ: | |
13142 | /* range inclusive expression - binary infix (no associativity) | |
13143 | * unambiguously RangeInclusiveExpr */ | |
13144 | return parse_range_inclusive_expr (tok, std::move (left), | |
13145 | std::move (outer_attrs), restrictions); | |
13146 | case SCOPE_RESOLUTION: | |
13147 | // path expression - binary infix? FIXME should this even be parsed | |
13148 | // here? | |
13149 | add_error ( | |
13150 | Error (tok->get_locus (), | |
13151 | "found scope resolution operator in left denotation " | |
13152 | "function - this should probably be handled elsewhere")); | |
13153 | ||
13154 | return nullptr; | |
13155 | case DOT: { | |
13156 | /* field expression or method call - relies on parentheses after next | |
13157 | * identifier or await if token after is "await" (unary postfix) or | |
13158 | * tuple index if token after is a decimal int literal */ | |
13159 | ||
13160 | const_TokenPtr next_tok = lexer.peek_token (); | |
13161 | if (next_tok->get_id () == IDENTIFIER | |
13162 | && next_tok->get_str () == "await") | |
13163 | { | |
13164 | // await expression | |
13165 | return parse_await_expr (tok, std::move (left), | |
13166 | std::move (outer_attrs)); | |
13167 | } | |
13168 | else if (next_tok->get_id () == INT_LITERAL) | |
13169 | { | |
13170 | // tuple index expression - TODO check for decimal int literal | |
13171 | return parse_tuple_index_expr (tok, std::move (left), | |
13172 | std::move (outer_attrs), | |
13173 | restrictions); | |
13174 | } | |
13175 | else if (next_tok->get_id () == IDENTIFIER | |
13176 | && lexer.peek_token (1)->get_id () != LEFT_PAREN | |
13177 | && lexer.peek_token (1)->get_id () != SCOPE_RESOLUTION) | |
13178 | { | |
13179 | /* field expression (or should be) - FIXME: scope resolution right | |
13180 | * after identifier should always be method, I'm pretty sure */ | |
13181 | return parse_field_access_expr (tok, std::move (left), | |
13182 | std::move (outer_attrs), | |
13183 | restrictions); | |
13184 | } | |
13185 | else | |
13186 | { | |
13187 | // method call (probably) | |
13188 | return parse_method_call_expr (tok, std::move (left), | |
13189 | std::move (outer_attrs), | |
13190 | restrictions); | |
13191 | } | |
13192 | } | |
13193 | case LEFT_PAREN: | |
13194 | // function call - method call is based on dot notation first | |
13195 | return parse_function_call_expr (tok, std::move (left), | |
13196 | std::move (outer_attrs), restrictions); | |
13197 | case LEFT_SQUARE: | |
13198 | // array or slice index expression (pseudo binary infix) | |
13199 | return parse_index_expr (tok, std::move (left), std::move (outer_attrs), | |
13200 | restrictions); | |
13201 | case FLOAT_LITERAL: | |
13202 | /* HACK: get around lexer mis-identifying '.0' or '.1' or whatever as a | |
13203 | * float literal - TODO does this happen anymore? It shouldn't. */ | |
13204 | return parse_tuple_index_expr_float (tok, std::move (left), | |
13205 | std::move (outer_attrs), | |
13206 | restrictions); | |
13207 | default: | |
13208 | add_error (Error (tok->get_locus (), | |
13209 | "found unexpected token %qs in left denotation", | |
13210 | tok->get_token_description ())); | |
13211 | ||
13212 | return nullptr; | |
13213 | } | |
13214 | } | |
13215 | ||
13216 | /* Returns the left binding power for the given ArithmeticOrLogicalExpr type. | |
13217 | * TODO make constexpr? Would that even do anything useful? */ | |
13218 | inline binding_powers | |
13219 | get_lbp_for_arithmetic_or_logical_expr ( | |
13220 | AST::ArithmeticOrLogicalExpr::ExprType expr_type) | |
13221 | { | |
13222 | switch (expr_type) | |
13223 | { | |
13224 | case ArithmeticOrLogicalOperator::ADD: | |
13225 | return LBP_PLUS; | |
13226 | case ArithmeticOrLogicalOperator::SUBTRACT: | |
13227 | return LBP_MINUS; | |
13228 | case ArithmeticOrLogicalOperator::MULTIPLY: | |
13229 | return LBP_MUL; | |
13230 | case ArithmeticOrLogicalOperator::DIVIDE: | |
13231 | return LBP_DIV; | |
13232 | case ArithmeticOrLogicalOperator::MODULUS: | |
13233 | return LBP_MOD; | |
13234 | case ArithmeticOrLogicalOperator::BITWISE_AND: | |
13235 | return LBP_AMP; | |
13236 | case ArithmeticOrLogicalOperator::BITWISE_OR: | |
13237 | return LBP_PIPE; | |
13238 | case ArithmeticOrLogicalOperator::BITWISE_XOR: | |
13239 | return LBP_CARET; | |
13240 | case ArithmeticOrLogicalOperator::LEFT_SHIFT: | |
13241 | return LBP_L_SHIFT; | |
13242 | case ArithmeticOrLogicalOperator::RIGHT_SHIFT: | |
13243 | return LBP_R_SHIFT; | |
13244 | default: | |
13245 | // WTF? should not happen, this is an error | |
13246 | gcc_unreachable (); | |
13247 | ||
13248 | return LBP_PLUS; | |
13249 | } | |
13250 | } | |
13251 | ||
13252 | // Parses an arithmetic or logical expression (with Pratt parsing). | |
13253 | template <typename ManagedTokenSource> | |
13254 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13255 | Parser<ManagedTokenSource>::parse_arithmetic_or_logical_expr ( | |
13256 | const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec, | |
13257 | AST::ArithmeticOrLogicalExpr::ExprType expr_type, | |
13258 | ParseRestrictions restrictions) | |
13259 | { | |
13260 | // parse RHS (as tok has already been consumed in parse_expression) | |
13261 | std::unique_ptr<AST::Expr> right | |
13262 | = parse_expr (get_lbp_for_arithmetic_or_logical_expr (expr_type), | |
13263 | AST::AttrVec (), restrictions); | |
13264 | if (right == nullptr) | |
13265 | return nullptr; | |
13266 | ||
13267 | // TODO: check types. actually, do so during semantic analysis | |
13268 | Location locus = left->get_locus (); | |
13269 | ||
13270 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13271 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13272 | expr_type, locus)); | |
13273 | } | |
13274 | ||
13275 | // Parses a binary addition expression (with Pratt parsing). | |
13276 | template <typename ManagedTokenSource> | |
13277 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13278 | Parser<ManagedTokenSource>::parse_binary_plus_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_PLUS, AST::AttrVec (), restrictions); | |
13285 | if (right == nullptr) | |
13286 | return nullptr; | |
13287 | ||
13288 | // TODO: check types. actually, do so during semantic analysis | |
13289 | Location locus = left->get_locus (); | |
13290 | ||
13291 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13292 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13293 | ArithmeticOrLogicalOperator::ADD, locus)); | |
13294 | } | |
13295 | ||
13296 | // Parses a binary subtraction expression (with Pratt parsing). | |
13297 | template <typename ManagedTokenSource> | |
13298 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13299 | Parser<ManagedTokenSource>::parse_binary_minus_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_MINUS, AST::AttrVec (), restrictions); | |
13306 | if (right == nullptr) | |
13307 | return nullptr; | |
13308 | ||
13309 | // TODO: check types. actually, do so during semantic analysis | |
13310 | Location locus = left->get_locus (); | |
13311 | ||
13312 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13313 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13314 | ArithmeticOrLogicalOperator::SUBTRACT, | |
13315 | locus)); | |
13316 | } | |
13317 | ||
13318 | // Parses a binary multiplication expression (with Pratt parsing). | |
13319 | template <typename ManagedTokenSource> | |
13320 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13321 | Parser<ManagedTokenSource>::parse_binary_mult_expr ( | |
13322 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13323 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13324 | { | |
13325 | // parse RHS (as tok has already been consumed in parse_expression) | |
13326 | std::unique_ptr<AST::Expr> right | |
13327 | = parse_expr (LBP_MUL, AST::AttrVec (), restrictions); | |
13328 | if (right == nullptr) | |
13329 | return nullptr; | |
13330 | ||
13331 | // TODO: check types. actually, do so during semantic analysis | |
13332 | Location locus = left->get_locus (); | |
13333 | ||
13334 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13335 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13336 | ArithmeticOrLogicalOperator::MULTIPLY, | |
13337 | locus)); | |
13338 | } | |
13339 | ||
13340 | // Parses a binary division expression (with Pratt parsing). | |
13341 | template <typename ManagedTokenSource> | |
13342 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13343 | Parser<ManagedTokenSource>::parse_binary_div_expr ( | |
13344 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13345 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13346 | { | |
13347 | // parse RHS (as tok has already been consumed in parse_expression) | |
13348 | std::unique_ptr<AST::Expr> right | |
13349 | = parse_expr (LBP_DIV, AST::AttrVec (), restrictions); | |
13350 | if (right == nullptr) | |
13351 | return nullptr; | |
13352 | ||
13353 | // TODO: check types. actually, do so during semantic analysis | |
13354 | Location locus = left->get_locus (); | |
13355 | ||
13356 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13357 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13358 | ArithmeticOrLogicalOperator::DIVIDE, | |
13359 | locus)); | |
13360 | } | |
13361 | ||
13362 | // Parses a binary modulo expression (with Pratt parsing). | |
13363 | template <typename ManagedTokenSource> | |
13364 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13365 | Parser<ManagedTokenSource>::parse_binary_mod_expr ( | |
13366 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13367 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13368 | { | |
13369 | // parse RHS (as tok has already been consumed in parse_expression) | |
13370 | std::unique_ptr<AST::Expr> right | |
13371 | = parse_expr (LBP_MOD, AST::AttrVec (), restrictions); | |
13372 | if (right == nullptr) | |
13373 | return nullptr; | |
13374 | ||
13375 | // TODO: check types. actually, do so during semantic analysis | |
13376 | Location locus = left->get_locus (); | |
13377 | ||
13378 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13379 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13380 | ArithmeticOrLogicalOperator::MODULUS, | |
13381 | locus)); | |
13382 | } | |
13383 | ||
13384 | /* Parses a binary bitwise (or eager logical) and expression (with Pratt | |
13385 | * parsing). */ | |
13386 | template <typename ManagedTokenSource> | |
13387 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13388 | Parser<ManagedTokenSource>::parse_bitwise_and_expr ( | |
13389 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13390 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13391 | { | |
13392 | // parse RHS (as tok has already been consumed in parse_expression) | |
13393 | std::unique_ptr<AST::Expr> right | |
13394 | = parse_expr (LBP_AMP, AST::AttrVec (), restrictions); | |
13395 | if (right == nullptr) | |
13396 | return nullptr; | |
13397 | ||
13398 | // TODO: check types. actually, do so during semantic analysis | |
13399 | Location locus = left->get_locus (); | |
13400 | ||
13401 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13402 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13403 | ArithmeticOrLogicalOperator::BITWISE_AND, | |
13404 | locus)); | |
13405 | } | |
13406 | ||
13407 | /* Parses a binary bitwise (or eager logical) or expression (with Pratt | |
13408 | * parsing). */ | |
13409 | template <typename ManagedTokenSource> | |
13410 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13411 | Parser<ManagedTokenSource>::parse_bitwise_or_expr ( | |
13412 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13413 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13414 | { | |
13415 | // parse RHS (as tok has already been consumed in parse_expression) | |
13416 | std::unique_ptr<AST::Expr> right | |
13417 | = parse_expr (LBP_PIPE, AST::AttrVec (), restrictions); | |
13418 | if (right == nullptr) | |
13419 | return nullptr; | |
13420 | ||
13421 | // TODO: check types. actually, do so during semantic analysis | |
13422 | Location locus = left->get_locus (); | |
13423 | ||
13424 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13425 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13426 | ArithmeticOrLogicalOperator::BITWISE_OR, | |
13427 | locus)); | |
13428 | } | |
13429 | ||
13430 | /* Parses a binary bitwise (or eager logical) xor expression (with Pratt | |
13431 | * parsing). */ | |
13432 | template <typename ManagedTokenSource> | |
13433 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13434 | Parser<ManagedTokenSource>::parse_bitwise_xor_expr ( | |
13435 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13436 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13437 | { | |
13438 | // parse RHS (as tok has already been consumed in parse_expression) | |
13439 | std::unique_ptr<AST::Expr> right | |
13440 | = parse_expr (LBP_CARET, AST::AttrVec (), restrictions); | |
13441 | if (right == nullptr) | |
13442 | return nullptr; | |
13443 | ||
13444 | // TODO: check types. actually, do so during semantic analysis | |
13445 | Location locus = left->get_locus (); | |
13446 | ||
13447 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13448 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13449 | ArithmeticOrLogicalOperator::BITWISE_XOR, | |
13450 | locus)); | |
13451 | } | |
13452 | ||
13453 | // Parses a binary left shift expression (with Pratt parsing). | |
13454 | template <typename ManagedTokenSource> | |
13455 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13456 | Parser<ManagedTokenSource>::parse_left_shift_expr ( | |
13457 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13458 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13459 | { | |
13460 | // parse RHS (as tok has already been consumed in parse_expression) | |
13461 | std::unique_ptr<AST::Expr> right | |
13462 | = parse_expr (LBP_L_SHIFT, AST::AttrVec (), restrictions); | |
13463 | if (right == nullptr) | |
13464 | return nullptr; | |
13465 | ||
13466 | // TODO: check types. actually, do so during semantic analysis | |
13467 | Location locus = left->get_locus (); | |
13468 | ||
13469 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13470 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13471 | ArithmeticOrLogicalOperator::LEFT_SHIFT, | |
13472 | locus)); | |
13473 | } | |
13474 | ||
13475 | // Parses a binary right shift expression (with Pratt parsing). | |
13476 | template <typename ManagedTokenSource> | |
13477 | std::unique_ptr<AST::ArithmeticOrLogicalExpr> | |
13478 | Parser<ManagedTokenSource>::parse_right_shift_expr ( | |
13479 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13480 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13481 | { | |
13482 | // parse RHS (as tok has already been consumed in parse_expression) | |
13483 | std::unique_ptr<AST::Expr> right | |
13484 | = parse_expr (LBP_R_SHIFT, AST::AttrVec (), restrictions); | |
13485 | if (right == nullptr) | |
13486 | return nullptr; | |
13487 | ||
13488 | // TODO: check types. actually, do so during semantic analysis | |
13489 | Location locus = left->get_locus (); | |
13490 | ||
13491 | return std::unique_ptr<AST::ArithmeticOrLogicalExpr> ( | |
13492 | new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right), | |
13493 | ArithmeticOrLogicalOperator::RIGHT_SHIFT, | |
13494 | locus)); | |
13495 | } | |
13496 | ||
13497 | /* Returns the left binding power for the given ComparisonExpr type. | |
13498 | * TODO make constexpr? Would that even do anything useful? */ | |
13499 | inline binding_powers | |
13500 | get_lbp_for_comparison_expr (AST::ComparisonExpr::ExprType expr_type) | |
13501 | { | |
13502 | switch (expr_type) | |
13503 | { | |
13504 | case ComparisonOperator::EQUAL: | |
13505 | return LBP_EQUAL; | |
13506 | case ComparisonOperator::NOT_EQUAL: | |
13507 | return LBP_NOT_EQUAL; | |
13508 | case ComparisonOperator::GREATER_THAN: | |
13509 | return LBP_GREATER_THAN; | |
13510 | case ComparisonOperator::LESS_THAN: | |
13511 | return LBP_SMALLER_THAN; | |
13512 | case ComparisonOperator::GREATER_OR_EQUAL: | |
13513 | return LBP_GREATER_EQUAL; | |
13514 | case ComparisonOperator::LESS_OR_EQUAL: | |
13515 | return LBP_SMALLER_EQUAL; | |
13516 | default: | |
13517 | // WTF? should not happen, this is an error | |
13518 | gcc_unreachable (); | |
13519 | ||
13520 | return LBP_EQUAL; | |
13521 | } | |
13522 | } | |
13523 | ||
13524 | /* Parses a ComparisonExpr of given type and LBP. TODO find a way to only | |
13525 | * specify one and have the other looked up - e.g. specify ExprType and | |
13526 | * binding power is looked up? */ | |
13527 | template <typename ManagedTokenSource> | |
13528 | std::unique_ptr<AST::ComparisonExpr> | |
13529 | Parser<ManagedTokenSource>::parse_comparison_expr ( | |
13530 | const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec, | |
13531 | AST::ComparisonExpr::ExprType expr_type, ParseRestrictions restrictions) | |
13532 | { | |
13533 | // parse RHS (as tok has already been consumed in parse_expression) | |
13534 | std::unique_ptr<AST::Expr> right | |
13535 | = parse_expr (get_lbp_for_comparison_expr (expr_type), AST::AttrVec (), | |
13536 | restrictions); | |
13537 | if (right == nullptr) | |
13538 | return nullptr; | |
13539 | ||
13540 | // TODO: check types. actually, do so during semantic analysis | |
13541 | Location locus = left->get_locus (); | |
13542 | ||
13543 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13544 | new AST::ComparisonExpr (std::move (left), std::move (right), expr_type, | |
13545 | locus)); | |
13546 | } | |
13547 | ||
13548 | // Parses a binary equal to expression (with Pratt parsing). | |
13549 | template <typename ManagedTokenSource> | |
13550 | std::unique_ptr<AST::ComparisonExpr> | |
13551 | Parser<ManagedTokenSource>::parse_binary_equal_expr ( | |
13552 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13553 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13554 | { | |
13555 | // parse RHS (as tok has already been consumed in parse_expression) | |
13556 | std::unique_ptr<AST::Expr> right | |
13557 | = parse_expr (LBP_EQUAL, AST::AttrVec (), restrictions); | |
13558 | if (right == nullptr) | |
13559 | return nullptr; | |
13560 | ||
13561 | // TODO: check types. actually, do so during semantic analysis | |
13562 | Location locus = left->get_locus (); | |
13563 | ||
13564 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13565 | new AST::ComparisonExpr (std::move (left), std::move (right), | |
13566 | ComparisonOperator::EQUAL, locus)); | |
13567 | } | |
13568 | ||
13569 | // Parses a binary not equal to expression (with Pratt parsing). | |
13570 | template <typename ManagedTokenSource> | |
13571 | std::unique_ptr<AST::ComparisonExpr> | |
13572 | Parser<ManagedTokenSource>::parse_binary_not_equal_expr ( | |
13573 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13574 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13575 | { | |
13576 | // parse RHS (as tok has already been consumed in parse_expression) | |
13577 | std::unique_ptr<AST::Expr> right | |
13578 | = parse_expr (LBP_NOT_EQUAL, AST::AttrVec (), restrictions); | |
13579 | if (right == nullptr) | |
13580 | return nullptr; | |
13581 | ||
13582 | // TODO: check types. actually, do so during semantic analysis | |
13583 | Location locus = left->get_locus (); | |
13584 | ||
13585 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13586 | new AST::ComparisonExpr (std::move (left), std::move (right), | |
13587 | ComparisonOperator::NOT_EQUAL, locus)); | |
13588 | } | |
13589 | ||
13590 | // Parses a binary greater than expression (with Pratt parsing). | |
13591 | template <typename ManagedTokenSource> | |
13592 | std::unique_ptr<AST::ComparisonExpr> | |
13593 | Parser<ManagedTokenSource>::parse_binary_greater_than_expr ( | |
13594 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13595 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13596 | { | |
13597 | // parse RHS (as tok has already been consumed in parse_expression) | |
13598 | std::unique_ptr<AST::Expr> right | |
13599 | = parse_expr (LBP_GREATER_THAN, AST::AttrVec (), restrictions); | |
13600 | if (right == nullptr) | |
13601 | return nullptr; | |
13602 | ||
13603 | // TODO: check types. actually, do so during semantic analysis | |
13604 | Location locus = left->get_locus (); | |
13605 | ||
13606 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13607 | new AST::ComparisonExpr (std::move (left), std::move (right), | |
13608 | ComparisonOperator::GREATER_THAN, locus)); | |
13609 | } | |
13610 | ||
13611 | // Parses a binary less than expression (with Pratt parsing). | |
13612 | template <typename ManagedTokenSource> | |
13613 | std::unique_ptr<AST::ComparisonExpr> | |
13614 | Parser<ManagedTokenSource>::parse_binary_less_than_expr ( | |
13615 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13616 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13617 | { | |
13618 | // parse RHS (as tok has already been consumed in parse_expression) | |
13619 | std::unique_ptr<AST::Expr> right | |
13620 | = parse_expr (LBP_SMALLER_THAN, AST::AttrVec (), restrictions); | |
13621 | if (right == nullptr) | |
13622 | return nullptr; | |
13623 | ||
13624 | // TODO: check types. actually, do so during semantic analysis | |
13625 | Location locus = left->get_locus (); | |
13626 | ||
13627 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13628 | new AST::ComparisonExpr (std::move (left), std::move (right), | |
13629 | ComparisonOperator::LESS_THAN, locus)); | |
13630 | } | |
13631 | ||
13632 | // Parses a binary greater than or equal to expression (with Pratt parsing). | |
13633 | template <typename ManagedTokenSource> | |
13634 | std::unique_ptr<AST::ComparisonExpr> | |
13635 | Parser<ManagedTokenSource>::parse_binary_greater_equal_expr ( | |
13636 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13637 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13638 | { | |
13639 | // parse RHS (as tok has already been consumed in parse_expression) | |
13640 | std::unique_ptr<AST::Expr> right | |
13641 | = parse_expr (LBP_GREATER_EQUAL, AST::AttrVec (), restrictions); | |
13642 | if (right == nullptr) | |
13643 | return nullptr; | |
13644 | ||
13645 | // TODO: check types. actually, do so during semantic analysis | |
13646 | Location locus = left->get_locus (); | |
13647 | ||
13648 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13649 | new AST::ComparisonExpr (std::move (left), std::move (right), | |
13650 | ComparisonOperator::GREATER_OR_EQUAL, locus)); | |
13651 | } | |
13652 | ||
13653 | // Parses a binary less than or equal to expression (with Pratt parsing). | |
13654 | template <typename ManagedTokenSource> | |
13655 | std::unique_ptr<AST::ComparisonExpr> | |
13656 | Parser<ManagedTokenSource>::parse_binary_less_equal_expr ( | |
13657 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13658 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13659 | { | |
13660 | // parse RHS (as tok has already been consumed in parse_expression) | |
13661 | std::unique_ptr<AST::Expr> right | |
13662 | = parse_expr (LBP_SMALLER_EQUAL, AST::AttrVec (), restrictions); | |
13663 | if (right == nullptr) | |
13664 | return nullptr; | |
13665 | ||
13666 | // TODO: check types. actually, do so during semantic analysis | |
13667 | Location locus = left->get_locus (); | |
13668 | ||
13669 | return std::unique_ptr<AST::ComparisonExpr> ( | |
13670 | new AST::ComparisonExpr (std::move (left), std::move (right), | |
13671 | ComparisonOperator::LESS_OR_EQUAL, locus)); | |
13672 | } | |
13673 | ||
13674 | // Parses a binary lazy boolean or expression (with Pratt parsing). | |
13675 | template <typename ManagedTokenSource> | |
13676 | std::unique_ptr<AST::LazyBooleanExpr> | |
13677 | Parser<ManagedTokenSource>::parse_lazy_or_expr ( | |
13678 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13679 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13680 | { | |
13681 | // parse RHS (as tok has already been consumed in parse_expression) | |
13682 | std::unique_ptr<AST::Expr> right | |
13683 | = parse_expr (LBP_LOGICAL_OR, AST::AttrVec (), restrictions); | |
13684 | if (right == nullptr) | |
13685 | return nullptr; | |
13686 | ||
13687 | // TODO: check types. actually, do so during semantic analysis | |
13688 | Location locus = left->get_locus (); | |
13689 | ||
13690 | return std::unique_ptr<AST::LazyBooleanExpr> ( | |
13691 | new AST::LazyBooleanExpr (std::move (left), std::move (right), | |
13692 | LazyBooleanOperator::LOGICAL_OR, locus)); | |
13693 | } | |
13694 | ||
13695 | // Parses a binary lazy boolean and expression (with Pratt parsing). | |
13696 | template <typename ManagedTokenSource> | |
13697 | std::unique_ptr<AST::LazyBooleanExpr> | |
13698 | Parser<ManagedTokenSource>::parse_lazy_and_expr ( | |
13699 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13700 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13701 | { | |
13702 | // parse RHS (as tok has already been consumed in parse_expression) | |
13703 | std::unique_ptr<AST::Expr> right | |
13704 | = parse_expr (LBP_LOGICAL_AND, AST::AttrVec (), restrictions); | |
13705 | if (right == nullptr) | |
13706 | return nullptr; | |
13707 | ||
13708 | // TODO: check types. actually, do so during semantic analysis | |
13709 | Location locus = left->get_locus (); | |
13710 | ||
13711 | return std::unique_ptr<AST::LazyBooleanExpr> ( | |
13712 | new AST::LazyBooleanExpr (std::move (left), std::move (right), | |
13713 | LazyBooleanOperator::LOGICAL_AND, locus)); | |
13714 | } | |
13715 | ||
13716 | // Parses a pseudo-binary infix type cast expression (with Pratt parsing). | |
13717 | template <typename ManagedTokenSource> | |
13718 | std::unique_ptr<AST::TypeCastExpr> | |
13719 | Parser<ManagedTokenSource>::parse_type_cast_expr ( | |
13720 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> expr_to_cast, | |
13721 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, | |
13722 | ParseRestrictions restrictions ATTRIBUTE_UNUSED) | |
13723 | { | |
13724 | // parse RHS (as tok has already been consumed in parse_expression) | |
13725 | std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds (); | |
13726 | if (type == nullptr) | |
13727 | return nullptr; | |
13728 | // FIXME: how do I get precedence put in here? | |
13729 | ||
13730 | // TODO: check types. actually, do so during semantic analysis | |
13731 | Location locus = expr_to_cast->get_locus (); | |
13732 | ||
13733 | return std::unique_ptr<AST::TypeCastExpr> ( | |
13734 | new AST::TypeCastExpr (std::move (expr_to_cast), std::move (type), locus)); | |
13735 | } | |
13736 | ||
13737 | // Parses a binary assignment expression (with Pratt parsing). | |
13738 | template <typename ManagedTokenSource> | |
13739 | std::unique_ptr<AST::AssignmentExpr> | |
13740 | Parser<ManagedTokenSource>::parse_assig_expr ( | |
13741 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13742 | AST::AttrVec outer_attrs, ParseRestrictions restrictions) | |
13743 | { | |
13744 | // parse RHS (as tok has already been consumed in parse_expression) | |
13745 | std::unique_ptr<AST::Expr> right | |
13746 | = parse_expr (LBP_ASSIG - 1, AST::AttrVec (), restrictions); | |
13747 | if (right == nullptr) | |
13748 | return nullptr; | |
13749 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13750 | ||
13751 | // TODO: check types. actually, do so during semantic analysis | |
13752 | Location locus = left->get_locus (); | |
13753 | ||
13754 | return std::unique_ptr<AST::AssignmentExpr> ( | |
13755 | new AST::AssignmentExpr (std::move (left), std::move (right), | |
13756 | std::move (outer_attrs), locus)); | |
13757 | } | |
13758 | ||
13759 | /* Returns the left binding power for the given CompoundAssignmentExpr type. | |
13760 | * TODO make constexpr? Would that even do anything useful? */ | |
13761 | inline binding_powers | |
13762 | get_lbp_for_compound_assignment_expr ( | |
13763 | AST::CompoundAssignmentExpr::ExprType expr_type) | |
13764 | { | |
13765 | switch (expr_type) | |
13766 | { | |
13767 | case CompoundAssignmentOperator::ADD: | |
13768 | return LBP_PLUS; | |
13769 | case CompoundAssignmentOperator::SUBTRACT: | |
13770 | return LBP_MINUS; | |
13771 | case CompoundAssignmentOperator::MULTIPLY: | |
13772 | return LBP_MUL; | |
13773 | case CompoundAssignmentOperator::DIVIDE: | |
13774 | return LBP_DIV; | |
13775 | case CompoundAssignmentOperator::MODULUS: | |
13776 | return LBP_MOD; | |
13777 | case CompoundAssignmentOperator::BITWISE_AND: | |
13778 | return LBP_AMP; | |
13779 | case CompoundAssignmentOperator::BITWISE_OR: | |
13780 | return LBP_PIPE; | |
13781 | case CompoundAssignmentOperator::BITWISE_XOR: | |
13782 | return LBP_CARET; | |
13783 | case CompoundAssignmentOperator::LEFT_SHIFT: | |
13784 | return LBP_L_SHIFT; | |
13785 | case CompoundAssignmentOperator::RIGHT_SHIFT: | |
13786 | return LBP_R_SHIFT; | |
13787 | default: | |
13788 | // WTF? should not happen, this is an error | |
13789 | gcc_unreachable (); | |
13790 | ||
13791 | return LBP_PLUS; | |
13792 | } | |
13793 | } | |
13794 | ||
13795 | // Parses a compound assignment expression (with Pratt parsing). | |
13796 | template <typename ManagedTokenSource> | |
13797 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13798 | Parser<ManagedTokenSource>::parse_compound_assignment_expr ( | |
13799 | const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec, | |
13800 | AST::CompoundAssignmentExpr::ExprType expr_type, | |
13801 | ParseRestrictions restrictions) | |
13802 | { | |
13803 | // parse RHS (as tok has already been consumed in parse_expression) | |
13804 | std::unique_ptr<AST::Expr> right | |
13805 | = parse_expr (get_lbp_for_compound_assignment_expr (expr_type) - 1, | |
13806 | AST::AttrVec (), restrictions); | |
13807 | if (right == nullptr) | |
13808 | return nullptr; | |
13809 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13810 | ||
13811 | // TODO: check types. actually, do so during semantic analysis | |
13812 | Location locus = left->get_locus (); | |
13813 | ||
13814 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13815 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13816 | expr_type, locus)); | |
13817 | } | |
13818 | ||
13819 | // Parses a binary add-assignment expression (with Pratt parsing). | |
13820 | template <typename ManagedTokenSource> | |
13821 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13822 | Parser<ManagedTokenSource>::parse_plus_assig_expr ( | |
13823 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13824 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13825 | { | |
13826 | // parse RHS (as tok has already been consumed in parse_expression) | |
13827 | std::unique_ptr<AST::Expr> right | |
13828 | = parse_expr (LBP_PLUS_ASSIG - 1, AST::AttrVec (), restrictions); | |
13829 | if (right == nullptr) | |
13830 | return nullptr; | |
13831 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13832 | ||
13833 | // TODO: check types. actually, do so during semantic analysis | |
13834 | Location locus = left->get_locus (); | |
13835 | ||
13836 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13837 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13838 | CompoundAssignmentOperator::ADD, locus)); | |
13839 | } | |
13840 | ||
13841 | // Parses a binary minus-assignment expression (with Pratt parsing). | |
13842 | template <typename ManagedTokenSource> | |
13843 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13844 | Parser<ManagedTokenSource>::parse_minus_assig_expr ( | |
13845 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13846 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13847 | { | |
13848 | // parse RHS (as tok has already been consumed in parse_expression) | |
13849 | std::unique_ptr<AST::Expr> right | |
13850 | = parse_expr (LBP_MINUS_ASSIG - 1, AST::AttrVec (), restrictions); | |
13851 | if (right == nullptr) | |
13852 | return nullptr; | |
13853 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13854 | ||
13855 | // TODO: check types. actually, do so during semantic analysis | |
13856 | Location locus = left->get_locus (); | |
13857 | ||
13858 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13859 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13860 | CompoundAssignmentOperator::SUBTRACT, | |
13861 | locus)); | |
13862 | } | |
13863 | ||
13864 | // Parses a binary multiplication-assignment expression (with Pratt parsing). | |
13865 | template <typename ManagedTokenSource> | |
13866 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13867 | Parser<ManagedTokenSource>::parse_mult_assig_expr ( | |
13868 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13869 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13870 | { | |
13871 | // parse RHS (as tok has already been consumed in parse_expression) | |
13872 | std::unique_ptr<AST::Expr> right | |
13873 | = parse_expr (LBP_MULT_ASSIG - 1, AST::AttrVec (), restrictions); | |
13874 | if (right == nullptr) | |
13875 | return nullptr; | |
13876 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13877 | ||
13878 | // TODO: check types. actually, do so during semantic analysis | |
13879 | Location locus = left->get_locus (); | |
13880 | ||
13881 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13882 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13883 | CompoundAssignmentOperator::MULTIPLY, | |
13884 | locus)); | |
13885 | } | |
13886 | ||
13887 | // Parses a binary division-assignment expression (with Pratt parsing). | |
13888 | template <typename ManagedTokenSource> | |
13889 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13890 | Parser<ManagedTokenSource>::parse_div_assig_expr ( | |
13891 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13892 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13893 | { | |
13894 | // parse RHS (as tok has already been consumed in parse_expression) | |
13895 | std::unique_ptr<AST::Expr> right | |
13896 | = parse_expr (LBP_DIV_ASSIG - 1, AST::AttrVec (), restrictions); | |
13897 | if (right == nullptr) | |
13898 | return nullptr; | |
13899 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13900 | ||
13901 | // TODO: check types. actually, do so during semantic analysis | |
13902 | Location locus = left->get_locus (); | |
13903 | ||
13904 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13905 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13906 | CompoundAssignmentOperator::DIVIDE, | |
13907 | locus)); | |
13908 | } | |
13909 | ||
13910 | // Parses a binary modulo-assignment expression (with Pratt parsing). | |
13911 | template <typename ManagedTokenSource> | |
13912 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13913 | Parser<ManagedTokenSource>::parse_mod_assig_expr ( | |
13914 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13915 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13916 | { | |
13917 | // parse RHS (as tok has already been consumed in parse_expression) | |
13918 | std::unique_ptr<AST::Expr> right | |
13919 | = parse_expr (LBP_MOD_ASSIG - 1, AST::AttrVec (), restrictions); | |
13920 | if (right == nullptr) | |
13921 | return nullptr; | |
13922 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13923 | ||
13924 | // TODO: check types. actually, do so during semantic analysis | |
13925 | Location locus = left->get_locus (); | |
13926 | ||
13927 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13928 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13929 | CompoundAssignmentOperator::MODULUS, | |
13930 | locus)); | |
13931 | } | |
13932 | ||
13933 | // Parses a binary and-assignment expression (with Pratt parsing). | |
13934 | template <typename ManagedTokenSource> | |
13935 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13936 | Parser<ManagedTokenSource>::parse_and_assig_expr ( | |
13937 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13938 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13939 | { | |
13940 | // parse RHS (as tok has already been consumed in parse_expression) | |
13941 | std::unique_ptr<AST::Expr> right | |
13942 | = parse_expr (LBP_AMP_ASSIG - 1, AST::AttrVec (), restrictions); | |
13943 | if (right == nullptr) | |
13944 | return nullptr; | |
13945 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13946 | ||
13947 | // TODO: check types. actually, do so during semantic analysis | |
13948 | Location locus = left->get_locus (); | |
13949 | ||
13950 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13951 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13952 | CompoundAssignmentOperator::BITWISE_AND, | |
13953 | locus)); | |
13954 | } | |
13955 | ||
13956 | // Parses a binary or-assignment expression (with Pratt parsing). | |
13957 | template <typename ManagedTokenSource> | |
13958 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13959 | Parser<ManagedTokenSource>::parse_or_assig_expr ( | |
13960 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13961 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13962 | { | |
13963 | // parse RHS (as tok has already been consumed in parse_expression) | |
13964 | std::unique_ptr<AST::Expr> right | |
13965 | = parse_expr (LBP_PIPE_ASSIG - 1, AST::AttrVec (), restrictions); | |
13966 | if (right == nullptr) | |
13967 | return nullptr; | |
13968 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13969 | ||
13970 | // TODO: check types. actually, do so during semantic analysis | |
13971 | Location locus = left->get_locus (); | |
13972 | ||
13973 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13974 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13975 | CompoundAssignmentOperator::BITWISE_OR, | |
13976 | locus)); | |
13977 | } | |
13978 | ||
13979 | // Parses a binary xor-assignment expression (with Pratt parsing). | |
13980 | template <typename ManagedTokenSource> | |
13981 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
13982 | Parser<ManagedTokenSource>::parse_xor_assig_expr ( | |
13983 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
13984 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
13985 | { | |
13986 | // parse RHS (as tok has already been consumed in parse_expression) | |
13987 | std::unique_ptr<AST::Expr> right | |
13988 | = parse_expr (LBP_CARET_ASSIG - 1, AST::AttrVec (), restrictions); | |
13989 | if (right == nullptr) | |
13990 | return nullptr; | |
13991 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
13992 | ||
13993 | // TODO: check types. actually, do so during semantic analysis | |
13994 | Location locus = left->get_locus (); | |
13995 | ||
13996 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
13997 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
13998 | CompoundAssignmentOperator::BITWISE_XOR, | |
13999 | locus)); | |
14000 | } | |
14001 | ||
14002 | // Parses a binary left shift-assignment expression (with Pratt parsing). | |
14003 | template <typename ManagedTokenSource> | |
14004 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
14005 | Parser<ManagedTokenSource>::parse_left_shift_assig_expr ( | |
14006 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
14007 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
14008 | { | |
14009 | // parse RHS (as tok has already been consumed in parse_expression) | |
14010 | std::unique_ptr<AST::Expr> right | |
14011 | = parse_expr (LBP_L_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions); | |
14012 | if (right == nullptr) | |
14013 | return nullptr; | |
14014 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
14015 | ||
14016 | // TODO: check types. actually, do so during semantic analysis | |
14017 | Location locus = left->get_locus (); | |
14018 | ||
14019 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
14020 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
14021 | CompoundAssignmentOperator::LEFT_SHIFT, | |
14022 | locus)); | |
14023 | } | |
14024 | ||
14025 | // Parses a binary right shift-assignment expression (with Pratt parsing). | |
14026 | template <typename ManagedTokenSource> | |
14027 | std::unique_ptr<AST::CompoundAssignmentExpr> | |
14028 | Parser<ManagedTokenSource>::parse_right_shift_assig_expr ( | |
14029 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
14030 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
14031 | { | |
14032 | // parse RHS (as tok has already been consumed in parse_expression) | |
14033 | std::unique_ptr<AST::Expr> right | |
14034 | = parse_expr (LBP_R_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions); | |
14035 | if (right == nullptr) | |
14036 | return nullptr; | |
14037 | // FIXME: ensure right-associativity for this - 'LBP - 1' may do this? | |
14038 | ||
14039 | // TODO: check types. actually, do so during semantic analysis | |
14040 | Location locus = left->get_locus (); | |
14041 | ||
14042 | return std::unique_ptr<AST::CompoundAssignmentExpr> ( | |
14043 | new AST::CompoundAssignmentExpr (std::move (left), std::move (right), | |
14044 | CompoundAssignmentOperator::RIGHT_SHIFT, | |
14045 | locus)); | |
14046 | } | |
14047 | ||
14048 | // Parses a postfix unary await expression (with Pratt parsing). | |
14049 | template <typename ManagedTokenSource> | |
14050 | std::unique_ptr<AST::AwaitExpr> | |
14051 | Parser<ManagedTokenSource>::parse_await_expr ( | |
14052 | const_TokenPtr tok, std::unique_ptr<AST::Expr> expr_to_await, | |
14053 | AST::AttrVec outer_attrs) | |
14054 | { | |
14055 | /* skip "await" identifier (as "." has already been consumed in | |
14056 | * parse_expression) this assumes that the identifier was already identified | |
14057 | * as await */ | |
14058 | if (!skip_token (IDENTIFIER)) | |
14059 | { | |
14060 | Error error (tok->get_locus (), "failed to skip %<await%> in await expr " | |
14061 | "- this is probably a deep issue"); | |
14062 | add_error (std::move (error)); | |
14063 | ||
14064 | // skip somewhere? | |
14065 | return nullptr; | |
14066 | } | |
14067 | ||
14068 | // TODO: check inside async block in semantic analysis | |
14069 | Location locus = expr_to_await->get_locus (); | |
14070 | ||
14071 | return std::unique_ptr<AST::AwaitExpr> ( | |
14072 | new AST::AwaitExpr (std::move (expr_to_await), std::move (outer_attrs), | |
14073 | locus)); | |
14074 | } | |
14075 | ||
14076 | /* Parses an exclusive range ('..') in left denotation position (i.e. | |
14077 | * RangeFromExpr or RangeFromToExpr). */ | |
14078 | template <typename ManagedTokenSource> | |
14079 | std::unique_ptr<AST::RangeExpr> | |
14080 | Parser<ManagedTokenSource>::parse_led_range_exclusive_expr ( | |
14081 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
14082 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
14083 | { | |
14084 | // FIXME: this probably parses expressions accidently or whatever | |
14085 | // try parsing RHS (as tok has already been consumed in parse_expression) | |
14086 | // Can be nullptr, in which case it is a RangeFromExpr, otherwise a | |
14087 | // RangeFromToExpr. | |
14088 | restrictions.expr_can_be_null = true; | |
14089 | std::unique_ptr<AST::Expr> right | |
14090 | = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions); | |
14091 | ||
14092 | Location locus = left->get_locus (); | |
14093 | ||
14094 | if (right == nullptr) | |
14095 | { | |
14096 | // range from expr | |
14097 | return std::unique_ptr<AST::RangeFromExpr> ( | |
14098 | new AST::RangeFromExpr (std::move (left), locus)); | |
14099 | } | |
14100 | else | |
14101 | { | |
14102 | return std::unique_ptr<AST::RangeFromToExpr> ( | |
14103 | new AST::RangeFromToExpr (std::move (left), std::move (right), locus)); | |
14104 | } | |
14105 | // FIXME: make non-associative | |
14106 | } | |
14107 | ||
14108 | /* Parses an exclusive range ('..') in null denotation position (i.e. | |
14109 | * RangeToExpr or RangeFullExpr). */ | |
14110 | template <typename ManagedTokenSource> | |
14111 | std::unique_ptr<AST::RangeExpr> | |
14112 | Parser<ManagedTokenSource>::parse_nud_range_exclusive_expr ( | |
14113 | const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED) | |
14114 | { | |
14115 | // FIXME: this probably parses expressions accidently or whatever | |
14116 | // try parsing RHS (as tok has already been consumed in parse_expression) | |
14117 | std::unique_ptr<AST::Expr> right = parse_expr (LBP_DOT_DOT, AST::AttrVec ()); | |
14118 | ||
14119 | Location locus = tok->get_locus (); | |
14120 | ||
14121 | if (right == nullptr) | |
14122 | { | |
14123 | // range from expr | |
14124 | return std::unique_ptr<AST::RangeFullExpr> ( | |
14125 | new AST::RangeFullExpr (locus)); | |
14126 | } | |
14127 | else | |
14128 | { | |
14129 | return std::unique_ptr<AST::RangeToExpr> ( | |
14130 | new AST::RangeToExpr (std::move (right), locus)); | |
14131 | } | |
14132 | // FIXME: make non-associative | |
14133 | } | |
14134 | ||
14135 | // Parses a full binary range inclusive expression. | |
14136 | template <typename ManagedTokenSource> | |
14137 | std::unique_ptr<AST::RangeFromToInclExpr> | |
14138 | Parser<ManagedTokenSource>::parse_range_inclusive_expr ( | |
14139 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left, | |
14140 | AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions) | |
14141 | { | |
14142 | // parse RHS (as tok has already been consumed in parse_expression) | |
14143 | std::unique_ptr<AST::Expr> right | |
14144 | = parse_expr (LBP_DOT_DOT_EQ, AST::AttrVec (), restrictions); | |
14145 | if (right == nullptr) | |
14146 | return nullptr; | |
14147 | // FIXME: make non-associative | |
14148 | ||
14149 | // TODO: check types. actually, do so during semantic analysis | |
14150 | Location locus = left->get_locus (); | |
14151 | ||
14152 | return std::unique_ptr<AST::RangeFromToInclExpr> ( | |
14153 | new AST::RangeFromToInclExpr (std::move (left), std::move (right), locus)); | |
14154 | } | |
14155 | ||
14156 | // Parses an inclusive range-to prefix unary expression. | |
14157 | template <typename ManagedTokenSource> | |
14158 | std::unique_ptr<AST::RangeToInclExpr> | |
14159 | Parser<ManagedTokenSource>::parse_range_to_inclusive_expr ( | |
14160 | const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED) | |
14161 | { | |
14162 | // parse RHS (as tok has already been consumed in parse_expression) | |
14163 | std::unique_ptr<AST::Expr> right = parse_expr (LBP_DOT_DOT_EQ); | |
14164 | if (right == nullptr) | |
14165 | return nullptr; | |
14166 | // FIXME: make non-associative | |
14167 | ||
14168 | // TODO: check types. actually, do so during semantic analysis | |
14169 | ||
14170 | return std::unique_ptr<AST::RangeToInclExpr> ( | |
14171 | new AST::RangeToInclExpr (std::move (right), tok->get_locus ())); | |
14172 | } | |
14173 | ||
14174 | // Parses a pseudo-binary infix tuple index expression. | |
14175 | template <typename ManagedTokenSource> | |
14176 | std::unique_ptr<AST::TupleIndexExpr> | |
14177 | Parser<ManagedTokenSource>::parse_tuple_index_expr ( | |
14178 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> tuple_expr, | |
14179 | AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED) | |
14180 | { | |
14181 | // parse int literal (as token already skipped) | |
14182 | const_TokenPtr index_tok = expect_token (INT_LITERAL); | |
14183 | if (index_tok == nullptr) | |
14184 | { | |
14185 | return nullptr; | |
14186 | } | |
14187 | std::string index = index_tok->get_str (); | |
14188 | ||
14189 | // convert to integer | |
14190 | if (!index_tok->is_pure_decimal ()) | |
14191 | { | |
14192 | Error error (index_tok->get_locus (), | |
14193 | "tuple index should be a pure decimal literal"); | |
14194 | add_error (std::move (error)); | |
14195 | } | |
14196 | int index_int = atoi (index.c_str ()); | |
14197 | ||
14198 | Location locus = tuple_expr->get_locus (); | |
14199 | ||
14200 | return std::unique_ptr<AST::TupleIndexExpr> ( | |
14201 | new AST::TupleIndexExpr (std::move (tuple_expr), index_int, | |
14202 | std::move (outer_attrs), locus)); | |
14203 | } | |
14204 | ||
14205 | // Parses a pseudo-binary infix array (or slice) index expression. | |
14206 | template <typename ManagedTokenSource> | |
14207 | std::unique_ptr<AST::ArrayIndexExpr> | |
14208 | Parser<ManagedTokenSource>::parse_index_expr ( | |
14209 | const_TokenPtr, std::unique_ptr<AST::Expr> array_expr, | |
14210 | AST::AttrVec outer_attrs, ParseRestrictions) | |
14211 | { | |
14212 | // parse RHS (as tok has already been consumed in parse_expression) | |
14213 | /*std::unique_ptr<AST::Expr> index_expr | |
14214 | = parse_expr (LBP_ARRAY_REF, AST::AttrVec (), | |
14215 | restrictions);*/ | |
14216 | // TODO: conceptually, should treat [] as brackets, so just parse all expr | |
14217 | std::unique_ptr<AST::Expr> index_expr = parse_expr (); | |
14218 | if (index_expr == nullptr) | |
14219 | return nullptr; | |
14220 | ||
14221 | // skip ']' at end of array | |
14222 | if (!skip_token (RIGHT_SQUARE)) | |
14223 | { | |
14224 | // skip somewhere? | |
14225 | return nullptr; | |
14226 | } | |
14227 | ||
14228 | // TODO: check types. actually, do so during semantic analysis | |
14229 | Location locus = array_expr->get_locus (); | |
14230 | ||
14231 | return std::unique_ptr<AST::ArrayIndexExpr> ( | |
14232 | new AST::ArrayIndexExpr (std::move (array_expr), std::move (index_expr), | |
14233 | std::move (outer_attrs), locus)); | |
14234 | } | |
14235 | ||
14236 | // Parses a pseudo-binary infix struct field access expression. | |
14237 | template <typename ManagedTokenSource> | |
14238 | std::unique_ptr<AST::FieldAccessExpr> | |
14239 | Parser<ManagedTokenSource>::parse_field_access_expr ( | |
14240 | const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> struct_expr, | |
14241 | AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED) | |
14242 | { | |
14243 | /* get field name identifier (assume that this is a field access expr and | |
14244 | * not await, for instance) */ | |
14245 | const_TokenPtr ident_tok = expect_token (IDENTIFIER); | |
14246 | if (ident_tok == nullptr) | |
14247 | return nullptr; | |
14248 | ||
14249 | Identifier ident = ident_tok->get_str (); | |
14250 | ||
14251 | Location locus = struct_expr->get_locus (); | |
14252 | ||
14253 | // TODO: check types. actually, do so during semantic analysis | |
14254 | return std::unique_ptr<AST::FieldAccessExpr> ( | |
14255 | new AST::FieldAccessExpr (std::move (struct_expr), std::move (ident), | |
14256 | std::move (outer_attrs), locus)); | |
14257 | } | |
14258 | ||
14259 | // Parses a pseudo-binary infix method call expression. | |
14260 | template <typename ManagedTokenSource> | |
14261 | std::unique_ptr<AST::MethodCallExpr> | |
14262 | Parser<ManagedTokenSource>::parse_method_call_expr ( | |
14263 | const_TokenPtr tok, std::unique_ptr<AST::Expr> receiver_expr, | |
14264 | AST::AttrVec outer_attrs, ParseRestrictions) | |
14265 | { | |
14266 | // parse path expr segment | |
14267 | AST::PathExprSegment segment = parse_path_expr_segment (); | |
14268 | if (segment.is_error ()) | |
14269 | { | |
14270 | Error error (tok->get_locus (), | |
14271 | "failed to parse path expr segment of method call expr"); | |
14272 | add_error (std::move (error)); | |
14273 | ||
14274 | return nullptr; | |
14275 | } | |
14276 | ||
14277 | // skip left parentheses | |
14278 | if (!skip_token (LEFT_PAREN)) | |
14279 | { | |
14280 | return nullptr; | |
14281 | } | |
14282 | ||
14283 | // parse method params (if they exist) | |
14284 | std::vector<std::unique_ptr<AST::Expr>> params; | |
14285 | ||
14286 | const_TokenPtr t = lexer.peek_token (); | |
14287 | while (t->get_id () != RIGHT_PAREN) | |
14288 | { | |
14289 | std::unique_ptr<AST::Expr> param = parse_expr (); | |
14290 | if (param == nullptr) | |
14291 | { | |
14292 | Error error (t->get_locus (), | |
14293 | "failed to parse method param in method call"); | |
14294 | add_error (std::move (error)); | |
14295 | ||
14296 | return nullptr; | |
14297 | } | |
14298 | params.push_back (std::move (param)); | |
14299 | ||
14300 | if (lexer.peek_token ()->get_id () != COMMA) | |
14301 | break; | |
14302 | ||
14303 | lexer.skip_token (); | |
14304 | t = lexer.peek_token (); | |
14305 | } | |
14306 | ||
14307 | // skip right paren | |
14308 | if (!skip_token (RIGHT_PAREN)) | |
14309 | { | |
14310 | return nullptr; | |
14311 | } | |
14312 | ||
14313 | // TODO: check types. actually do so in semantic analysis pass. | |
14314 | Location locus = receiver_expr->get_locus (); | |
14315 | ||
14316 | return std::unique_ptr<AST::MethodCallExpr> ( | |
14317 | new AST::MethodCallExpr (std::move (receiver_expr), std::move (segment), | |
14318 | std::move (params), std::move (outer_attrs), | |
14319 | locus)); | |
14320 | } | |
14321 | ||
14322 | // Parses a pseudo-binary infix function call expression. | |
14323 | template <typename ManagedTokenSource> | |
14324 | std::unique_ptr<AST::CallExpr> | |
14325 | Parser<ManagedTokenSource>::parse_function_call_expr ( | |
14326 | const_TokenPtr, std::unique_ptr<AST::Expr> function_expr, | |
14327 | AST::AttrVec outer_attrs, ParseRestrictions) | |
14328 | { | |
14329 | // parse function params (if they exist) | |
14330 | std::vector<std::unique_ptr<AST::Expr>> params; | |
14331 | ||
14332 | const_TokenPtr t = lexer.peek_token (); | |
14333 | while (t->get_id () != RIGHT_PAREN) | |
14334 | { | |
14335 | std::unique_ptr<AST::Expr> param = parse_expr (); | |
14336 | if (param == nullptr) | |
14337 | { | |
14338 | Error error (t->get_locus (), | |
14339 | "failed to parse function param in function call"); | |
14340 | add_error (std::move (error)); | |
14341 | ||
14342 | return nullptr; | |
14343 | } | |
14344 | params.push_back (std::move (param)); | |
14345 | ||
14346 | if (lexer.peek_token ()->get_id () != COMMA) | |
14347 | break; | |
14348 | ||
14349 | lexer.skip_token (); | |
14350 | t = lexer.peek_token (); | |
14351 | } | |
14352 | ||
14353 | // skip ')' at end of param list | |
14354 | if (!skip_token (RIGHT_PAREN)) | |
14355 | { | |
14356 | // skip somewhere? | |
14357 | return nullptr; | |
14358 | } | |
14359 | ||
14360 | // TODO: check types. actually, do so during semantic analysis | |
14361 | Location locus = function_expr->get_locus (); | |
14362 | ||
14363 | return std::unique_ptr<AST::CallExpr> ( | |
14364 | new AST::CallExpr (std::move (function_expr), std::move (params), | |
14365 | std::move (outer_attrs), locus)); | |
14366 | } | |
14367 | ||
14368 | /* Parses a macro invocation with a path in expression already parsed (but not | |
14369 | * '!' token). */ | |
14370 | template <typename ManagedTokenSource> | |
14371 | std::unique_ptr<AST::MacroInvocation> | |
14372 | Parser<ManagedTokenSource>::parse_macro_invocation_partial ( | |
14373 | AST::PathInExpression path, AST::AttrVec outer_attrs, | |
14374 | ParseRestrictions restrictions) | |
14375 | { | |
14376 | // macro invocation | |
14377 | if (!skip_token (EXCLAM)) | |
14378 | { | |
14379 | return nullptr; | |
14380 | } | |
14381 | ||
14382 | // convert PathInExpression to SimplePath - if this isn't possible, error | |
14383 | AST::SimplePath converted_path = path.as_simple_path (); | |
14384 | if (converted_path.is_empty ()) | |
14385 | { | |
14386 | Error error (lexer.peek_token ()->get_locus (), | |
14387 | "failed to parse simple path in macro invocation"); | |
14388 | add_error (std::move (error)); | |
14389 | ||
14390 | return nullptr; | |
14391 | } | |
14392 | ||
14393 | AST::DelimTokenTree tok_tree = parse_delim_token_tree (); | |
14394 | ||
14395 | rust_debug ("successfully parsed macro invocation (via partial)"); | |
14396 | ||
14397 | Location macro_locus = converted_path.get_locus (); | |
14398 | ||
14399 | return std::unique_ptr<AST::MacroInvocation> (new AST::MacroInvocation ( | |
14400 | AST::MacroInvocData (std::move (converted_path), std::move (tok_tree)), | |
14401 | std::move (outer_attrs), macro_locus, restrictions.expr_can_be_stmt)); | |
14402 | } | |
14403 | ||
14404 | /* Parses a struct expr struct with a path in expression already parsed (but | |
14405 | * not | |
14406 | * '{' token). */ | |
14407 | template <typename ManagedTokenSource> | |
14408 | std::unique_ptr<AST::StructExprStruct> | |
14409 | Parser<ManagedTokenSource>::parse_struct_expr_struct_partial ( | |
14410 | AST::PathInExpression path, AST::AttrVec outer_attrs) | |
14411 | { | |
14412 | // assume struct expr struct (as struct-enum disambiguation requires name | |
14413 | // lookup) again, make statement if final ';' | |
14414 | if (!skip_token (LEFT_CURLY)) | |
14415 | { | |
14416 | return nullptr; | |
14417 | } | |
14418 | ||
14419 | // parse inner attributes | |
14420 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
14421 | ||
14422 | // branch based on next token | |
14423 | const_TokenPtr t = lexer.peek_token (); | |
14424 | Location path_locus = path.get_locus (); | |
14425 | switch (t->get_id ()) | |
14426 | { | |
14427 | case RIGHT_CURLY: | |
14428 | // struct with no body | |
14429 | lexer.skip_token (); | |
14430 | ||
14431 | return std::unique_ptr<AST::StructExprStruct> ( | |
14432 | new AST::StructExprStruct (std::move (path), std::move (inner_attrs), | |
14433 | std::move (outer_attrs), path_locus)); | |
14434 | case DOT_DOT: | |
14435 | /* technically this would give a struct base-only struct, but this | |
14436 | * algorithm should work too. As such, AST type not happening. */ | |
14437 | case IDENTIFIER: | |
14438 | case INT_LITERAL: { | |
14439 | // struct with struct expr fields | |
14440 | ||
14441 | // parse struct expr fields | |
14442 | std::vector<std::unique_ptr<AST::StructExprField>> fields; | |
14443 | ||
14444 | while (t->get_id () != RIGHT_CURLY && t->get_id () != DOT_DOT) | |
14445 | { | |
14446 | std::unique_ptr<AST::StructExprField> field | |
14447 | = parse_struct_expr_field (); | |
14448 | if (field == nullptr) | |
14449 | { | |
14450 | Error error (t->get_locus (), | |
14451 | "failed to parse struct (or enum) expr field"); | |
14452 | add_error (std::move (error)); | |
14453 | ||
14454 | return nullptr; | |
14455 | } | |
14456 | ||
14457 | // DEBUG: | |
14458 | rust_debug ("struct/enum expr field validated to not be null"); | |
14459 | ||
14460 | fields.push_back (std::move (field)); | |
14461 | ||
14462 | // DEBUG: | |
14463 | rust_debug ("struct/enum expr field pushed back"); | |
14464 | ||
14465 | if (lexer.peek_token ()->get_id () != COMMA) | |
14466 | { | |
14467 | // DEBUG: | |
14468 | rust_debug ("lack of comma detected in struct/enum expr " | |
14469 | "fields - break"); | |
14470 | break; | |
14471 | } | |
14472 | lexer.skip_token (); | |
14473 | ||
14474 | // DEBUG: | |
14475 | rust_debug ("struct/enum expr fields comma skipped "); | |
14476 | ||
14477 | t = lexer.peek_token (); | |
14478 | } | |
14479 | ||
14480 | // DEBUG: | |
14481 | rust_debug ("struct/enum expr about to parse struct base "); | |
14482 | ||
14483 | // parse struct base if it exists | |
14484 | AST::StructBase struct_base = AST::StructBase::error (); | |
14485 | if (lexer.peek_token ()->get_id () == DOT_DOT) | |
14486 | { | |
14487 | Location dot_dot_location = lexer.peek_token ()->get_locus (); | |
14488 | lexer.skip_token (); | |
14489 | ||
14490 | // parse required struct base expr | |
14491 | std::unique_ptr<AST::Expr> base_expr = parse_expr (); | |
14492 | if (base_expr == nullptr) | |
14493 | { | |
14494 | Error error (lexer.peek_token ()->get_locus (), | |
14495 | "failed to parse struct base expression in struct " | |
14496 | "expression"); | |
14497 | add_error (std::move (error)); | |
14498 | ||
14499 | return nullptr; | |
14500 | } | |
14501 | ||
14502 | // DEBUG: | |
14503 | rust_debug ("struct/enum expr - parsed and validated base expr"); | |
14504 | ||
14505 | struct_base | |
14506 | = AST::StructBase (std::move (base_expr), dot_dot_location); | |
14507 | ||
14508 | // DEBUG: | |
14509 | rust_debug ("assigned struct base to new struct base "); | |
14510 | } | |
14511 | ||
14512 | if (!skip_token (RIGHT_CURLY)) | |
14513 | { | |
14514 | return nullptr; | |
14515 | } | |
14516 | ||
14517 | // DEBUG: | |
14518 | rust_debug ( | |
14519 | "struct/enum expr skipped right curly - done and ready to return"); | |
14520 | ||
14521 | return std::unique_ptr<AST::StructExprStructFields> ( | |
14522 | new AST::StructExprStructFields (std::move (path), std::move (fields), | |
14523 | path_locus, std::move (struct_base), | |
14524 | std::move (inner_attrs), | |
14525 | std::move (outer_attrs))); | |
14526 | } | |
14527 | default: | |
14528 | add_error ( | |
14529 | Error (t->get_locus (), | |
14530 | "unrecognised token %qs in struct (or enum) expression - " | |
14531 | "expected %<}%>, identifier, integer literal, or %<..%>", | |
14532 | t->get_token_description ())); | |
14533 | ||
14534 | return nullptr; | |
14535 | } | |
14536 | } | |
14537 | ||
14538 | /* Parses a struct expr tuple with a path in expression already parsed (but | |
14539 | * not | |
14540 | * '(' token). | |
14541 | * FIXME: this currently outputs a call expr, as they cannot be disambiguated. | |
14542 | * A better solution would be to just get this to call that function directly. | |
14543 | * */ | |
14544 | template <typename ManagedTokenSource> | |
14545 | std::unique_ptr<AST::CallExpr> | |
14546 | Parser<ManagedTokenSource>::parse_struct_expr_tuple_partial ( | |
14547 | AST::PathInExpression path, AST::AttrVec outer_attrs) | |
14548 | { | |
14549 | if (!skip_token (LEFT_PAREN)) | |
14550 | { | |
14551 | return nullptr; | |
14552 | } | |
14553 | ||
14554 | AST::AttrVec inner_attrs = parse_inner_attributes (); | |
14555 | ||
14556 | std::vector<std::unique_ptr<AST::Expr>> exprs; | |
14557 | ||
14558 | const_TokenPtr t = lexer.peek_token (); | |
14559 | while (t->get_id () != RIGHT_PAREN) | |
14560 | { | |
14561 | // parse expression (required) | |
14562 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
14563 | if (expr == nullptr) | |
14564 | { | |
14565 | Error error (t->get_locus (), "failed to parse expression in " | |
14566 | "struct (or enum) expression tuple"); | |
14567 | add_error (std::move (error)); | |
14568 | ||
14569 | return nullptr; | |
14570 | } | |
14571 | exprs.push_back (std::move (expr)); | |
14572 | ||
14573 | if (lexer.peek_token ()->get_id () != COMMA) | |
14574 | break; | |
14575 | ||
14576 | lexer.skip_token (); | |
14577 | ||
14578 | t = lexer.peek_token (); | |
14579 | } | |
14580 | ||
14581 | if (!skip_token (RIGHT_PAREN)) | |
14582 | { | |
14583 | return nullptr; | |
14584 | } | |
14585 | ||
14586 | Location path_locus = path.get_locus (); | |
14587 | ||
14588 | auto pathExpr = std::unique_ptr<AST::PathInExpression> ( | |
14589 | new AST::PathInExpression (std::move (path))); | |
14590 | ||
14591 | return std::unique_ptr<AST::CallExpr> ( | |
14592 | new AST::CallExpr (std::move (pathExpr), std::move (exprs), | |
14593 | std::move (outer_attrs), path_locus)); | |
14594 | } | |
14595 | ||
14596 | /* Parses a path in expression with the first token passed as a parameter (as | |
14597 | * it is skipped in token stream). Note that this only parses segment-first | |
14598 | * paths, not global ones. */ | |
14599 | template <typename ManagedTokenSource> | |
14600 | AST::PathInExpression | |
14601 | Parser<ManagedTokenSource>::parse_path_in_expression_pratt (const_TokenPtr tok) | |
14602 | { | |
14603 | // HACK-y way of making up for pratt-parsing consuming first token | |
14604 | ||
14605 | // DEBUG | |
14606 | rust_debug ("current peek token when starting path pratt parse: '%s'", | |
14607 | lexer.peek_token ()->get_token_description ()); | |
14608 | ||
14609 | // create segment vector | |
14610 | std::vector<AST::PathExprSegment> segments; | |
14611 | ||
14612 | std::string initial_str; | |
14613 | ||
14614 | switch (tok->get_id ()) | |
14615 | { | |
14616 | case IDENTIFIER: | |
14617 | initial_str = tok->get_str (); | |
14618 | break; | |
14619 | case SUPER: | |
14620 | initial_str = "super"; | |
14621 | break; | |
14622 | case SELF: | |
14623 | initial_str = "self"; | |
14624 | break; | |
14625 | case SELF_ALIAS: | |
14626 | initial_str = "Self"; | |
14627 | break; | |
14628 | case CRATE: | |
14629 | initial_str = "crate"; | |
14630 | break; | |
14631 | case DOLLAR_SIGN: | |
14632 | if (lexer.peek_token ()->get_id () == CRATE) | |
14633 | { | |
14634 | initial_str = "$crate"; | |
14635 | break; | |
14636 | } | |
14637 | gcc_fallthrough (); | |
14638 | default: | |
14639 | add_error (Error (tok->get_locus (), | |
14640 | "unrecognised token %qs in path in expression", | |
14641 | tok->get_token_description ())); | |
14642 | ||
14643 | return AST::PathInExpression::create_error (); | |
14644 | } | |
14645 | ||
14646 | // parse required initial segment | |
14647 | AST::PathExprSegment initial_segment (initial_str, tok->get_locus ()); | |
14648 | // parse generic args (and turbofish), if they exist | |
14649 | /* use lookahead to determine if they actually exist (don't want to | |
14650 | * accidently parse over next ident segment) */ | |
14651 | if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION | |
14652 | && lexer.peek_token (1)->get_id () == LEFT_ANGLE) | |
14653 | { | |
14654 | // skip scope resolution | |
14655 | lexer.skip_token (); | |
14656 | ||
14657 | AST::GenericArgs generic_args = parse_path_generic_args (); | |
14658 | ||
14659 | initial_segment | |
14660 | = AST::PathExprSegment (AST::PathIdentSegment (initial_str, | |
14661 | tok->get_locus ()), | |
14662 | tok->get_locus (), std::move (generic_args)); | |
14663 | } | |
14664 | if (initial_segment.is_error ()) | |
14665 | { | |
14666 | // skip after somewhere? | |
14667 | // don't necessarily throw error but yeah | |
14668 | ||
14669 | // DEBUG | |
14670 | rust_debug ("initial segment is error - returning null"); | |
14671 | ||
14672 | return AST::PathInExpression::create_error (); | |
14673 | } | |
14674 | segments.push_back (std::move (initial_segment)); | |
14675 | ||
14676 | // parse optional segments (as long as scope resolution operator exists) | |
14677 | const_TokenPtr t = lexer.peek_token (); | |
14678 | while (t->get_id () == SCOPE_RESOLUTION) | |
14679 | { | |
14680 | // skip scope resolution operator | |
14681 | lexer.skip_token (); | |
14682 | ||
14683 | // parse the actual segment - it is an error if it doesn't exist now | |
14684 | AST::PathExprSegment segment = parse_path_expr_segment (); | |
14685 | if (segment.is_error ()) | |
14686 | { | |
14687 | // skip after somewhere? | |
14688 | Error error (t->get_locus (), | |
14689 | "could not parse path expression segment"); | |
14690 | add_error (std::move (error)); | |
14691 | ||
14692 | return AST::PathInExpression::create_error (); | |
14693 | } | |
14694 | ||
14695 | segments.push_back (std::move (segment)); | |
14696 | ||
14697 | t = lexer.peek_token (); | |
14698 | } | |
14699 | ||
14700 | // DEBUG: | |
14701 | rust_debug ( | |
14702 | "current token (just about to return path to null denotation): '%s'", | |
14703 | lexer.peek_token ()->get_token_description ()); | |
14704 | ||
14705 | return AST::PathInExpression (std::move (segments), {}, tok->get_locus (), | |
14706 | false); | |
14707 | } | |
14708 | ||
14709 | // Parses a closure expression with pratt parsing (from null denotation). | |
14710 | template <typename ManagedTokenSource> | |
14711 | std::unique_ptr<AST::ClosureExpr> | |
14712 | Parser<ManagedTokenSource>::parse_closure_expr_pratt (const_TokenPtr tok, | |
14713 | AST::AttrVec outer_attrs) | |
14714 | { | |
14715 | // TODO: does this need pratt parsing (for precedence)? probably not, but | |
14716 | // idk | |
14717 | Location locus = tok->get_locus (); | |
14718 | bool has_move = false; | |
14719 | if (tok->get_id () == MOVE) | |
14720 | { | |
14721 | has_move = true; | |
14722 | tok = lexer.peek_token (); | |
14723 | lexer.skip_token (); | |
14724 | // skip token and reassign | |
14725 | } | |
14726 | ||
14727 | // handle parameter list | |
14728 | std::vector<AST::ClosureParam> params; | |
14729 | ||
14730 | switch (tok->get_id ()) | |
14731 | { | |
14732 | case OR: | |
14733 | // no parameters, don't skip token | |
14734 | break; | |
14735 | case PIPE: { | |
14736 | // actually may have parameters | |
14737 | // don't skip token | |
14738 | const_TokenPtr t = lexer.peek_token (); | |
14739 | while (t->get_id () != PIPE) | |
14740 | { | |
14741 | AST::ClosureParam param = parse_closure_param (); | |
14742 | if (param.is_error ()) | |
14743 | { | |
14744 | // TODO is this really an error? | |
14745 | Error error (t->get_locus (), "could not parse closure param"); | |
14746 | add_error (std::move (error)); | |
14747 | ||
14748 | return nullptr; | |
14749 | } | |
14750 | params.push_back (std::move (param)); | |
14751 | ||
14752 | if (lexer.peek_token ()->get_id () != COMMA) | |
14753 | { | |
14754 | // not an error but means param list is done | |
14755 | break; | |
14756 | } | |
14757 | // skip comma | |
14758 | lexer.skip_token (); | |
14759 | ||
14760 | t = lexer.peek_token (); | |
14761 | } | |
14762 | ||
14763 | if (!skip_token (PIPE)) | |
14764 | { | |
14765 | return nullptr; | |
14766 | } | |
14767 | break; | |
14768 | } | |
14769 | default: | |
14770 | add_error (Error (tok->get_locus (), | |
14771 | "unexpected token %qs in closure expression - expected " | |
14772 | "%<|%> or %<||%>", | |
14773 | tok->get_token_description ())); | |
14774 | ||
14775 | // skip somewhere? | |
14776 | return nullptr; | |
14777 | } | |
14778 | ||
14779 | // again branch based on next token | |
14780 | tok = lexer.peek_token (); | |
14781 | if (tok->get_id () == RETURN_TYPE) | |
14782 | { | |
14783 | // must be return type closure with block expr | |
14784 | ||
14785 | // skip "return type" token | |
14786 | lexer.skip_token (); | |
14787 | ||
14788 | // parse actual type, which is required | |
14789 | std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds (); | |
14790 | if (type == nullptr) | |
14791 | { | |
14792 | // error | |
14793 | Error error (tok->get_locus (), "failed to parse type for closure"); | |
14794 | add_error (std::move (error)); | |
14795 | ||
14796 | // skip somewhere? | |
14797 | return nullptr; | |
14798 | } | |
14799 | ||
14800 | // parse block expr, which is required | |
14801 | std::unique_ptr<AST::BlockExpr> block = parse_block_expr (); | |
14802 | if (block == nullptr) | |
14803 | { | |
14804 | // error | |
14805 | Error error (lexer.peek_token ()->get_locus (), | |
14806 | "failed to parse block expr in closure"); | |
14807 | add_error (std::move (error)); | |
14808 | ||
14809 | // skip somewhere? | |
14810 | return nullptr; | |
14811 | } | |
14812 | ||
14813 | return std::unique_ptr<AST::ClosureExprInnerTyped> ( | |
14814 | new AST::ClosureExprInnerTyped (std::move (type), std::move (block), | |
14815 | std::move (params), locus, has_move, | |
14816 | std::move (outer_attrs))); | |
14817 | } | |
14818 | else | |
14819 | { | |
14820 | // must be expr-only closure | |
14821 | ||
14822 | // parse expr, which is required | |
14823 | std::unique_ptr<AST::Expr> expr = parse_expr (); | |
14824 | if (expr == nullptr) | |
14825 | { | |
14826 | Error error (tok->get_locus (), | |
14827 | "failed to parse expression in closure"); | |
14828 | add_error (std::move (error)); | |
14829 | ||
14830 | // skip somewhere? | |
14831 | return nullptr; | |
14832 | } | |
14833 | ||
14834 | return std::unique_ptr<AST::ClosureExprInner> ( | |
14835 | new AST::ClosureExprInner (std::move (expr), std::move (params), locus, | |
14836 | has_move, std::move (outer_attrs))); | |
14837 | } | |
14838 | } | |
14839 | ||
14840 | /* Parses a tuple index expression (pratt-parsed) from a 'float' token as a | |
14841 | * result of lexer misidentification. */ | |
14842 | template <typename ManagedTokenSource> | |
14843 | std::unique_ptr<AST::TupleIndexExpr> | |
14844 | Parser<ManagedTokenSource>::parse_tuple_index_expr_float ( | |
14845 | const_TokenPtr tok, std::unique_ptr<AST::Expr> tuple_expr, | |
14846 | AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED) | |
14847 | { | |
14848 | // only works on float literals | |
14849 | if (tok->get_id () != FLOAT_LITERAL) | |
14850 | return nullptr; | |
14851 | ||
14852 | // DEBUG: | |
14853 | rust_debug ("exact string form of float: '%s'", tok->get_str ().c_str ()); | |
14854 | ||
14855 | // get float string and remove dot and initial 0 | |
14856 | std::string index_str = tok->get_str (); | |
14857 | index_str.erase (index_str.begin ()); | |
14858 | ||
14859 | // get int from string | |
14860 | int index = atoi (index_str.c_str ()); | |
14861 | ||
14862 | Location locus = tuple_expr->get_locus (); | |
14863 | ||
14864 | return std::unique_ptr<AST::TupleIndexExpr> ( | |
14865 | new AST::TupleIndexExpr (std::move (tuple_expr), index, | |
14866 | std::move (outer_attrs), locus)); | |
14867 | } | |
14868 | ||
14869 | // Returns true if the next token is END, ELSE, or EOF; | |
14870 | template <typename ManagedTokenSource> | |
14871 | bool | |
14872 | Parser<ManagedTokenSource>::done_end_or_else () | |
14873 | { | |
14874 | const_TokenPtr t = lexer.peek_token (); | |
14875 | return (t->get_id () == RIGHT_CURLY || t->get_id () == ELSE | |
14876 | || t->get_id () == END_OF_FILE); | |
14877 | } | |
14878 | ||
14879 | // Returns true if the next token is END or EOF. | |
14880 | template <typename ManagedTokenSource> | |
14881 | bool | |
14882 | Parser<ManagedTokenSource>::done_end () | |
14883 | { | |
14884 | const_TokenPtr t = lexer.peek_token (); | |
14885 | return (t->get_id () == RIGHT_CURLY || t->get_id () == END_OF_FILE); | |
14886 | } | |
14887 | ||
14888 | // Dumps lexer output to stderr. | |
14889 | template <typename ManagedTokenSource> | |
14890 | void | |
14891 | Parser<ManagedTokenSource>::debug_dump_lex_output (std::ostream &out) | |
14892 | { | |
14893 | /* TODO: a better implementation of "lexer dump" (as in dump what was | |
14894 | * actually tokenised) would actually be to "write" a token to a file every | |
14895 | * time skip_token() here was called. This would reflect the parser | |
14896 | * modifications to the token stream, such as fixing the template angle | |
14897 | * brackets. */ | |
14898 | ||
14899 | const_TokenPtr tok = lexer.peek_token (); | |
14900 | ||
14901 | while (true) | |
14902 | { | |
14903 | if (tok->get_id () == Rust::END_OF_FILE) | |
14904 | break; | |
14905 | ||
14906 | bool has_text = tok->get_id () == Rust::IDENTIFIER | |
14907 | || tok->get_id () == Rust::INT_LITERAL | |
14908 | || tok->get_id () == Rust::FLOAT_LITERAL | |
14909 | || tok->get_id () == Rust::STRING_LITERAL | |
14910 | || tok->get_id () == Rust::CHAR_LITERAL | |
14911 | || tok->get_id () == Rust::BYTE_STRING_LITERAL | |
14912 | || tok->get_id () == Rust::BYTE_CHAR_LITERAL; | |
14913 | ||
14914 | Location loc = tok->get_locus (); | |
14915 | ||
14916 | out << "<id="; | |
14917 | out << tok->token_id_to_str (); | |
14918 | out << has_text ? (std::string (", text=") + tok->get_str () | |
14919 | + std::string (", typehint=") | |
14920 | + std::string (tok->get_type_hint_str ())) | |
14921 | : ""; | |
14922 | out << lexer.get_line_map ()->to_string (loc); | |
14923 | ||
14924 | lexer.skip_token (); | |
14925 | tok = lexer.peek_token (); | |
14926 | } | |
14927 | } | |
14928 | ||
14929 | // Parses crate and dumps AST to stderr, recursively. | |
14930 | template <typename ManagedTokenSource> | |
14931 | void | |
14932 | Parser<ManagedTokenSource>::debug_dump_ast_output (AST::Crate &crate, | |
14933 | std::ostream &out) | |
14934 | { | |
14935 | out << crate.as_string (); | |
14936 | } | |
14937 | } // namespace Rust |