Line data Source code
1 : // Copyright (C) 2025-2026 Free Software Foundation, Inc.
2 :
3 : // This file is part of GCC.
4 :
5 : // GCC is free software; you can redistribute it and/or modify it under
6 : // the terms of the GNU General Public License as published by the Free
7 : // Software Foundation; either version 3, or (at your option) any later
8 : // version.
9 :
10 : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : // for more details.
14 :
15 : // You should have received a copy of the GNU General Public License
16 : // along with GCC; see the file COPYING3. If not see
17 : // <http://www.gnu.org/licenses/>.
18 :
19 : /* DO NOT INCLUDE ANYWHERE - this is automatically included
20 : * by rust-parse-impl.h
21 : * This is also the reason why there are no include guards. */
22 :
23 : #include "rust-parse.h"
24 :
25 : namespace Rust {
26 :
27 : // Parses a block expression, including the curly braces at start and end.
28 : template <typename ManagedTokenSource>
29 : tl::expected<std::unique_ptr<AST::BlockExpr>, Parse::Error::Node>
30 23581 : Parser<ManagedTokenSource>::parse_block_expr (
31 : AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label,
32 : location_t pratt_parsed_loc)
33 : {
34 23581 : location_t locus = pratt_parsed_loc;
35 23581 : if (locus == UNKNOWN_LOCATION)
36 : {
37 22035 : locus = lexer.peek_token ()->get_locus ();
38 22035 : if (!skip_token (LEFT_CURLY))
39 : {
40 0 : skip_after_end_block ();
41 : return tl::unexpected<Parse::Error::Node> (
42 0 : Parse::Error::Node::MALFORMED);
43 : }
44 : }
45 :
46 23581 : AST::AttrVec inner_attrs = parse_inner_attributes ();
47 :
48 : // parse statements and expression
49 23581 : std::vector<std::unique_ptr<AST::Stmt>> stmts;
50 23581 : std::unique_ptr<AST::Expr> expr = nullptr;
51 :
52 23581 : const_TokenPtr t = lexer.peek_token ();
53 64575 : while (t->get_id () != RIGHT_CURLY)
54 : {
55 40994 : auto expr_or_stmt = parse_stmt_or_expr ();
56 40994 : if (!expr_or_stmt)
57 : {
58 35 : skip_after_end_block ();
59 : return tl::unexpected<Parse::Error::Node> (
60 35 : Parse::Error::Node::CHILD_ERROR);
61 : }
62 :
63 40959 : t = lexer.peek_token ();
64 :
65 40959 : if (expr_or_stmt->stmt != nullptr)
66 : {
67 24458 : stmts.push_back (std::move (expr_or_stmt->stmt));
68 : }
69 : else
70 : {
71 : // assign to expression and end parsing inside
72 16501 : expr = std::move (expr_or_stmt->expr);
73 : }
74 : }
75 :
76 23546 : location_t end_locus = t->get_locus ();
77 :
78 23546 : if (!skip_token (RIGHT_CURLY))
79 : {
80 : // We don't need to throw an error as it already reported by skip_token
81 0 : skip_after_end_block ();
82 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
83 : }
84 :
85 : // grammar allows for empty block expressions
86 :
87 23546 : stmts.shrink_to_fit ();
88 :
89 23546 : return std::unique_ptr<AST::BlockExpr> (
90 23549 : new AST::BlockExpr (std::move (stmts), std::move (expr),
91 : std::move (inner_attrs), std::move (outer_attrs),
92 23546 : std::move (label), locus, end_locus));
93 23581 : }
94 :
95 : /* Parse an anonymous const expression. This can be a regular const expression
96 : * or an underscore for deferred const inference */
97 : template <typename ManagedTokenSource>
98 : tl::expected<AST::AnonConst, Parse::Error::Node>
99 679 : Parser<ManagedTokenSource>::parse_anon_const ()
100 : {
101 679 : auto current = lexer.peek_token ();
102 679 : auto locus = current->get_locus ();
103 :
104 : // Special case deferred inference constants
105 679 : if (maybe_skip_token (UNDERSCORE))
106 13 : return AST::AnonConst (locus);
107 :
108 666 : auto expr = parse_expr ();
109 :
110 666 : if (!expr)
111 1 : return tl::make_unexpected (Parse::Error::Node{});
112 :
113 1330 : return AST::AnonConst (std::move (expr.value ()), locus);
114 666 : }
115 :
116 : /* Parse a "const block", a block preceded by the `const` keyword whose
117 : * statements can be const evaluated and used in constant contexts */
118 : template <typename ManagedTokenSource>
119 : tl::expected<std::unique_ptr<AST::ConstBlock>, Parse::Error::Node>
120 15 : Parser<ManagedTokenSource>::parse_const_block_expr (AST::AttrVec outer_attrs,
121 : location_t locus)
122 : {
123 15 : auto block_res = parse_block_expr ();
124 :
125 15 : if (!block_res)
126 : {
127 0 : add_error (Error (locus, "failed to parse inner block in const block"));
128 0 : skip_after_end_block ();
129 :
130 : return tl::unexpected<Parse::Error::Node> (
131 0 : Parse::Error::Node::CHILD_ERROR);
132 : }
133 15 : auto block = std::move (block_res.value ());
134 :
135 15 : auto block_locus = block->get_locus ();
136 :
137 30 : return std::make_unique<AST::ConstBlock> (AST::AnonConst (std::move (block),
138 : block_locus),
139 15 : locus, std::move (outer_attrs));
140 15 : }
141 :
142 : /* Parses a "grouped" expression (expression in parentheses), used to control
143 : * precedence. */
144 : template <typename ManagedTokenSource>
145 : tl::expected<std::unique_ptr<AST::GroupedExpr>, Parse::Error::Node>
146 0 : Parser<ManagedTokenSource>::parse_grouped_expr (AST::AttrVec outer_attrs)
147 : {
148 0 : location_t locus = lexer.peek_token ()->get_locus ();
149 0 : skip_token (LEFT_PAREN);
150 :
151 0 : AST::AttrVec inner_attrs = parse_inner_attributes ();
152 :
153 : // parse required expr inside parentheses
154 0 : auto expr_in_parens = parse_expr ();
155 0 : if (!expr_in_parens)
156 : {
157 : // skip after somewhere?
158 : // error?
159 : return tl::unexpected<Parse::Error::Node> (
160 0 : Parse::Error::Node::CHILD_ERROR);
161 : }
162 :
163 0 : if (!skip_token (RIGHT_PAREN))
164 : {
165 : // skip after somewhere?
166 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
167 : }
168 :
169 0 : return std::unique_ptr<AST::GroupedExpr> (
170 0 : new AST::GroupedExpr (std::move (expr_in_parens.value ()),
171 : std::move (inner_attrs), std::move (outer_attrs),
172 0 : locus));
173 0 : }
174 :
175 : // Parses a closure expression (closure definition).
176 : template <typename ManagedTokenSource>
177 : tl::expected<std::unique_ptr<AST::ClosureExpr>, Parse::Error::Node>
178 0 : Parser<ManagedTokenSource>::parse_closure_expr (AST::AttrVec outer_attrs)
179 : {
180 0 : location_t locus = lexer.peek_token ()->get_locus ();
181 : // detect optional "move"
182 0 : bool has_move = false;
183 0 : if (lexer.peek_token ()->get_id () == MOVE)
184 : {
185 0 : lexer.skip_token ();
186 0 : has_move = true;
187 : }
188 :
189 : // handle parameter list
190 0 : std::vector<AST::ClosureParam> params;
191 :
192 0 : const_TokenPtr t = lexer.peek_token ();
193 0 : switch (t->get_id ())
194 : {
195 0 : case OR:
196 : // skip token, no parameters
197 0 : lexer.skip_token ();
198 : break;
199 0 : case PIPE:
200 : // actually may have parameters
201 0 : lexer.skip_token ();
202 0 : t = lexer.peek_token ();
203 :
204 0 : while (t->get_id () != PIPE)
205 : {
206 0 : AST::ClosureParam param = parse_closure_param ();
207 0 : if (param.is_error ())
208 : {
209 : // TODO is this really an error?
210 0 : Error error (t->get_locus (), "could not parse closure param");
211 0 : add_error (std::move (error));
212 :
213 : break;
214 0 : }
215 0 : params.push_back (std::move (param));
216 :
217 0 : if (lexer.peek_token ()->get_id () != COMMA)
218 : {
219 0 : lexer.skip_token ();
220 : // not an error but means param list is done
221 : break;
222 : }
223 : // skip comma
224 0 : lexer.skip_token ();
225 :
226 0 : t = lexer.peek_token ();
227 : }
228 0 : params.shrink_to_fit ();
229 : break;
230 0 : default:
231 0 : add_error (Error (t->get_locus (),
232 : "unexpected token %qs in closure expression - expected "
233 : "%<|%> or %<||%>",
234 : t->get_token_description ()));
235 :
236 : // skip somewhere?
237 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
238 : }
239 :
240 : // again branch based on next token
241 0 : t = lexer.peek_token ();
242 0 : if (t->get_id () == RETURN_TYPE)
243 : {
244 : // must be return type closure with block expr
245 :
246 : // skip "return type" token
247 0 : lexer.skip_token ();
248 :
249 : // parse actual type, which is required
250 0 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
251 0 : if (type == nullptr)
252 : {
253 : // error
254 0 : Error error (t->get_locus (), "failed to parse type for closure");
255 0 : add_error (std::move (error));
256 :
257 : // skip somewhere?
258 : return tl::unexpected<Parse::Error::Node> (
259 0 : Parse::Error::Node::CHILD_ERROR);
260 0 : }
261 :
262 : // parse block expr, which is required
263 0 : auto block = parse_block_expr ();
264 0 : if (!block)
265 : {
266 : // error
267 0 : Error error (lexer.peek_token ()->get_locus (),
268 : "failed to parse block expr in closure");
269 0 : add_error (std::move (error));
270 :
271 : // skip somewhere?
272 : return tl::unexpected<Parse::Error::Node> (
273 0 : Parse::Error::Node::CHILD_ERROR);
274 0 : }
275 :
276 0 : return std::unique_ptr<AST::ClosureExprInnerTyped> (
277 0 : new AST::ClosureExprInnerTyped (std::move (type),
278 0 : std::move (block.value ()),
279 : std::move (params), locus, has_move,
280 0 : std::move (outer_attrs)));
281 0 : }
282 : else
283 : {
284 : // must be expr-only closure
285 :
286 : // parse expr, which is required
287 0 : auto expr = parse_expr ();
288 0 : if (!expr)
289 : {
290 0 : Error error (t->get_locus (),
291 : "failed to parse expression in closure");
292 0 : add_error (std::move (error));
293 :
294 : // skip somewhere?
295 : return tl::unexpected<Parse::Error::Node> (
296 0 : Parse::Error::Node::CHILD_ERROR);
297 0 : }
298 :
299 0 : return std::unique_ptr<AST::ClosureExprInner> (
300 0 : new AST::ClosureExprInner (std::move (expr.value ()),
301 : std::move (params), locus, has_move,
302 0 : std::move (outer_attrs)));
303 0 : }
304 0 : }
305 :
306 : // Parses a literal token (to literal expression).
307 : template <typename ManagedTokenSource>
308 : tl::expected<std::unique_ptr<AST::LiteralExpr>, Parse::Error::Node>
309 3665 : Parser<ManagedTokenSource>::parse_literal_expr (AST::AttrVec outer_attrs)
310 : {
311 : // TODO: change if literal representation in lexer changes
312 :
313 3665 : std::string literal_value;
314 3665 : AST::Literal::LitType type = AST::Literal::STRING;
315 :
316 : // branch based on token
317 3665 : const_TokenPtr t = lexer.peek_token ();
318 3665 : switch (t->get_id ())
319 : {
320 2 : case CHAR_LITERAL:
321 2 : type = AST::Literal::CHAR;
322 2 : literal_value = t->get_str ();
323 2 : lexer.skip_token ();
324 : break;
325 293 : case STRING_LITERAL:
326 293 : type = AST::Literal::STRING;
327 293 : literal_value = t->get_str ();
328 293 : lexer.skip_token ();
329 : break;
330 0 : case BYTE_CHAR_LITERAL:
331 0 : type = AST::Literal::BYTE;
332 0 : literal_value = t->get_str ();
333 0 : lexer.skip_token ();
334 : break;
335 1 : case BYTE_STRING_LITERAL:
336 1 : type = AST::Literal::BYTE_STRING;
337 1 : literal_value = t->get_str ();
338 1 : lexer.skip_token ();
339 : break;
340 0 : case RAW_STRING_LITERAL:
341 0 : type = AST::Literal::RAW_STRING;
342 0 : literal_value = t->get_str ();
343 0 : lexer.skip_token ();
344 : break;
345 0 : case C_STRING_LITERAL:
346 : {
347 0 : if (flag_c_style_string_literals)
348 : {
349 0 : type = AST::Literal::C_STRING;
350 0 : literal_value = t->get_str ();
351 0 : lexer.skip_token ();
352 : }
353 : else
354 : {
355 0 : add_error (
356 0 : Error (t->get_locus (),
357 : "unexpected token %qs when parsing literal expression - "
358 : "C-style string literals require "
359 : "%<-frust-c-style-string-literals%> to be enabled",
360 : t->get_token_description ()));
361 : return tl::unexpected<Parse::Error::Node> (
362 0 : Parse::Error::Node::MALFORMED);
363 : }
364 : }
365 :
366 : break;
367 3362 : case INT_LITERAL:
368 3362 : type = AST::Literal::INT;
369 3362 : literal_value = LiteralResolve::evaluate_integer_literal (t);
370 3362 : lexer.skip_token ();
371 : break;
372 1 : case FLOAT_LITERAL:
373 1 : type = AST::Literal::FLOAT;
374 1 : literal_value = LiteralResolve::evaluate_float_literal (t);
375 1 : lexer.skip_token ();
376 : break;
377 : // case BOOL_LITERAL
378 : // use true and false keywords rather than "bool literal" Rust terminology
379 0 : case TRUE_LITERAL:
380 0 : type = AST::Literal::BOOL;
381 0 : literal_value = Values::Keywords::TRUE_LITERAL;
382 0 : lexer.skip_token ();
383 : break;
384 1 : case FALSE_LITERAL:
385 1 : type = AST::Literal::BOOL;
386 1 : literal_value = Values::Keywords::FALSE_LITERAL;
387 1 : lexer.skip_token ();
388 : break;
389 5 : default:
390 : // error - cannot be a literal expr
391 5 : add_error (Error (t->get_locus (),
392 : "unexpected token %qs when parsing literal expression",
393 : t->get_token_description ()));
394 :
395 : // skip?
396 5 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
397 : }
398 :
399 3660 : auto type_hint
400 3660 : = (t->get_id () == INT_LITERAL || t->get_id () == FLOAT_LITERAL)
401 10386 : ? LiteralResolve::resolve_literal_suffix (t)
402 297 : : t->get_type_hint ();
403 :
404 : // create literal based on stuff in switch
405 3660 : return std::unique_ptr<AST::LiteralExpr> (
406 7320 : new AST::LiteralExpr (std::move (literal_value), std::move (type),
407 3660 : type_hint, std::move (outer_attrs), t->get_locus ()));
408 3665 : }
409 :
410 : template <typename ManagedTokenSource>
411 : tl::expected<std::unique_ptr<AST::BoxExpr>, Parse::Error::Node>
412 5 : Parser<ManagedTokenSource>::parse_box_expr (AST::AttrVec outer_attrs,
413 : location_t pratt_parsed_loc)
414 : {
415 5 : location_t locus = pratt_parsed_loc;
416 5 : if (locus == UNKNOWN_LOCATION)
417 : {
418 0 : locus = lexer.peek_token ()->get_locus ();
419 0 : skip_token (BOX);
420 : }
421 :
422 5 : ParseRestrictions restrictions;
423 : restrictions.expr_can_be_null = false;
424 :
425 5 : auto expr = parse_expr (AST::AttrVec (), restrictions);
426 5 : if (!expr)
427 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
428 :
429 5 : return std::unique_ptr<AST::BoxExpr> (
430 5 : new AST::BoxExpr (std::move (expr.value ()), std::move (outer_attrs),
431 5 : locus));
432 5 : }
433 :
434 : // Parses a return expression (including any expression to return).
435 : template <typename ManagedTokenSource>
436 : tl::expected<std::unique_ptr<AST::ReturnExpr>, Parse::Error::Node>
437 549 : Parser<ManagedTokenSource>::parse_return_expr (AST::AttrVec outer_attrs,
438 : location_t pratt_parsed_loc)
439 : {
440 549 : location_t locus = pratt_parsed_loc;
441 549 : if (locus == UNKNOWN_LOCATION)
442 : {
443 0 : locus = lexer.peek_token ()->get_locus ();
444 0 : skip_token (RETURN_KW);
445 : }
446 :
447 : // parse expression to return, if it exists
448 549 : ParseRestrictions restrictions;
449 549 : restrictions.expr_can_be_null = true;
450 549 : auto returned_expr = parse_expr (AST::AttrVec (), restrictions);
451 549 : tl::optional<std::unique_ptr<AST::Expr>> expr = tl::nullopt;
452 549 : if (returned_expr)
453 516 : expr = std::move (returned_expr.value ());
454 :
455 549 : return std::make_unique<AST::ReturnExpr> (std::move (expr),
456 549 : std::move (outer_attrs), locus);
457 549 : }
458 :
459 : // Parses a try expression.
460 : template <typename ManagedTokenSource>
461 : tl::expected<std::unique_ptr<AST::TryExpr>, Parse::Error::Node>
462 1 : Parser<ManagedTokenSource>::parse_try_expr (AST::AttrVec outer_attrs,
463 : location_t pratt_parsed_loc)
464 : {
465 1 : location_t locus = pratt_parsed_loc;
466 1 : if (locus == UNKNOWN_LOCATION)
467 : {
468 0 : locus = lexer.peek_token ()->get_locus ();
469 0 : skip_token (TRY);
470 : }
471 :
472 1 : auto block_expr = parse_block_expr ();
473 :
474 1 : if (!block_expr)
475 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
476 :
477 1 : return std::unique_ptr<AST::TryExpr> (
478 1 : new AST::TryExpr (std::move (block_expr.value ()), std::move (outer_attrs),
479 1 : locus));
480 1 : }
481 :
482 : /* Parses a break expression (including any label to break to AND any return
483 : * expression). */
484 : template <typename ManagedTokenSource>
485 : tl::expected<std::unique_ptr<AST::BreakExpr>, Parse::Error::Node>
486 83 : Parser<ManagedTokenSource>::parse_break_expr (AST::AttrVec outer_attrs,
487 : location_t pratt_parsed_loc)
488 : {
489 83 : location_t locus = pratt_parsed_loc;
490 83 : if (locus == UNKNOWN_LOCATION)
491 : {
492 0 : locus = lexer.peek_token ()->get_locus ();
493 0 : skip_token (BREAK);
494 : }
495 :
496 83 : auto parsed_label = parse_lifetime (false);
497 83 : auto label = (parsed_label)
498 83 : ? tl::optional<AST::Lifetime> (parsed_label.value ())
499 : : tl::nullopt;
500 :
501 : // parse break return expression if it exists
502 83 : ParseRestrictions restrictions;
503 83 : restrictions.expr_can_be_null = true;
504 83 : auto return_expr = parse_expr (AST::AttrVec (), restrictions);
505 :
506 83 : if (return_expr)
507 26 : return std::unique_ptr<AST::BreakExpr> (
508 78 : new AST::BreakExpr (std::move (label), std::move (return_expr.value ()),
509 26 : std::move (outer_attrs), locus));
510 57 : else if (return_expr.error () == Parse::Error::Expr::NULL_EXPR)
511 57 : return std::unique_ptr<AST::BreakExpr> (
512 114 : new AST::BreakExpr (std::move (label), tl::nullopt,
513 57 : std::move (outer_attrs), locus));
514 : else
515 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
516 110 : }
517 :
518 : // Parses a continue expression (including any label to continue from).
519 : template <typename ManagedTokenSource>
520 : std::unique_ptr<AST::ContinueExpr>
521 17 : Parser<ManagedTokenSource>::parse_continue_expr (AST::AttrVec outer_attrs,
522 : location_t pratt_parsed_loc)
523 : {
524 17 : location_t locus = pratt_parsed_loc;
525 17 : if (locus == UNKNOWN_LOCATION)
526 : {
527 0 : locus = lexer.peek_token ()->get_locus ();
528 0 : skip_token (CONTINUE);
529 : }
530 :
531 17 : auto parsed_label = parse_lifetime (false);
532 17 : auto label = (parsed_label)
533 17 : ? tl::optional<AST::Lifetime> (parsed_label.value ())
534 : : tl::nullopt;
535 :
536 : return std::make_unique<AST::ContinueExpr> (std::move (label),
537 17 : std::move (outer_attrs), locus);
538 17 : }
539 :
540 : /* Parses an if expression of any kind, including with else, else if, else if
541 : * let, and neither. Note that any outer attributes will be ignored because if
542 : * expressions don't support them. */
543 : template <typename ManagedTokenSource>
544 : tl::expected<std::unique_ptr<AST::IfExpr>, Parse::Error::Node>
545 2509 : Parser<ManagedTokenSource>::parse_if_expr (AST::AttrVec outer_attrs,
546 : location_t pratt_parsed_loc)
547 : {
548 : // TODO: make having outer attributes an error?
549 2509 : location_t locus = pratt_parsed_loc;
550 2509 : if (locus == UNKNOWN_LOCATION)
551 : {
552 363 : locus = lexer.peek_token ()->get_locus ();
553 363 : if (!skip_token (IF))
554 : {
555 0 : skip_after_end_block ();
556 : return tl::unexpected<Parse::Error::Node> (
557 0 : Parse::Error::Node::MALFORMED);
558 : }
559 : }
560 :
561 : // detect accidental if let
562 5018 : if (lexer.peek_token ()->get_id () == LET)
563 : {
564 0 : Error error (lexer.peek_token ()->get_locus (),
565 : "if let expression probably exists, but is being parsed "
566 : "as an if expression. This may be a parser error");
567 0 : add_error (std::move (error));
568 :
569 : // skip somewhere?
570 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
571 0 : }
572 :
573 : /* parse required condition expr - HACK to prevent struct expr from being
574 : * parsed */
575 2509 : ParseRestrictions no_struct_expr;
576 2509 : no_struct_expr.can_be_struct_expr = false;
577 2509 : auto condition = parse_expr ({}, no_struct_expr);
578 2509 : if (!condition)
579 : {
580 0 : Error error (lexer.peek_token ()->get_locus (),
581 : "failed to parse condition expression in if expression");
582 0 : add_error (std::move (error));
583 :
584 : // skip somewhere?
585 : return tl::unexpected<Parse::Error::Node> (
586 0 : Parse::Error::Node::CHILD_ERROR);
587 0 : }
588 :
589 : // parse required block expr
590 2509 : auto if_body = parse_block_expr ();
591 2509 : if (!if_body)
592 1 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
593 :
594 : // branch to parse end or else (and then else, else if, or else if let)
595 5016 : if (lexer.peek_token ()->get_id () != ELSE)
596 : {
597 : // single selection - end of if expression
598 1239 : return std::unique_ptr<AST::IfExpr> (
599 1239 : new AST::IfExpr (std::move (condition.value ()),
600 1239 : std::move (if_body.value ()), std::move (outer_attrs),
601 1239 : locus));
602 : }
603 : else
604 : {
605 : // double or multiple selection - branch on end, else if, or else if let
606 :
607 : // skip "else"
608 1269 : lexer.skip_token ();
609 :
610 : // branch on whether next token is '{' or 'if'
611 1269 : const_TokenPtr t = lexer.peek_token ();
612 1269 : switch (t->get_id ())
613 : {
614 906 : case LEFT_CURLY:
615 : {
616 : // double selection - else
617 : // parse else block expr (required)
618 906 : auto else_body = parse_block_expr ();
619 906 : if (!else_body)
620 : {
621 0 : Error error (lexer.peek_token ()->get_locus (),
622 : "failed to parse else body block expression in "
623 : "if expression");
624 0 : add_error (std::move (error));
625 :
626 : // skip somewhere?
627 : return tl::unexpected<Parse::Error::Node> (
628 0 : Parse::Error::Node::CHILD_ERROR);
629 0 : }
630 :
631 906 : return std::unique_ptr<AST::IfExprConseqElse> (
632 1812 : new AST::IfExprConseqElse (std::move (condition.value ()),
633 906 : std::move (if_body.value ()),
634 906 : std::move (else_body.value ()),
635 906 : std::move (outer_attrs), locus));
636 906 : }
637 363 : case IF:
638 : {
639 : // multiple selection - else if or else if let
640 : // branch on whether next token is 'let' or not
641 726 : if (lexer.peek_token (1)->get_id () == LET)
642 : {
643 : // parse if let expr (required)
644 1 : auto if_let_expr = parse_if_let_expr ();
645 1 : if (!if_let_expr)
646 : {
647 0 : Error error (lexer.peek_token ()->get_locus (),
648 : "failed to parse (else) if let expression "
649 : "after if expression");
650 0 : add_error (std::move (error));
651 :
652 : // skip somewhere?
653 : return tl::unexpected<Parse::Error::Node> (
654 0 : Parse::Error::Node::CHILD_ERROR);
655 0 : }
656 :
657 1 : return std::unique_ptr<AST::IfExprConseqElse> (
658 2 : new AST::IfExprConseqElse (std::move (condition.value ()),
659 1 : std::move (if_body.value ()),
660 1 : std::move (if_let_expr.value ()),
661 1 : std::move (outer_attrs), locus));
662 1 : }
663 : else
664 : {
665 : // parse if expr (required)
666 362 : auto if_expr = parse_if_expr ();
667 362 : if (!if_expr)
668 : {
669 0 : Error error (lexer.peek_token ()->get_locus (),
670 : "failed to parse (else) if expression after "
671 : "if expression");
672 0 : add_error (std::move (error));
673 :
674 : // skip somewhere?
675 : return tl::unexpected<Parse::Error::Node> (
676 0 : Parse::Error::Node::CHILD_ERROR);
677 0 : }
678 :
679 362 : return std::unique_ptr<AST::IfExprConseqElse> (
680 724 : new AST::IfExprConseqElse (std::move (condition.value ()),
681 362 : std::move (if_body.value ()),
682 362 : std::move (if_expr.value ()),
683 362 : std::move (outer_attrs), locus));
684 362 : }
685 : }
686 0 : default:
687 : // error - invalid token
688 0 : add_error (Error (t->get_locus (),
689 : "unexpected token %qs after else in if expression",
690 : t->get_token_description ()));
691 :
692 : // skip somewhere?
693 : return tl::unexpected<Parse::Error::Node> (
694 0 : Parse::Error::Node::MALFORMED);
695 : }
696 1269 : }
697 5018 : }
698 :
699 : /* Parses an if let expression of any kind, including with else, else if, else
700 : * if let, and none. Note that any outer attributes will be ignored as if let
701 : * expressions don't support them. */
702 : template <typename ManagedTokenSource>
703 : tl::expected<std::unique_ptr<AST::IfLetExpr>, Parse::Error::Node>
704 31 : Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs,
705 : location_t pratt_parsed_loc)
706 : {
707 : // TODO: make having outer attributes an error?
708 31 : location_t locus = pratt_parsed_loc;
709 31 : if (locus == UNKNOWN_LOCATION)
710 : {
711 1 : locus = lexer.peek_token ()->get_locus ();
712 1 : if (!skip_token (IF))
713 : {
714 0 : skip_after_end_block ();
715 : return tl::unexpected<Parse::Error::Node> (
716 0 : Parse::Error::Node::MALFORMED);
717 : }
718 : }
719 :
720 : // detect accidental if expr parsed as if let expr
721 62 : if (lexer.peek_token ()->get_id () != LET)
722 : {
723 0 : Error error (lexer.peek_token ()->get_locus (),
724 : "if expression probably exists, but is being parsed as an "
725 : "if let expression. This may be a parser error");
726 0 : add_error (std::move (error));
727 :
728 : // skip somewhere?
729 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
730 0 : }
731 31 : lexer.skip_token ();
732 :
733 : // parse match arm patterns (which are required)
734 31 : std::unique_ptr<AST::Pattern> match_arm_pattern
735 : = parse_match_arm_pattern (EQUAL);
736 31 : if (match_arm_pattern == nullptr)
737 : {
738 0 : Error error (
739 0 : lexer.peek_token ()->get_locus (),
740 : "failed to parse any match arm patterns in if let expression");
741 0 : add_error (std::move (error));
742 :
743 : // skip somewhere?
744 : return tl::unexpected<Parse::Error::Node> (
745 0 : Parse::Error::Node::CHILD_ERROR);
746 0 : }
747 :
748 31 : if (!skip_token (EQUAL))
749 : {
750 : // skip somewhere?
751 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
752 : }
753 :
754 : // parse expression (required) - HACK to prevent struct expr being parsed
755 31 : ParseRestrictions no_struct_expr;
756 31 : no_struct_expr.can_be_struct_expr = false;
757 31 : auto scrutinee_expr = parse_expr ({}, no_struct_expr);
758 31 : if (!scrutinee_expr)
759 : {
760 0 : Error error (lexer.peek_token ()->get_locus (),
761 : "failed to parse scrutinee expression in if let expression");
762 0 : add_error (std::move (error));
763 :
764 : // skip somewhere?
765 : return tl::unexpected<Parse::Error::Node> (
766 0 : Parse::Error::Node::CHILD_ERROR);
767 0 : }
768 : /* TODO: check for expression not being a struct expression or lazy boolean
769 : * expression here? or actually probably in semantic analysis. */
770 :
771 : // parse block expression (required)
772 31 : auto if_let_body = parse_block_expr ();
773 31 : if (!if_let_body)
774 : {
775 0 : Error error (
776 0 : lexer.peek_token ()->get_locus (),
777 : "failed to parse if let body block expression in if let expression");
778 0 : add_error (std::move (error));
779 :
780 : // skip somewhere?
781 : return tl::unexpected<Parse::Error::Node> (
782 0 : Parse::Error::Node::CHILD_ERROR);
783 0 : }
784 :
785 : // branch to parse end or else (and then else, else if, or else if let)
786 62 : if (lexer.peek_token ()->get_id () != ELSE)
787 : {
788 : // single selection - end of if let expression
789 38 : return std::unique_ptr<AST::IfLetExpr> (new AST::IfLetExpr (
790 19 : std::move (match_arm_pattern), std::move (scrutinee_expr.value ()),
791 38 : std::move (if_let_body.value ()), std::move (outer_attrs), locus));
792 : }
793 : else
794 : {
795 : // double or multiple selection - branch on end, else if, or else if let
796 :
797 : // skip "else"
798 12 : lexer.skip_token ();
799 :
800 : // branch on whether next token is '{' or 'if'
801 12 : const_TokenPtr t = lexer.peek_token ();
802 12 : switch (t->get_id ())
803 : {
804 11 : case LEFT_CURLY:
805 : {
806 : // double selection - else
807 : // parse else block expr (required)
808 11 : auto else_body = parse_block_expr ();
809 11 : if (!else_body)
810 : {
811 0 : Error error (lexer.peek_token ()->get_locus (),
812 : "failed to parse else body block expression in "
813 : "if let expression");
814 0 : add_error (std::move (error));
815 :
816 : // skip somewhere?
817 : return tl::unexpected<Parse::Error::Node> (
818 0 : Parse::Error::Node::CHILD_ERROR);
819 0 : }
820 :
821 11 : return std::unique_ptr<AST::IfLetExprConseqElse> (
822 22 : new AST::IfLetExprConseqElse (std::move (match_arm_pattern),
823 11 : std::move (scrutinee_expr.value ()),
824 11 : std::move (if_let_body.value ()),
825 11 : std::move (else_body.value ()),
826 11 : std::move (outer_attrs), locus));
827 11 : }
828 1 : case IF:
829 : {
830 : // multiple selection - else if or else if let
831 : // branch on whether next token is 'let' or not
832 2 : if (lexer.peek_token (1)->get_id () == LET)
833 : {
834 : // parse if let expr (required)
835 0 : auto if_let_expr = parse_if_let_expr ();
836 0 : if (!if_let_expr)
837 : {
838 0 : Error error (lexer.peek_token ()->get_locus (),
839 : "failed to parse (else) if let expression "
840 : "after if let expression");
841 0 : add_error (std::move (error));
842 :
843 : // skip somewhere?
844 : return tl::unexpected<Parse::Error::Node> (
845 0 : Parse::Error::Node::CHILD_ERROR);
846 0 : }
847 :
848 0 : return std::unique_ptr<AST::IfLetExprConseqElse> (
849 0 : new AST::IfLetExprConseqElse (
850 : std::move (match_arm_pattern),
851 0 : std::move (scrutinee_expr.value ()),
852 0 : std::move (if_let_body.value ()),
853 0 : std::move (if_let_expr.value ()), std::move (outer_attrs),
854 0 : locus));
855 0 : }
856 : else
857 : {
858 : // parse if expr (required)
859 1 : auto if_expr = parse_if_expr ();
860 1 : if (!if_expr)
861 : {
862 0 : Error error (lexer.peek_token ()->get_locus (),
863 : "failed to parse (else) if expression after "
864 : "if let expression");
865 0 : add_error (std::move (error));
866 :
867 : // skip somewhere?
868 : return tl::unexpected<Parse::Error::Node> (
869 0 : Parse::Error::Node::CHILD_ERROR);
870 0 : }
871 :
872 1 : return std::unique_ptr<AST::IfLetExprConseqElse> (
873 2 : new AST::IfLetExprConseqElse (
874 : std::move (match_arm_pattern),
875 1 : std::move (scrutinee_expr.value ()),
876 1 : std::move (if_let_body.value ()),
877 1 : std::move (if_expr.value ()), std::move (outer_attrs),
878 1 : locus));
879 1 : }
880 : }
881 0 : default:
882 : // error - invalid token
883 0 : add_error (
884 0 : Error (t->get_locus (),
885 : "unexpected token %qs after else in if let expression",
886 : t->get_token_description ()));
887 :
888 : // skip somewhere?
889 : return tl::unexpected<Parse::Error::Node> (
890 0 : Parse::Error::Node::MALFORMED);
891 : }
892 12 : }
893 62 : }
894 :
895 : /* TODO: possibly decide on different method of handling label (i.e. not
896 : * parameter) */
897 :
898 : /* Parses a "loop" infinite loop expression. Label is not parsed and should be
899 : * parsed via parse_labelled_loop_expr, which would call this. */
900 : template <typename ManagedTokenSource>
901 : tl::expected<std::unique_ptr<AST::LoopExpr>, Parse::Error::Node>
902 118 : Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs,
903 : tl::optional<AST::LoopLabel> label,
904 : location_t pratt_parsed_loc)
905 : {
906 118 : location_t locus = pratt_parsed_loc;
907 118 : if (locus == UNKNOWN_LOCATION)
908 : {
909 39 : if (label)
910 39 : locus = label->get_locus ();
911 : else
912 0 : locus = lexer.peek_token ()->get_locus ();
913 :
914 39 : if (!skip_token (LOOP))
915 : {
916 0 : skip_after_end_block ();
917 : return tl::unexpected<Parse::Error::Node> (
918 0 : Parse::Error::Node::MALFORMED);
919 : }
920 : }
921 : else
922 : {
923 79 : if (label)
924 0 : locus = label->get_locus ();
925 : }
926 :
927 : // parse loop body, which is required
928 118 : auto loop_body = parse_block_expr ();
929 118 : if (!loop_body)
930 1 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
931 :
932 117 : return std::unique_ptr<AST::LoopExpr> (
933 156 : new AST::LoopExpr (std::move (loop_body.value ()), locus, std::move (label),
934 117 : std::move (outer_attrs)));
935 118 : }
936 :
937 : /* Parses a "while" loop expression. Label is not parsed and should be parsed
938 : * via parse_labelled_loop_expr, which would call this. */
939 : template <typename ManagedTokenSource>
940 : tl::expected<std::unique_ptr<AST::WhileLoopExpr>, Parse::Error::Node>
941 79 : Parser<ManagedTokenSource>::parse_while_loop_expr (
942 : AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label,
943 : location_t pratt_parsed_loc)
944 : {
945 79 : location_t locus = pratt_parsed_loc;
946 79 : if (locus == UNKNOWN_LOCATION)
947 : {
948 2 : if (label)
949 2 : locus = label->get_locus ();
950 : else
951 0 : locus = lexer.peek_token ()->get_locus ();
952 :
953 2 : if (!skip_token (WHILE))
954 : {
955 0 : skip_after_end_block ();
956 : return tl::unexpected<Parse::Error::Node> (
957 0 : Parse::Error::Node::MALFORMED);
958 : }
959 : }
960 : else
961 : {
962 77 : if (label)
963 0 : locus = label->get_locus ();
964 : }
965 :
966 : // ensure it isn't a while let loop
967 158 : if (lexer.peek_token ()->get_id () == LET)
968 : {
969 0 : Error error (lexer.peek_token ()->get_locus (),
970 : "appears to be while let loop but is being parsed by "
971 : "while loop - this may be a compiler issue");
972 0 : add_error (std::move (error));
973 :
974 : // skip somewhere?
975 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
976 0 : }
977 :
978 : // parse loop predicate (required) with HACK to prevent struct expr parsing
979 79 : ParseRestrictions no_struct_expr;
980 79 : no_struct_expr.can_be_struct_expr = false;
981 79 : auto predicate = parse_expr ({}, no_struct_expr);
982 79 : if (!predicate)
983 : {
984 0 : Error error (lexer.peek_token ()->get_locus (),
985 : "failed to parse predicate expression in while loop");
986 0 : add_error (std::move (error));
987 :
988 : // skip somewhere?
989 : return tl::unexpected<Parse::Error::Node> (
990 0 : Parse::Error::Node::CHILD_ERROR);
991 0 : }
992 : /* TODO: check that it isn't struct expression here? actually, probably in
993 : * semantic analysis */
994 :
995 : // parse loop body (required)
996 79 : auto body = parse_block_expr ();
997 79 : if (!body)
998 : {
999 0 : Error error (lexer.peek_token ()->get_locus (),
1000 : "failed to parse loop body block expression in while loop");
1001 0 : add_error (std::move (error));
1002 :
1003 : // skip somewhere
1004 : return tl::unexpected<Parse::Error::Node> (
1005 0 : Parse::Error::Node::CHILD_ERROR);
1006 0 : }
1007 :
1008 79 : return std::unique_ptr<AST::WhileLoopExpr> (
1009 160 : new AST::WhileLoopExpr (std::move (predicate.value ()),
1010 79 : std::move (body.value ()), locus, std::move (label),
1011 79 : std::move (outer_attrs)));
1012 158 : }
1013 :
1014 : /* Parses a "while let" loop expression. Label is not parsed and should be
1015 : * parsed via parse_labelled_loop_expr, which would call this. */
1016 : template <typename ManagedTokenSource>
1017 : tl::expected<std::unique_ptr<AST::WhileLetLoopExpr>, Parse::Error::Node>
1018 5 : Parser<ManagedTokenSource>::parse_while_let_loop_expr (
1019 : AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label)
1020 : {
1021 5 : location_t locus = UNKNOWN_LOCATION;
1022 5 : if (label)
1023 1 : locus = label->get_locus ();
1024 : else
1025 8 : locus = lexer.peek_token ()->get_locus ();
1026 5 : maybe_skip_token (WHILE);
1027 :
1028 : /* check for possible accidental recognition of a while loop as a while let
1029 : * loop */
1030 10 : if (lexer.peek_token ()->get_id () != LET)
1031 : {
1032 0 : Error error (lexer.peek_token ()->get_locus (),
1033 : "appears to be a while loop but is being parsed by "
1034 : "while let loop - this may be a compiler issue");
1035 0 : add_error (std::move (error));
1036 :
1037 : // skip somewhere
1038 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
1039 0 : }
1040 : // as this token is definitely let now, save the computation of comparison
1041 5 : lexer.skip_token ();
1042 :
1043 : // parse predicate patterns
1044 5 : std::unique_ptr<AST::Pattern> predicate_pattern
1045 : = parse_match_arm_pattern (EQUAL);
1046 : // ensure that there is at least 1 pattern
1047 5 : if (predicate_pattern == nullptr)
1048 : {
1049 1 : Error error (lexer.peek_token ()->get_locus (),
1050 : "should be at least 1 pattern");
1051 1 : add_error (std::move (error));
1052 1 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
1053 1 : }
1054 :
1055 4 : if (!skip_token (EQUAL))
1056 : {
1057 : // skip somewhere?
1058 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
1059 : }
1060 :
1061 : /* parse predicate expression, which is required (and HACK to prevent struct
1062 : * expr) */
1063 4 : ParseRestrictions no_struct_expr;
1064 4 : no_struct_expr.can_be_struct_expr = false;
1065 4 : auto predicate_expr = parse_expr ({}, no_struct_expr);
1066 4 : if (!predicate_expr)
1067 : {
1068 0 : Error error (lexer.peek_token ()->get_locus (),
1069 : "failed to parse predicate expression in while let loop");
1070 0 : add_error (std::move (error));
1071 :
1072 : // skip somewhere?
1073 : return tl::unexpected<Parse::Error::Node> (
1074 0 : Parse::Error::Node::CHILD_ERROR);
1075 0 : }
1076 : /* TODO: ensure that struct expression is not parsed? Actually, probably in
1077 : * semantic analysis. */
1078 :
1079 : // parse loop body, which is required
1080 4 : auto body = parse_block_expr ();
1081 4 : if (!body)
1082 : {
1083 0 : Error error (lexer.peek_token ()->get_locus (),
1084 : "failed to parse block expr (loop body) of while let loop");
1085 0 : add_error (std::move (error));
1086 :
1087 : // skip somewhere?
1088 : return tl::unexpected<Parse::Error::Node> (
1089 0 : Parse::Error::Node::CHILD_ERROR);
1090 0 : }
1091 :
1092 4 : return std::unique_ptr<AST::WhileLetLoopExpr> (
1093 9 : new AST::WhileLetLoopExpr (std::move (predicate_pattern),
1094 4 : std::move (predicate_expr.value ()),
1095 4 : std::move (body.value ()), locus,
1096 4 : std::move (label), std::move (outer_attrs)));
1097 9 : }
1098 :
1099 : /* Parses a "for" iterative loop. Label is not parsed and should be parsed via
1100 : * parse_labelled_loop_expr, which would call this. */
1101 : template <typename ManagedTokenSource>
1102 : tl::expected<std::unique_ptr<AST::ForLoopExpr>, Parse::Error::Node>
1103 20 : Parser<ManagedTokenSource>::parse_for_loop_expr (
1104 : AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label)
1105 : {
1106 20 : location_t locus = UNKNOWN_LOCATION;
1107 20 : if (label)
1108 0 : locus = label->get_locus ();
1109 : else
1110 40 : locus = lexer.peek_token ()->get_locus ();
1111 20 : maybe_skip_token (FOR);
1112 :
1113 : // parse pattern, which is required
1114 20 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
1115 20 : if (!pattern)
1116 : {
1117 0 : Error error (lexer.peek_token ()->get_locus (),
1118 : "failed to parse iterator pattern in for loop");
1119 0 : add_error (std::move (error));
1120 :
1121 : // skip somewhere?
1122 : return tl::unexpected<Parse::Error::Node> (
1123 0 : Parse::Error::Node::CHILD_ERROR);
1124 0 : }
1125 :
1126 20 : if (!skip_token (IN))
1127 : {
1128 : // skip somewhere?
1129 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
1130 : }
1131 :
1132 : /* parse iterator expression, which is required - also HACK to prevent
1133 : * struct expr */
1134 20 : ParseRestrictions no_struct_expr;
1135 20 : no_struct_expr.can_be_struct_expr = false;
1136 20 : auto expr = parse_expr ({}, no_struct_expr);
1137 20 : if (!expr)
1138 : {
1139 0 : Error error (lexer.peek_token ()->get_locus (),
1140 : "failed to parse iterator expression in for loop");
1141 0 : add_error (std::move (error));
1142 :
1143 : // skip somewhere?
1144 : return tl::unexpected<Parse::Error::Node> (
1145 0 : Parse::Error::Node::CHILD_ERROR);
1146 0 : }
1147 : // TODO: check to ensure this isn't struct expr? Or in semantic analysis.
1148 :
1149 : // parse loop body, which is required
1150 20 : auto body = parse_block_expr ();
1151 20 : if (!body)
1152 : {
1153 0 : Error error (lexer.peek_token ()->get_locus (),
1154 : "failed to parse loop body block expression in for loop");
1155 0 : add_error (std::move (error));
1156 :
1157 : // skip somewhere?
1158 : return tl::unexpected<Parse::Error::Node> (
1159 0 : Parse::Error::Node::CHILD_ERROR);
1160 0 : }
1161 20 : return std::unique_ptr<AST::ForLoopExpr> (
1162 40 : new AST::ForLoopExpr (std::move (pattern), std::move (expr.value ()),
1163 20 : std::move (body.value ()), locus, std::move (label),
1164 20 : std::move (outer_attrs)));
1165 40 : }
1166 :
1167 : // Parses a loop expression with label (any kind of loop - disambiguates).
1168 : template <typename ManagedTokenSource>
1169 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Node>
1170 45 : Parser<ManagedTokenSource>::parse_labelled_loop_expr (const_TokenPtr tok,
1171 : AST::AttrVec outer_attrs)
1172 : {
1173 : // parse loop label (required)
1174 90 : auto parsed_label = parse_loop_label (tok);
1175 45 : if (!parsed_label)
1176 : {
1177 : /* TODO: decide whether it should not work if there is no label, or parse
1178 : * it with no label at the moment, I will make it not work with no label
1179 : * because that's the implication. */
1180 :
1181 0 : if (parsed_label.error ().kind
1182 : == Parse::Error::LoopLabel::Kind::NOT_LOOP_LABEL)
1183 : {
1184 0 : Error error (tok->get_locus (),
1185 : "expected lifetime in labelled loop expr (to parse loop "
1186 : "label) - found %qs",
1187 : tok->get_token_description ());
1188 0 : add_error (std::move (error));
1189 : return tl::unexpected<Parse::Error::Node> (
1190 0 : Parse::Error::Node::CHILD_ERROR);
1191 0 : }
1192 :
1193 : else
1194 : {
1195 0 : Error error (lexer.peek_token ()->get_locus (),
1196 : "failed to parse loop label in labelled loop expr");
1197 0 : add_error (std::move (error));
1198 :
1199 : // skip?
1200 : return tl::unexpected<Parse::Error::Node> (
1201 0 : Parse::Error::Node::CHILD_ERROR);
1202 0 : }
1203 : }
1204 :
1205 45 : auto label = parsed_label
1206 : ? tl::optional<AST::LoopLabel> (parsed_label.value ())
1207 : : tl::nullopt;
1208 :
1209 : // branch on next token
1210 45 : const_TokenPtr t = lexer.peek_token ();
1211 45 : switch (t->get_id ())
1212 : {
1213 39 : case LOOP:
1214 117 : return parse_loop_expr (std::move (outer_attrs), std::move (label));
1215 0 : case FOR:
1216 0 : return parse_for_loop_expr (std::move (outer_attrs), std::move (label));
1217 3 : case WHILE:
1218 : // further disambiguate into while vs while let
1219 6 : if (lexer.peek_token (1)->get_id () == LET)
1220 3 : return parse_while_let_loop_expr (std::move (outer_attrs),
1221 1 : std::move (label));
1222 : else
1223 6 : return parse_while_loop_expr (std::move (outer_attrs),
1224 2 : std::move (label));
1225 3 : case LEFT_CURLY:
1226 9 : return parse_block_expr (std::move (outer_attrs), std::move (label));
1227 0 : default:
1228 : // error
1229 0 : add_error (Error (t->get_locus (),
1230 : "unexpected token %qs when parsing labelled loop",
1231 : t->get_token_description ()));
1232 :
1233 : // skip?
1234 : return tl::unexpected<Parse::Error::Node> (
1235 0 : Parse::Error::Node::CHILD_ERROR);
1236 : }
1237 90 : }
1238 :
1239 : // Parses a match expression.
1240 : template <typename ManagedTokenSource>
1241 : tl::expected<std::unique_ptr<AST::MatchExpr>, Parse::Error::Node>
1242 920 : Parser<ManagedTokenSource>::parse_match_expr (AST::AttrVec outer_attrs,
1243 : location_t pratt_parsed_loc)
1244 : {
1245 920 : location_t locus = pratt_parsed_loc;
1246 920 : if (locus == UNKNOWN_LOCATION)
1247 : {
1248 0 : locus = lexer.peek_token ()->get_locus ();
1249 0 : skip_token (MATCH_KW);
1250 : }
1251 :
1252 : /* parse scrutinee expression, which is required (and HACK to prevent struct
1253 : * expr) */
1254 920 : ParseRestrictions no_struct_expr;
1255 920 : no_struct_expr.can_be_struct_expr = false;
1256 920 : auto scrutinee = parse_expr ({}, no_struct_expr);
1257 920 : if (!scrutinee)
1258 : {
1259 1 : Error error (lexer.peek_token ()->get_locus (),
1260 : "failed to parse scrutinee expression in match expression");
1261 1 : add_error (std::move (error));
1262 :
1263 : // skip somewhere?
1264 : return tl::unexpected<Parse::Error::Node> (
1265 1 : Parse::Error::Node::CHILD_ERROR);
1266 1 : }
1267 : /* TODO: check for scrutinee expr not being struct expr? or do so in
1268 : * semantic analysis */
1269 :
1270 919 : if (!skip_token (LEFT_CURLY))
1271 : {
1272 : // skip somewhere?
1273 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
1274 : }
1275 :
1276 : // parse inner attributes (if they exist)
1277 919 : AST::AttrVec inner_attrs = parse_inner_attributes ();
1278 :
1279 : // parse match arms (if they exist)
1280 : // std::vector<std::unique_ptr<AST::MatchCase> > match_arms;
1281 919 : std::vector<AST::MatchCase> match_arms;
1282 :
1283 : // parse match cases
1284 8278 : while (lexer.peek_token ()->get_id () != RIGHT_CURLY)
1285 : {
1286 : // parse match arm itself, which is required
1287 2162 : AST::MatchArm arm = parse_match_arm ();
1288 2162 : if (arm.is_error ())
1289 : {
1290 : // TODO is this worth throwing everything away?
1291 0 : Error error (lexer.peek_token ()->get_locus (),
1292 : "failed to parse match arm in match arms");
1293 0 : add_error (std::move (error));
1294 :
1295 : return tl::unexpected<Parse::Error::Node> (
1296 0 : Parse::Error::Node::CHILD_ERROR);
1297 0 : }
1298 :
1299 2162 : if (!skip_token (MATCH_ARROW))
1300 : {
1301 : // skip after somewhere?
1302 : // TODO is returning here a good idea? or is break better?
1303 : return tl::unexpected<Parse::Error::Node> (
1304 0 : Parse::Error::Node::MALFORMED);
1305 : }
1306 :
1307 2162 : ParseRestrictions restrictions;
1308 2162 : restrictions.expr_can_be_stmt = true;
1309 :
1310 2162 : auto expr = parse_expr ({}, restrictions);
1311 :
1312 2162 : if (!expr)
1313 : {
1314 : /* We don't need to throw an error as it already reported by
1315 : * parse_expr
1316 : */
1317 : return tl::unexpected<Parse::Error::Node> (
1318 2 : Parse::Error::Node::CHILD_ERROR);
1319 : }
1320 :
1321 2160 : bool is_expr_without_block = expr.value ()->is_expr_without_block ();
1322 :
1323 2160 : match_arms.push_back (
1324 4320 : AST::MatchCase (std::move (arm), std::move (expr.value ())));
1325 :
1326 : // handle comma presence
1327 4320 : if (lexer.peek_token ()->get_id () != COMMA)
1328 : {
1329 569 : if (!is_expr_without_block)
1330 : {
1331 : // allowed even if not final case
1332 : continue;
1333 : }
1334 21 : else if (is_expr_without_block
1335 42 : && lexer.peek_token ()->get_id () != RIGHT_CURLY)
1336 : {
1337 : // not allowed if not final case
1338 1 : Error error (lexer.peek_token ()->get_locus (),
1339 : "exprwithoutblock requires comma after match case "
1340 : "expression in match arm (if not final case)");
1341 1 : add_error (std::move (error));
1342 :
1343 : return tl::unexpected<Parse::Error::Node> (
1344 1 : Parse::Error::Node::MALFORMED);
1345 1 : }
1346 : else
1347 : {
1348 : // otherwise, must be final case, so fine
1349 : break;
1350 : }
1351 : }
1352 1591 : lexer.skip_token ();
1353 : }
1354 :
1355 916 : if (!skip_token (RIGHT_CURLY))
1356 : {
1357 : // skip somewhere?
1358 0 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
1359 : }
1360 :
1361 916 : match_arms.shrink_to_fit ();
1362 :
1363 916 : return std::unique_ptr<AST::MatchExpr> (
1364 916 : new AST::MatchExpr (std::move (scrutinee.value ()), std::move (match_arms),
1365 : std::move (inner_attrs), std::move (outer_attrs),
1366 916 : locus));
1367 919 : }
1368 :
1369 : // Parses an async block expression.
1370 : template <typename ManagedTokenSource>
1371 : tl::expected<std::unique_ptr<AST::AsyncBlockExpr>, Parse::Error::Node>
1372 0 : Parser<ManagedTokenSource>::parse_async_block_expr (AST::AttrVec outer_attrs)
1373 : {
1374 0 : location_t locus = lexer.peek_token ()->get_locus ();
1375 0 : skip_token (ASYNC);
1376 :
1377 : // detect optional move token
1378 0 : bool has_move = false;
1379 0 : if (lexer.peek_token ()->get_id () == MOVE)
1380 : {
1381 0 : lexer.skip_token ();
1382 0 : has_move = true;
1383 : }
1384 :
1385 : // parse block expression (required)
1386 0 : auto block_expr = parse_block_expr ();
1387 0 : if (!block_expr)
1388 : {
1389 0 : Error error (
1390 0 : lexer.peek_token ()->get_locus (),
1391 : "failed to parse block expression of async block expression");
1392 0 : add_error (std::move (error));
1393 :
1394 : // skip somewhere?
1395 : return tl::unexpected<Parse::Error::Node> (
1396 0 : Parse::Error::Node::CHILD_ERROR);
1397 0 : }
1398 :
1399 0 : return std::unique_ptr<AST::AsyncBlockExpr> (
1400 0 : new AST::AsyncBlockExpr (std::move (block_expr.value ()), has_move,
1401 0 : std::move (outer_attrs), locus));
1402 0 : }
1403 :
1404 : // Parses an unsafe block expression.
1405 : template <typename ManagedTokenSource>
1406 : tl::expected<std::unique_ptr<AST::UnsafeBlockExpr>, Parse::Error::Node>
1407 3690 : Parser<ManagedTokenSource>::parse_unsafe_block_expr (
1408 : AST::AttrVec outer_attrs, location_t pratt_parsed_loc)
1409 : {
1410 3690 : location_t locus = pratt_parsed_loc;
1411 3690 : if (locus == UNKNOWN_LOCATION)
1412 : {
1413 0 : locus = lexer.peek_token ()->get_locus ();
1414 0 : skip_token (UNSAFE);
1415 : }
1416 :
1417 : // parse block expression (required)
1418 3690 : auto block_expr = parse_block_expr ();
1419 3690 : if (!block_expr)
1420 : {
1421 0 : Error error (
1422 0 : lexer.peek_token ()->get_locus (),
1423 : "failed to parse block expression of unsafe block expression");
1424 0 : add_error (std::move (error));
1425 :
1426 : // skip somewhere?
1427 : return tl::unexpected<Parse::Error::Node> (
1428 0 : Parse::Error::Node::CHILD_ERROR);
1429 0 : }
1430 3690 : return std::unique_ptr<AST::UnsafeBlockExpr> (
1431 3690 : new AST::UnsafeBlockExpr (std::move (block_expr.value ()),
1432 3690 : std::move (outer_attrs), locus));
1433 3690 : }
1434 :
1435 : // Parses an array definition expression.
1436 : template <typename ManagedTokenSource>
1437 : tl::expected<std::unique_ptr<AST::ArrayExpr>, Parse::Error::Node>
1438 410 : Parser<ManagedTokenSource>::parse_array_expr (AST::AttrVec outer_attrs,
1439 : location_t pratt_parsed_loc)
1440 : {
1441 410 : location_t locus = pratt_parsed_loc;
1442 410 : if (locus == UNKNOWN_LOCATION)
1443 : {
1444 0 : locus = lexer.peek_token ()->get_locus ();
1445 0 : skip_token (LEFT_SQUARE);
1446 : }
1447 :
1448 : // parse optional inner attributes
1449 410 : AST::AttrVec inner_attrs = parse_inner_attributes ();
1450 :
1451 : // parse the "array elements" section, which is optional
1452 820 : if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
1453 : {
1454 : // no array elements
1455 1 : lexer.skip_token ();
1456 :
1457 1 : std::vector<std::unique_ptr<AST::Expr>> exprs;
1458 1 : auto array_elems
1459 : = std::make_unique<AST::ArrayElemsValues> (std::move (exprs), locus);
1460 1 : return std::make_unique<AST::ArrayExpr> (std::move (array_elems),
1461 : std::move (inner_attrs),
1462 1 : std::move (outer_attrs), locus);
1463 1 : }
1464 : else
1465 : {
1466 : // should have array elements
1467 : // parse initial expression, which is required for either
1468 409 : auto initial_expr = parse_expr ();
1469 409 : if (!initial_expr)
1470 : {
1471 0 : Error error (lexer.peek_token ()->get_locus (),
1472 : "could not parse expression in array expression "
1473 : "(even though arrayelems seems to be present)");
1474 0 : add_error (std::move (error));
1475 :
1476 : // skip somewhere?
1477 : return tl::unexpected<Parse::Error::Node> (
1478 0 : Parse::Error::Node::CHILD_ERROR);
1479 0 : }
1480 :
1481 818 : if (lexer.peek_token ()->get_id () == SEMICOLON)
1482 : {
1483 : // copy array elems
1484 123 : lexer.skip_token ();
1485 :
1486 : // parse copy amount expression (required)
1487 123 : auto copy_amount = parse_expr ();
1488 123 : if (!copy_amount)
1489 : {
1490 0 : Error error (lexer.peek_token ()->get_locus (),
1491 : "could not parse copy amount expression in array "
1492 : "expression (arrayelems)");
1493 0 : add_error (std::move (error));
1494 :
1495 : // skip somewhere?
1496 : return tl::unexpected<Parse::Error::Node> (
1497 0 : Parse::Error::Node::CHILD_ERROR);
1498 0 : }
1499 :
1500 123 : skip_token (RIGHT_SQUARE);
1501 :
1502 123 : std::unique_ptr<AST::ArrayElemsCopied> copied_array_elems (
1503 246 : new AST::ArrayElemsCopied (std::move (initial_expr.value ()),
1504 123 : std::move (copy_amount.value ()),
1505 : locus));
1506 123 : return std::unique_ptr<AST::ArrayExpr> (
1507 123 : new AST::ArrayExpr (std::move (copied_array_elems),
1508 : std::move (inner_attrs),
1509 123 : std::move (outer_attrs), locus));
1510 246 : }
1511 572 : else if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
1512 : {
1513 : // single-element array expression
1514 34 : std::vector<std::unique_ptr<AST::Expr>> exprs;
1515 34 : exprs.reserve (1);
1516 34 : exprs.push_back (std::move (initial_expr.value ()));
1517 34 : exprs.shrink_to_fit ();
1518 :
1519 34 : skip_token (RIGHT_SQUARE);
1520 :
1521 34 : std::unique_ptr<AST::ArrayElemsValues> array_elems (
1522 34 : new AST::ArrayElemsValues (std::move (exprs), locus));
1523 34 : return std::unique_ptr<AST::ArrayExpr> (
1524 34 : new AST::ArrayExpr (std::move (array_elems),
1525 : std::move (inner_attrs),
1526 34 : std::move (outer_attrs), locus));
1527 34 : }
1528 504 : else if (lexer.peek_token ()->get_id () == COMMA)
1529 : {
1530 : // multi-element array expression (or trailing comma)
1531 252 : std::vector<std::unique_ptr<AST::Expr>> exprs;
1532 252 : exprs.push_back (std::move (initial_expr.value ()));
1533 :
1534 252 : const_TokenPtr t = lexer.peek_token ();
1535 1150 : while (t->get_id () == COMMA)
1536 : {
1537 905 : lexer.skip_token ();
1538 :
1539 : // quick break if right square bracket
1540 1810 : if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
1541 : break;
1542 :
1543 : // parse expression (required)
1544 898 : auto expr = parse_expr ();
1545 898 : if (!expr)
1546 : {
1547 0 : Error error (lexer.peek_token ()->get_locus (),
1548 : "failed to parse element in array expression");
1549 0 : add_error (std::move (error));
1550 :
1551 : // skip somewhere?
1552 : return tl::unexpected<Parse::Error::Node> (
1553 0 : Parse::Error::Node::CHILD_ERROR);
1554 0 : }
1555 898 : exprs.push_back (std::move (expr.value ()));
1556 :
1557 898 : t = lexer.peek_token ();
1558 : }
1559 :
1560 252 : skip_token (RIGHT_SQUARE);
1561 :
1562 252 : exprs.shrink_to_fit ();
1563 :
1564 252 : std::unique_ptr<AST::ArrayElemsValues> array_elems (
1565 252 : new AST::ArrayElemsValues (std::move (exprs), locus));
1566 252 : return std::unique_ptr<AST::ArrayExpr> (
1567 252 : new AST::ArrayExpr (std::move (array_elems),
1568 : std::move (inner_attrs),
1569 252 : std::move (outer_attrs), locus));
1570 504 : }
1571 : else
1572 : {
1573 : // error
1574 0 : Error error (lexer.peek_token ()->get_locus (),
1575 : "unexpected token %qs in array expression (arrayelems)",
1576 0 : lexer.peek_token ()->get_token_description ());
1577 0 : add_error (std::move (error));
1578 :
1579 : // skip somewhere?
1580 : return tl::unexpected<Parse::Error::Node> (
1581 0 : Parse::Error::Node::MALFORMED);
1582 0 : }
1583 409 : }
1584 410 : }
1585 :
1586 : // Parses a grouped or tuple expression (disambiguates).
1587 : template <typename ManagedTokenSource>
1588 : tl::expected<std::unique_ptr<AST::ExprWithoutBlock>, Parse::Error::Node>
1589 861 : Parser<ManagedTokenSource>::parse_grouped_or_tuple_expr (
1590 : AST::AttrVec outer_attrs, location_t pratt_parsed_loc)
1591 : {
1592 : // adjustment to allow Pratt parsing to reuse function without copy-paste
1593 861 : location_t locus = pratt_parsed_loc;
1594 861 : if (locus == UNKNOWN_LOCATION)
1595 : {
1596 0 : locus = lexer.peek_token ()->get_locus ();
1597 0 : skip_token (LEFT_PAREN);
1598 : }
1599 :
1600 : // parse optional inner attributes
1601 861 : AST::AttrVec inner_attrs = parse_inner_attributes ();
1602 :
1603 1722 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
1604 : {
1605 : // must be empty tuple
1606 155 : lexer.skip_token ();
1607 :
1608 : // create tuple with empty tuple elems
1609 155 : return std::unique_ptr<AST::TupleExpr> (
1610 155 : new AST::TupleExpr (std::vector<std::unique_ptr<AST::Expr>> (),
1611 : std::move (inner_attrs), std::move (outer_attrs),
1612 155 : locus));
1613 : }
1614 :
1615 : // parse first expression (required)
1616 706 : auto first_expr = parse_expr ();
1617 706 : if (!first_expr)
1618 : {
1619 0 : Error error (lexer.peek_token ()->get_locus (),
1620 : "failed to parse expression in grouped or tuple expression");
1621 0 : add_error (std::move (error));
1622 :
1623 : // skip after somewhere?
1624 : return tl::unexpected<Parse::Error::Node> (
1625 0 : Parse::Error::Node::CHILD_ERROR);
1626 0 : }
1627 :
1628 : // detect whether grouped expression with right parentheses as next token
1629 1412 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
1630 : {
1631 : // must be grouped expr
1632 318 : lexer.skip_token ();
1633 :
1634 : // create grouped expr
1635 318 : return std::unique_ptr<AST::GroupedExpr> (
1636 318 : new AST::GroupedExpr (std::move (first_expr.value ()),
1637 : std::move (inner_attrs), std::move (outer_attrs),
1638 318 : locus));
1639 : }
1640 776 : else if (lexer.peek_token ()->get_id () == COMMA)
1641 : {
1642 : // tuple expr
1643 387 : std::vector<std::unique_ptr<AST::Expr>> exprs;
1644 387 : exprs.push_back (std::move (first_expr.value ()));
1645 :
1646 : // parse potential other tuple exprs
1647 387 : const_TokenPtr t = lexer.peek_token ();
1648 918 : while (t->get_id () == COMMA)
1649 : {
1650 560 : lexer.skip_token ();
1651 :
1652 : // break out if right paren
1653 1120 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
1654 : break;
1655 :
1656 : // parse expr, which is now required
1657 531 : auto expr = parse_expr ();
1658 531 : if (!expr)
1659 : {
1660 0 : Error error (lexer.peek_token ()->get_locus (),
1661 : "failed to parse expr in tuple expr");
1662 0 : add_error (std::move (error));
1663 :
1664 : // skip somewhere?
1665 : return tl::unexpected<Parse::Error::Node> (
1666 0 : Parse::Error::Node::CHILD_ERROR);
1667 0 : }
1668 531 : exprs.push_back (std::move (expr.value ()));
1669 :
1670 531 : t = lexer.peek_token ();
1671 : }
1672 :
1673 : // skip right paren
1674 387 : skip_token (RIGHT_PAREN);
1675 :
1676 387 : return std::unique_ptr<AST::TupleExpr> (
1677 387 : new AST::TupleExpr (std::move (exprs), std::move (inner_attrs),
1678 387 : std::move (outer_attrs), locus));
1679 387 : }
1680 : else
1681 : {
1682 : // error
1683 1 : const_TokenPtr t = lexer.peek_token ();
1684 1 : Error error (t->get_locus (),
1685 : "unexpected token %qs in grouped or tuple expression "
1686 : "(parenthesised expression) - expected %<)%> for grouped "
1687 : "expr and %<,%> for tuple expr",
1688 : t->get_token_description ());
1689 1 : add_error (std::move (error));
1690 :
1691 : // skip somewhere?
1692 1 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
1693 2 : }
1694 861 : }
1695 :
1696 : // Parses a struct expression field.
1697 : template <typename ManagedTokenSource>
1698 : tl::expected<std::unique_ptr<AST::StructExprField>,
1699 : Parse::Error::StructExprField>
1700 2294 : Parser<ManagedTokenSource>::parse_struct_expr_field ()
1701 : {
1702 2294 : AST::AttrVec outer_attrs = parse_outer_attributes ();
1703 2294 : const_TokenPtr t = lexer.peek_token ();
1704 2294 : switch (t->get_id ())
1705 : {
1706 2249 : case IDENTIFIER:
1707 4498 : if (lexer.peek_token (1)->get_id () == COLON)
1708 : {
1709 : // struct expr field with identifier and expr
1710 2033 : Identifier ident = {t};
1711 2033 : lexer.skip_token (1);
1712 :
1713 : // parse expression (required)
1714 2033 : auto expr = parse_expr ();
1715 2033 : if (!expr)
1716 : {
1717 0 : Error error (t->get_locus (),
1718 : "failed to parse struct expression field with "
1719 : "identifier and expression");
1720 0 : add_error (std::move (error));
1721 :
1722 : return tl::unexpected<Parse::Error::StructExprField> (
1723 0 : Parse::Error::StructExprField::CHILD_ERROR);
1724 0 : }
1725 :
1726 2033 : return std::unique_ptr<AST::StructExprFieldIdentifierValue> (
1727 4066 : new AST::StructExprFieldIdentifierValue (std::move (ident),
1728 2033 : std::move (expr.value ()),
1729 : std::move (outer_attrs),
1730 2033 : t->get_locus ()));
1731 2033 : }
1732 : else
1733 : {
1734 : // struct expr field with identifier only
1735 216 : Identifier ident{t};
1736 216 : lexer.skip_token ();
1737 :
1738 216 : return std::unique_ptr<AST::StructExprFieldIdentifier> (
1739 432 : new AST::StructExprFieldIdentifier (std::move (ident),
1740 : std::move (outer_attrs),
1741 216 : t->get_locus ()));
1742 216 : }
1743 44 : case INT_LITERAL:
1744 : {
1745 : // parse tuple index field
1746 44 : int index = atoi (t->get_str ().c_str ());
1747 44 : lexer.skip_token ();
1748 :
1749 44 : if (!skip_token (COLON))
1750 : {
1751 : // skip somewhere?
1752 : return tl::unexpected<Parse::Error::StructExprField> (
1753 0 : Parse::Error::StructExprField::MALFORMED);
1754 : }
1755 :
1756 : // parse field expression (required)
1757 44 : auto expr = parse_expr ();
1758 44 : if (!expr)
1759 : {
1760 0 : Error error (t->get_locus (),
1761 : "failed to parse expr in struct (or enum) expr "
1762 : "field with tuple index");
1763 0 : add_error (std::move (error));
1764 :
1765 : return tl::unexpected<Parse::Error::StructExprField> (
1766 0 : Parse::Error::StructExprField::CHILD_ERROR);
1767 0 : }
1768 :
1769 44 : return std::unique_ptr<AST::StructExprFieldIndexValue> (
1770 44 : new AST::StructExprFieldIndexValue (index, std::move (expr.value ()),
1771 : std::move (outer_attrs),
1772 44 : t->get_locus ()));
1773 44 : }
1774 1 : case DOT_DOT:
1775 : /* this is a struct base and can't be parsed here, so just return
1776 : * nothing without erroring */
1777 1 : if (!outer_attrs.empty ())
1778 : {
1779 1 : add_error (
1780 1 : Error (t->get_locus (),
1781 : "attributes are not allowed before %<..%> in a struct "
1782 : "expression"));
1783 :
1784 : return tl::unexpected<Parse::Error::StructExprField> (
1785 1 : Parse::Error::StructExprField::STRUCT_BASE_ATTRIBUTES);
1786 : }
1787 :
1788 : return tl::unexpected<Parse::Error::StructExprField> (
1789 0 : Parse::Error::StructExprField::STRUCT_BASE);
1790 0 : default:
1791 0 : add_error (
1792 0 : Error (t->get_locus (),
1793 : "unrecognised token %qs as first token of struct expr field - "
1794 : "expected identifier or integer literal",
1795 : t->get_token_description ()));
1796 :
1797 : return tl::unexpected<Parse::Error::StructExprField> (
1798 0 : Parse::Error::StructExprField::MALFORMED);
1799 : }
1800 2294 : }
1801 :
1802 : /* Pratt parser impl of parse_expr. FIXME: this is only provisional and
1803 : * probably will be changed. */
1804 : template <typename ManagedTokenSource>
1805 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
1806 73814 : Parser<ManagedTokenSource>::parse_expr (int right_binding_power,
1807 : AST::AttrVec outer_attrs,
1808 : ParseRestrictions restrictions)
1809 : {
1810 73814 : const_TokenPtr current_token = lexer.peek_token ();
1811 : // Special hack because we are allowed to return nullptr, in that case we
1812 : // don't want to skip the token, since we don't actually parse it. But if
1813 : // null isn't allowed it indicates an error, and we want to skip past that.
1814 : // So return early if it is one of the tokens that ends an expression
1815 : // (or at least cannot start a new expression).
1816 73814 : if (restrictions.expr_can_be_null)
1817 : {
1818 1383 : TokenId id = current_token->get_id ();
1819 1383 : if (id == SEMICOLON || id == RIGHT_PAREN || id == RIGHT_CURLY
1820 : || id == RIGHT_SQUARE || id == COMMA || id == LEFT_CURLY)
1821 : return tl::unexpected<Parse::Error::Expr> (
1822 100 : Parse::Error::Expr::NULL_EXPR);
1823 : }
1824 :
1825 73714 : ParseRestrictions null_denotation_restrictions = restrictions;
1826 73714 : null_denotation_restrictions.expr_can_be_stmt = false;
1827 :
1828 : // parse null denotation (unary part of expression)
1829 73714 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr
1830 73714 : = null_denotation ({}, null_denotation_restrictions);
1831 73714 : if (!expr)
1832 66 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
1833 73648 : if (expr.value () == nullptr)
1834 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
1835 :
1836 147296 : return left_denotations (std::move (expr), right_binding_power,
1837 73648 : std::move (outer_attrs), restrictions);
1838 73714 : }
1839 :
1840 : // Parse expression with lowest left binding power.
1841 : template <typename ManagedTokenSource>
1842 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
1843 56010 : Parser<ManagedTokenSource>::parse_expr (AST::AttrVec outer_attrs,
1844 : ParseRestrictions restrictions)
1845 : {
1846 56010 : return parse_expr (LBP_LOWEST, std::move (outer_attrs), restrictions);
1847 : }
1848 :
1849 : template <typename ManagedTokenSource>
1850 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
1851 88946 : Parser<ManagedTokenSource>::left_denotations (
1852 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr,
1853 : int right_binding_power, AST::AttrVec outer_attrs,
1854 : ParseRestrictions restrictions)
1855 : {
1856 88946 : if (!expr)
1857 : {
1858 : // DEBUG
1859 1 : rust_debug ("null denotation is null; returning null for parse_expr");
1860 : return tl::unexpected<Parse::Error::Expr> (
1861 1 : Parse::Error::Expr::NULL_DENOTATION);
1862 : }
1863 :
1864 88945 : const_TokenPtr current_token = lexer.peek_token ();
1865 :
1866 29439 : if (restrictions.expr_can_be_stmt && !expr.value ()->is_expr_without_block ()
1867 7751 : && current_token->get_id () != DOT
1868 96691 : && current_token->get_id () != QUESTION_MARK)
1869 : {
1870 7746 : rust_debug ("statement expression with block");
1871 7746 : expr.value ()->set_outer_attrs (std::move (outer_attrs));
1872 88945 : return expr;
1873 : }
1874 :
1875 108334 : restrictions.expr_can_be_stmt = false;
1876 :
1877 : // stop parsing if find lower priority token - parse higher priority first
1878 325002 : while (right_binding_power < left_binding_power (current_token))
1879 : {
1880 27137 : lexer.skip_token ();
1881 :
1882 : // FIXME attributes should generally be applied to the null denotation.
1883 108546 : expr = left_denotation (current_token, std::move (expr.value ()),
1884 : std::move (outer_attrs), restrictions);
1885 :
1886 27137 : if (!expr)
1887 : {
1888 : // DEBUG
1889 2 : rust_debug ("left denotation is null; returning null for parse_expr");
1890 :
1891 : return tl::unexpected<Parse::Error::Expr> (
1892 2 : Parse::Error::Expr::LEFT_DENOTATION);
1893 : }
1894 :
1895 27135 : current_token = lexer.peek_token ();
1896 : }
1897 :
1898 88945 : return expr;
1899 88945 : }
1900 :
1901 : /* Determines action to take when finding token at beginning of expression. */
1902 : template <typename ManagedTokenSource>
1903 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
1904 73714 : Parser<ManagedTokenSource>::null_denotation (AST::AttrVec outer_attrs,
1905 : ParseRestrictions restrictions)
1906 : {
1907 : /* note: tok is previous character in input stream, not current one, as
1908 : * parse_expr skips it before passing it in */
1909 :
1910 : /* as a Pratt parser (which works by decomposing expressions into a null
1911 : * denotation and then a left denotation), null denotations handle primaries
1912 : * and unary operands (but only prefix unary operands) */
1913 :
1914 73714 : auto tok = lexer.peek_token ();
1915 :
1916 73714 : switch (tok->get_id ())
1917 : {
1918 34450 : case IDENTIFIER:
1919 : case SELF:
1920 : case SELF_ALIAS:
1921 : case DOLLAR_SIGN:
1922 : case CRATE:
1923 : case SUPER:
1924 : case SCOPE_RESOLUTION:
1925 : {
1926 : // DEBUG
1927 34450 : rust_debug ("beginning null denotation identifier handling");
1928 :
1929 : /* best option: parse as path, then extract identifier, macro,
1930 : * struct/enum, or just path info from it */
1931 34450 : AST::PathInExpression path = parse_path_in_expression ();
1932 :
1933 68900 : return null_denotation_path (std::move (path), std::move (outer_attrs),
1934 34450 : restrictions);
1935 34450 : }
1936 2 : case HASH:
1937 : {
1938 : // Parse outer attributes and then the expression that follows
1939 2 : AST::AttrVec attrs = parse_outer_attributes ();
1940 :
1941 : // Merge with any existing outer attributes
1942 2 : if (!outer_attrs.empty ())
1943 0 : attrs.insert (attrs.begin (), outer_attrs.begin (),
1944 : outer_attrs.end ());
1945 :
1946 : // Try to parse the expression that should follow the attributes
1947 2 : auto expr = parse_expr (std::move (attrs), restrictions);
1948 2 : if (!expr)
1949 : {
1950 : /* If parsing failed and we're at a semicolon, provide a better
1951 : * error
1952 : */
1953 2 : const_TokenPtr next_tok = lexer.peek_token ();
1954 2 : if (next_tok->get_id () == SEMICOLON)
1955 0 : add_error (Error (next_tok->get_locus (),
1956 : "expected expression, found %<;%>"));
1957 : return tl::unexpected<Parse::Error::Expr> (
1958 2 : Parse::Error::Expr::CHILD_ERROR);
1959 2 : }
1960 0 : return expr;
1961 2 : }
1962 39262 : default:
1963 39262 : if (tok->get_id () == LEFT_SHIFT)
1964 : {
1965 2 : lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
1966 2 : tok = lexer.peek_token ();
1967 : }
1968 :
1969 39262 : lexer.skip_token ();
1970 78524 : return null_denotation_not_path (std::move (tok), std::move (outer_attrs),
1971 39262 : restrictions);
1972 : }
1973 73714 : }
1974 :
1975 : // Handling of expresions that start with a path for `null_denotation`.
1976 : template <typename ManagedTokenSource>
1977 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
1978 49562 : Parser<ManagedTokenSource>::null_denotation_path (
1979 : AST::PathInExpression path, AST::AttrVec outer_attrs,
1980 : ParseRestrictions restrictions)
1981 : {
1982 49562 : rust_debug ("parsing null denotation after path");
1983 :
1984 : // HACK: always make "self" by itself a path (regardless of next
1985 : // tokens)
1986 49562 : if (path.is_single_segment () && path.get_segments ()[0].is_lower_self_seg ())
1987 : {
1988 : // HACK: add outer attrs to path
1989 6961 : path.set_outer_attrs (std::move (outer_attrs));
1990 13922 : return std::make_unique<AST::PathInExpression> (std::move (path));
1991 : }
1992 :
1993 : // branch on next token
1994 42601 : const_TokenPtr t = lexer.peek_token ();
1995 42601 : switch (t->get_id ())
1996 : {
1997 1817 : case EXCLAM:
1998 : {
1999 : // macro
2000 1817 : auto macro = parse_macro_invocation_partial (std::move (path),
2001 : std::move (outer_attrs));
2002 1817 : if (macro == nullptr)
2003 : return tl::unexpected<Parse::Error::Expr> (
2004 3 : Parse::Error::Expr::CHILD_ERROR);
2005 1814 : return std::unique_ptr<AST::Expr> (std::move (macro));
2006 1817 : }
2007 3045 : case LEFT_CURLY:
2008 : {
2009 3045 : bool not_a_block = lexer.peek_token (1)->get_id () == IDENTIFIER
2010 8424 : && (lexer.peek_token (2)->get_id () == COMMA
2011 7679 : || (lexer.peek_token (2)->get_id () == COLON
2012 4923 : && (lexer.peek_token (4)->get_id () == COMMA
2013 672 : || !Parse::Utils::can_tok_start_type (
2014 1494 : lexer.peek_token (3)->get_id ()))));
2015 :
2016 : /* definitely not a block:
2017 : * path '{' ident ','
2018 : * path '{' ident ':' [anything] ','
2019 : * path '{' ident ':' [not a type]
2020 : * otherwise, assume block expr and thus path */
2021 : // DEBUG
2022 12180 : rust_debug ("values of lookahead: '%s' '%s' '%s' '%s' ",
2023 : lexer.peek_token (1)->get_token_description (),
2024 : lexer.peek_token (2)->get_token_description (),
2025 : lexer.peek_token (3)->get_token_description (),
2026 : lexer.peek_token (4)->get_token_description ());
2027 :
2028 6667 : rust_debug ("can be struct expr: '%s', not a block: '%s'",
2029 : restrictions.can_be_struct_expr ? "true" : "false",
2030 : not_a_block ? "true" : "false");
2031 :
2032 : // struct/enum expr struct
2033 3045 : if (!restrictions.can_be_struct_expr && !not_a_block)
2034 : {
2035 : // HACK: add outer attrs to path
2036 1627 : path.set_outer_attrs (std::move (outer_attrs));
2037 1627 : return std::unique_ptr<AST::PathInExpression> (
2038 1627 : new AST::PathInExpression (std::move (path)));
2039 : }
2040 1418 : auto struct_expr
2041 2836 : = parse_struct_expr_struct_partial (std::move (path),
2042 : std::move (outer_attrs));
2043 1418 : if (struct_expr == nullptr)
2044 : {
2045 : return tl::unexpected<Parse::Error::Expr> (
2046 0 : Parse::Error::Expr::CHILD_ERROR);
2047 : }
2048 1418 : return struct_expr;
2049 1418 : }
2050 12221 : case LEFT_PAREN:
2051 : {
2052 : // struct/enum expr tuple
2053 12221 : if (!restrictions.can_be_struct_expr)
2054 : {
2055 : // assume path is returned
2056 : // HACK: add outer attributes to path
2057 875 : path.set_outer_attrs (std::move (outer_attrs));
2058 1750 : return std::make_unique<AST::PathInExpression> (std::move (path));
2059 : }
2060 11346 : auto tuple_expr
2061 22692 : = parse_struct_expr_tuple_partial (std::move (path),
2062 : std::move (outer_attrs));
2063 11346 : if (tuple_expr == nullptr)
2064 : {
2065 : return tl::unexpected<Parse::Error::Expr> (
2066 0 : Parse::Error::Expr::CHILD_ERROR);
2067 : }
2068 11346 : return tuple_expr;
2069 11346 : }
2070 25518 : default:
2071 : // assume path is returned if not single segment
2072 25518 : if (path.is_single_segment ())
2073 : {
2074 : // FIXME: This should probably be returned as a path.
2075 : /* HACK: may have to become permanent, but this is my current
2076 : * identifier expression */
2077 73005 : return std::unique_ptr<AST::IdentifierExpr> (new AST::IdentifierExpr (
2078 97340 : path.get_segments ()[0].get_ident_segment ().as_string (), {},
2079 24335 : path.get_locus ()));
2080 : }
2081 : // HACK: add outer attrs to path
2082 1183 : path.set_outer_attrs (std::move (outer_attrs));
2083 1183 : return std::unique_ptr<AST::PathInExpression> (
2084 1183 : new AST::PathInExpression (std::move (path)));
2085 : }
2086 : rust_unreachable ();
2087 42601 : }
2088 :
2089 : // Handling of expresions that do not start with a path for `null_denotation`.
2090 : template <typename ManagedTokenSource>
2091 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
2092 39262 : Parser<ManagedTokenSource>::null_denotation_not_path (
2093 : const_TokenPtr tok, AST::AttrVec outer_attrs, ParseRestrictions restrictions)
2094 : {
2095 39262 : switch (tok->get_id ())
2096 : {
2097 : // FIXME: Handle in null_denotation_path?
2098 99 : case LEFT_SHIFT:
2099 : case LEFT_ANGLE:
2100 : {
2101 : // qualified path
2102 : // HACK: add outer attrs to path
2103 99 : AST::QualifiedPathInExpression path
2104 : = parse_qualified_path_in_expression (tok->get_locus ());
2105 99 : path.set_outer_attrs (std::move (outer_attrs));
2106 99 : return std::make_unique<AST::QualifiedPathInExpression> (
2107 99 : std::move (path));
2108 99 : }
2109 : // FIXME: delegate to parse_literal_expr instead? would have to rejig
2110 : // tokens and whatever.
2111 : // FIXME: for literal exprs, outer attrs should be passed in, and later
2112 : // error if it does not make up the entire statement.
2113 17834 : case INT_LITERAL:
2114 : // we should check the range, but ignore for now
2115 : // encode as int?
2116 71336 : return std::unique_ptr<AST::LiteralExpr> (new AST::LiteralExpr (
2117 53502 : LiteralResolve::evaluate_integer_literal (tok), AST::Literal::INT,
2118 53502 : LiteralResolve::resolve_literal_suffix (tok), {}, tok->get_locus ()));
2119 358 : case FLOAT_LITERAL:
2120 : // encode as float?
2121 1432 : return std::unique_ptr<AST::LiteralExpr> (new AST::LiteralExpr (
2122 1074 : LiteralResolve::evaluate_float_literal (tok), AST::Literal::FLOAT,
2123 1074 : LiteralResolve::resolve_literal_suffix (tok), {}, tok->get_locus ()));
2124 2515 : case STRING_LITERAL:
2125 2515 : return std::unique_ptr<AST::LiteralExpr> (
2126 10060 : new AST::LiteralExpr (tok->get_str (), AST::Literal::STRING,
2127 2515 : tok->get_type_hint (), {}, tok->get_locus ()));
2128 81 : case BYTE_STRING_LITERAL:
2129 81 : return std::unique_ptr<AST::LiteralExpr> (
2130 324 : new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE_STRING,
2131 81 : tok->get_type_hint (), {}, tok->get_locus ()));
2132 25 : case RAW_STRING_LITERAL:
2133 25 : return std::unique_ptr<AST::LiteralExpr> (
2134 100 : new AST::LiteralExpr (tok->get_str (), AST::Literal::RAW_STRING,
2135 25 : tok->get_type_hint (), {}, tok->get_locus ()));
2136 15 : case C_STRING_LITERAL:
2137 15 : if (flag_c_style_string_literals)
2138 : {
2139 15 : return std::unique_ptr<AST::LiteralExpr> (
2140 60 : new AST::LiteralExpr (tok->get_str (), AST::Literal::C_STRING,
2141 : tok->get_type_hint (), {},
2142 15 : tok->get_locus ()));
2143 : }
2144 : else
2145 : {
2146 0 : Error error (tok->get_locus (),
2147 : "C-style string literals require "
2148 : "%<-frust-c-style-string-literals%> to be enabled");
2149 0 : add_error (std::move (error));
2150 : return tl::unexpected<Parse::Error::Expr> (
2151 0 : Parse::Error::Expr::MALFORMED);
2152 0 : }
2153 190 : case CHAR_LITERAL:
2154 190 : return std::unique_ptr<AST::LiteralExpr> (
2155 760 : new AST::LiteralExpr (tok->get_str (), AST::Literal::CHAR,
2156 190 : tok->get_type_hint (), {}, tok->get_locus ()));
2157 57 : case BYTE_CHAR_LITERAL:
2158 57 : return std::unique_ptr<AST::LiteralExpr> (
2159 228 : new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE,
2160 57 : tok->get_type_hint (), {}, tok->get_locus ()));
2161 728 : case TRUE_LITERAL:
2162 728 : return std::unique_ptr<AST::LiteralExpr> (
2163 2184 : new AST::LiteralExpr (Values::Keywords::TRUE_LITERAL,
2164 : AST::Literal::BOOL, tok->get_type_hint (), {},
2165 728 : tok->get_locus ()));
2166 535 : case FALSE_LITERAL:
2167 535 : return std::unique_ptr<AST::LiteralExpr> (
2168 1605 : new AST::LiteralExpr (Values::Keywords::FALSE_LITERAL,
2169 : AST::Literal::BOOL, tok->get_type_hint (), {},
2170 535 : tok->get_locus ()));
2171 861 : case LEFT_PAREN:
2172 : {
2173 861 : auto grouped_or_tuple_expr
2174 861 : = parse_grouped_or_tuple_expr (std::move (outer_attrs),
2175 : tok->get_locus ());
2176 861 : if (grouped_or_tuple_expr)
2177 860 : return std::move (grouped_or_tuple_expr.value ());
2178 : else
2179 : return tl::unexpected<Parse::Error::Expr> (
2180 1 : Parse::Error::Expr::CHILD_ERROR);
2181 861 : }
2182 :
2183 : /*case PLUS: { // unary plus operator
2184 : // invoke parse_expr recursively with appropriate priority, etc. for
2185 : below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS);
2186 :
2187 : if (expr == nullptr)
2188 : return nullptr;
2189 : // can only apply to integer and float expressions
2190 : if (expr->get_type() != integer_type_node || expr->get_type() !=
2191 : float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
2192 : plus must be int or float but it is %s", print_type(expr->get_type()));
2193 : return nullptr;
2194 : }
2195 :
2196 : return Tree(expr, tok->get_locus());
2197 : }*/
2198 : // Rust has no unary plus operator
2199 416 : case MINUS:
2200 : { // unary minus
2201 416 : ParseRestrictions entered_from_unary;
2202 416 : entered_from_unary.entered_from_unary = true;
2203 416 : if (!restrictions.can_be_struct_expr)
2204 15 : entered_from_unary.can_be_struct_expr = false;
2205 416 : auto expr = parse_expr (LBP_UNARY_MINUS, {}, entered_from_unary);
2206 :
2207 416 : if (!expr)
2208 : return tl::unexpected<Parse::Error::Expr> (
2209 0 : Parse::Error::Expr::CHILD_ERROR);
2210 : // can only apply to integer and float expressions
2211 : /*if (expr.get_type() != integer_type_node || expr.get_type() !=
2212 : float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
2213 : minus must be int or float but it is %s",
2214 : print_type(expr.get_type())); return Tree::error();
2215 : }*/
2216 : /* FIXME: when implemented the "get type" method on expr, ensure it is
2217 : * int or float type (except unsigned int). Actually, this would
2218 : * probably have to be done in semantic analysis (as type checking).
2219 : */
2220 :
2221 : /* FIXME: allow outer attributes on these expressions by having an
2222 : * outer attrs parameter in function*/
2223 416 : return std::make_unique<AST::NegationExpr> (std::move (expr.value ()),
2224 416 : NegationOperator::NEGATE,
2225 : std::move (outer_attrs),
2226 832 : tok->get_locus ());
2227 416 : }
2228 276 : case EXCLAM:
2229 : { // logical or bitwise not
2230 276 : ParseRestrictions entered_from_unary;
2231 276 : entered_from_unary.entered_from_unary = true;
2232 276 : if (!restrictions.can_be_struct_expr)
2233 74 : entered_from_unary.can_be_struct_expr = false;
2234 276 : auto expr = parse_expr (LBP_UNARY_EXCLAM, {}, entered_from_unary);
2235 :
2236 276 : if (!expr)
2237 : return tl::unexpected<Parse::Error::Expr> (
2238 0 : Parse::Error::Expr::CHILD_ERROR);
2239 : // can only apply to boolean expressions
2240 : /*if (expr.get_type() != boolean_type_node) {
2241 : rust_error_at(tok->get_locus(),
2242 : "operand of logical not must be a boolean but it is %s",
2243 : print_type(expr.get_type()));
2244 : return Tree::error();
2245 : }*/
2246 : /* FIXME: type checking for boolean or integer expressions in semantic
2247 : * analysis */
2248 :
2249 : // FIXME: allow outer attributes on these expressions
2250 276 : return std::make_unique<AST::NegationExpr> (std::move (expr.value ()),
2251 276 : NegationOperator::NOT,
2252 : std::move (outer_attrs),
2253 552 : tok->get_locus ());
2254 276 : }
2255 3977 : case ASTERISK:
2256 : {
2257 : /* pointer dereference only - HACK: as struct expressions should
2258 : * always be value expressions, cannot be dereferenced */
2259 3977 : ParseRestrictions entered_from_unary;
2260 3977 : entered_from_unary.entered_from_unary = true;
2261 3977 : entered_from_unary.can_be_struct_expr = false;
2262 3977 : auto expr = parse_expr (LBP_UNARY_ASTERISK, {}, entered_from_unary);
2263 3977 : if (!expr)
2264 : return tl::unexpected<Parse::Error::Expr> (
2265 1 : Parse::Error::Expr::CHILD_ERROR);
2266 : // FIXME: allow outer attributes on expression
2267 3976 : return std::make_unique<AST::DereferenceExpr> (std::move (
2268 3976 : expr.value ()),
2269 : std::move (outer_attrs),
2270 7952 : tok->get_locus ());
2271 3977 : }
2272 1503 : case AMP:
2273 : {
2274 : // (single) "borrow" expression - shared (mutable) or immutable
2275 1503 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr
2276 : = tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
2277 1503 : Mutability mutability = Mutability::Imm;
2278 : bool raw_borrow = false;
2279 :
2280 1503 : ParseRestrictions entered_from_unary;
2281 1503 : entered_from_unary.entered_from_unary = true;
2282 1503 : if (!restrictions.can_be_struct_expr)
2283 0 : entered_from_unary.can_be_struct_expr = false;
2284 :
2285 9 : auto is_mutability = [] (const_TokenPtr token) {
2286 9 : return token->get_id () == CONST || token->get_id () == MUT;
2287 : };
2288 :
2289 1503 : auto t = lexer.peek_token ();
2290 : // Weak raw keyword, we look (1) ahead and treat it as an identifier if
2291 : // there is no mut nor const.
2292 2979 : if (t->get_id () == IDENTIFIER
2293 795 : && t->get_str () == Values::WeakKeywords::RAW
2294 1556 : && is_mutability (lexer.peek_token (1)))
2295 : {
2296 7 : lexer.skip_token ();
2297 14 : switch (lexer.peek_token ()->get_id ())
2298 : {
2299 6 : case MUT:
2300 6 : mutability = Mutability::Mut;
2301 6 : break;
2302 : case CONST:
2303 : mutability = Mutability::Imm;
2304 : break;
2305 0 : default:
2306 0 : rust_error_at (lexer.peek_token ()->get_locus (),
2307 : "raw borrow should be either const or mut");
2308 : }
2309 7 : lexer.skip_token ();
2310 7 : auto expr_result
2311 7 : = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
2312 7 : if (expr_result)
2313 7 : expr = std::move (expr_result.value ());
2314 : else
2315 : return tl::unexpected<Parse::Error::Expr> (
2316 0 : Parse::Error::Expr::CHILD_ERROR);
2317 7 : raw_borrow = true;
2318 7 : }
2319 1496 : else if (t->get_id () == MUT)
2320 : {
2321 404 : lexer.skip_token ();
2322 404 : auto expr_result
2323 404 : = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
2324 404 : if (expr_result)
2325 404 : expr = std::move (expr_result.value ());
2326 : else
2327 : return tl::unexpected<Parse::Error::Expr> (
2328 0 : Parse::Error::Expr::CHILD_ERROR);
2329 404 : mutability = Mutability::Mut;
2330 404 : raw_borrow = false;
2331 404 : }
2332 : else
2333 : {
2334 1092 : auto expr_result
2335 1092 : = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary);
2336 1092 : if (expr_result)
2337 1091 : expr = std::move (expr_result.value ());
2338 : else
2339 : return tl::unexpected<Parse::Error::Expr> (
2340 1 : Parse::Error::Expr::CHILD_ERROR);
2341 1091 : raw_borrow = false;
2342 1092 : }
2343 :
2344 : // FIXME: allow outer attributes on expression
2345 1502 : return std::make_unique<AST::BorrowExpr> (std::move (expr.value ()),
2346 1502 : mutability, raw_borrow, false,
2347 : std::move (outer_attrs),
2348 3004 : tok->get_locus ());
2349 3005 : }
2350 23 : case LOGICAL_AND:
2351 : {
2352 : // (double) "borrow" expression - shared (mutable) or immutable
2353 23 : std::unique_ptr<AST::Expr> expr = nullptr;
2354 23 : Mutability mutability = Mutability::Imm;
2355 :
2356 23 : ParseRestrictions entered_from_unary;
2357 23 : entered_from_unary.entered_from_unary = true;
2358 :
2359 46 : if (lexer.peek_token ()->get_id () == MUT)
2360 : {
2361 0 : lexer.skip_token ();
2362 0 : auto expr_res
2363 0 : = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
2364 0 : if (!expr_res)
2365 : return tl::unexpected<Parse::Error::Expr> (
2366 0 : Parse::Error::Expr::CHILD_ERROR);
2367 0 : expr = std::move (expr_res.value ());
2368 0 : mutability = Mutability::Mut;
2369 0 : }
2370 : else
2371 : {
2372 23 : auto expr_result
2373 23 : = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary);
2374 23 : if (expr_result)
2375 23 : expr = std::move (expr_result.value ());
2376 : else
2377 : return tl::unexpected<Parse::Error::Expr> (
2378 0 : Parse::Error::Expr::CHILD_ERROR);
2379 23 : mutability = Mutability::Imm;
2380 23 : }
2381 :
2382 : // FIXME: allow outer attributes on expression
2383 23 : return std::make_unique<AST::BorrowExpr> (std::move (expr), mutability,
2384 23 : false, true,
2385 : std::move (outer_attrs),
2386 23 : tok->get_locus ());
2387 23 : }
2388 73 : case OR:
2389 : case PIPE:
2390 : case MOVE:
2391 : // closure expression
2392 : {
2393 219 : auto ret = parse_closure_expr_pratt (tok, std::move (outer_attrs));
2394 73 : if (ret)
2395 73 : return std::move (ret.value ());
2396 : else
2397 : return tl::unexpected<Parse::Error::Expr> (
2398 0 : Parse::Error::Expr::CHILD_ERROR);
2399 73 : }
2400 9 : case DOT_DOT:
2401 : // either "range to" or "range full" expressions
2402 : {
2403 9 : auto ret
2404 27 : = parse_nud_range_exclusive_expr (tok, std::move (outer_attrs));
2405 9 : if (ret)
2406 9 : return std::move (ret.value ());
2407 : else
2408 : return tl::unexpected<Parse::Error::Expr> (
2409 0 : Parse::Error::Expr::CHILD_ERROR);
2410 9 : }
2411 0 : case DOT_DOT_EQ:
2412 : // range to inclusive expr
2413 : {
2414 0 : auto ret = parse_range_to_inclusive_expr (tok, std::move (outer_attrs));
2415 0 : if (ret)
2416 0 : return std::move (ret.value ());
2417 : else
2418 : return tl::unexpected<Parse::Error::Expr> (
2419 0 : Parse::Error::Expr::CHILD_ERROR);
2420 0 : }
2421 549 : case RETURN_KW:
2422 : // FIXME: is this really a null denotation expression?
2423 : {
2424 549 : auto ret
2425 549 : = parse_return_expr (std::move (outer_attrs), tok->get_locus ());
2426 549 : if (ret)
2427 549 : return std::move (ret.value ());
2428 : else
2429 : return tl::unexpected<Parse::Error::Expr> (
2430 0 : Parse::Error::Expr::CHILD_ERROR);
2431 549 : }
2432 1 : case TRY:
2433 : // FIXME: is this really a null denotation expression?
2434 : {
2435 1 : auto ret = parse_try_expr (std::move (outer_attrs), tok->get_locus ());
2436 1 : if (ret)
2437 1 : return std::move (ret.value ());
2438 : else
2439 : return tl::unexpected<Parse::Error::Expr> (
2440 0 : Parse::Error::Expr::CHILD_ERROR);
2441 1 : }
2442 83 : case BREAK:
2443 : // FIXME: is this really a null denotation expression?
2444 : {
2445 83 : auto ret
2446 83 : = parse_break_expr (std::move (outer_attrs), tok->get_locus ());
2447 83 : if (ret)
2448 83 : return std::move (ret.value ());
2449 : else
2450 : return tl::unexpected<Parse::Error::Expr> (
2451 0 : Parse::Error::Expr::CHILD_ERROR);
2452 83 : }
2453 17 : case CONTINUE:
2454 17 : return parse_continue_expr (std::move (outer_attrs), tok->get_locus ());
2455 1546 : case LEFT_CURLY:
2456 : // ok - this is an expression with block for once.
2457 : {
2458 1546 : auto ret = parse_block_expr (std::move (outer_attrs), tl::nullopt,
2459 : tok->get_locus ());
2460 1546 : if (ret)
2461 1545 : return std::move (ret.value ());
2462 : else
2463 : return tl::unexpected<Parse::Error::Expr> (
2464 1 : Parse::Error::Expr::CHILD_ERROR);
2465 1546 : }
2466 2176 : case IF:
2467 : // if or if let, so more lookahead to find out
2468 4352 : if (lexer.peek_token ()->get_id () == LET)
2469 : {
2470 : // if let expr
2471 30 : auto ret
2472 30 : = parse_if_let_expr (std::move (outer_attrs), tok->get_locus ());
2473 30 : if (ret)
2474 30 : return std::move (ret.value ());
2475 : else
2476 : return tl::unexpected<Parse::Error::Expr> (
2477 0 : Parse::Error::Expr::CHILD_ERROR);
2478 30 : }
2479 : else
2480 : {
2481 : // if expr
2482 2146 : auto ret = parse_if_expr (std::move (outer_attrs), tok->get_locus ());
2483 2146 : if (ret)
2484 2145 : return std::move (ret.value ());
2485 : else
2486 : return tl::unexpected<Parse::Error::Expr> (
2487 1 : Parse::Error::Expr::CHILD_ERROR);
2488 2146 : }
2489 45 : case LIFETIME:
2490 : {
2491 135 : auto ret = parse_labelled_loop_expr (tok, std::move (outer_attrs));
2492 45 : if (ret)
2493 45 : return std::move (ret.value ());
2494 : else
2495 : return tl::unexpected<Parse::Error::Expr> (
2496 0 : Parse::Error::Expr::CHILD_ERROR);
2497 45 : }
2498 79 : case LOOP:
2499 : {
2500 79 : auto ret = parse_loop_expr (std::move (outer_attrs), tl::nullopt,
2501 : tok->get_locus ());
2502 79 : if (ret)
2503 78 : return std::move (ret.value ());
2504 : else
2505 : return tl::unexpected<Parse::Error::Expr> (
2506 1 : Parse::Error::Expr::CHILD_ERROR);
2507 79 : }
2508 81 : case WHILE:
2509 162 : if (lexer.peek_token ()->get_id () == LET)
2510 : {
2511 4 : auto ret = parse_while_let_loop_expr (std::move (outer_attrs));
2512 4 : if (ret)
2513 3 : return std::move (ret.value ());
2514 : else
2515 : return tl::unexpected<Parse::Error::Expr> (
2516 1 : Parse::Error::Expr::CHILD_ERROR);
2517 4 : }
2518 : else
2519 : {
2520 77 : auto ret = parse_while_loop_expr (std::move (outer_attrs),
2521 154 : tl::nullopt, tok->get_locus ());
2522 77 : if (ret)
2523 77 : return std::move (ret.value ());
2524 : else
2525 : return tl::unexpected<Parse::Error::Expr> (
2526 0 : Parse::Error::Expr::CHILD_ERROR);
2527 77 : }
2528 20 : case FOR:
2529 : {
2530 20 : auto ret = parse_for_loop_expr (std::move (outer_attrs), tl::nullopt);
2531 20 : if (ret)
2532 20 : return std::move (ret.value ());
2533 : else
2534 : return tl::unexpected<Parse::Error::Expr> (
2535 0 : Parse::Error::Expr::CHILD_ERROR);
2536 20 : }
2537 920 : case MATCH_KW:
2538 : // also an expression with block
2539 : {
2540 920 : auto ret
2541 920 : = parse_match_expr (std::move (outer_attrs), tok->get_locus ());
2542 920 : if (ret)
2543 916 : return std::move (ret.value ());
2544 : else
2545 : return tl::unexpected<Parse::Error::Expr> (
2546 4 : Parse::Error::Expr::CHILD_ERROR);
2547 920 : }
2548 :
2549 410 : case LEFT_SQUARE:
2550 : // array definition expr (not indexing)
2551 : {
2552 410 : auto ret
2553 410 : = parse_array_expr (std::move (outer_attrs), tok->get_locus ());
2554 410 : if (ret)
2555 410 : return std::move (ret.value ());
2556 : else
2557 : return tl::unexpected<Parse::Error::Expr> (
2558 0 : Parse::Error::Expr::CHILD_ERROR);
2559 410 : }
2560 3690 : case UNSAFE:
2561 : {
2562 3690 : auto ret = parse_unsafe_block_expr (std::move (outer_attrs),
2563 : tok->get_locus ());
2564 3690 : if (ret)
2565 3690 : return std::move (ret.value ());
2566 : else
2567 : return tl::unexpected<Parse::Error::Expr> (
2568 0 : Parse::Error::Expr::CHILD_ERROR);
2569 3690 : }
2570 5 : case BOX:
2571 : {
2572 5 : auto ret = parse_box_expr (std::move (outer_attrs), tok->get_locus ());
2573 5 : if (ret)
2574 5 : return std::move (ret.value ());
2575 : else
2576 : return tl::unexpected<Parse::Error::Expr> (
2577 0 : Parse::Error::Expr::CHILD_ERROR);
2578 5 : }
2579 1 : case UNDERSCORE:
2580 1 : add_error (
2581 1 : Error (tok->get_locus (),
2582 : "use of %qs is not allowed on the right-side of an assignment",
2583 : tok->get_token_description ()));
2584 1 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
2585 15 : case CONST:
2586 : {
2587 15 : auto ret
2588 15 : = parse_const_block_expr (std::move (outer_attrs), tok->get_locus ());
2589 15 : if (ret)
2590 15 : return std::move (ret.value ());
2591 : else
2592 : return tl::unexpected<Parse::Error::Expr> (
2593 0 : Parse::Error::Expr::CHILD_ERROR);
2594 15 : }
2595 49 : default:
2596 49 : if (!restrictions.expr_can_be_null)
2597 49 : add_error (Error (tok->get_locus (),
2598 : "found unexpected token %qs in null denotation",
2599 : tok->get_token_description ()));
2600 49 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
2601 : }
2602 : }
2603 :
2604 : /* Called for each token that can appear in infix (between) position. Can be
2605 : * operators or other punctuation. Returns a function pointer to member
2606 : * function that implements the left denotation for the token given. */
2607 : template <typename ManagedTokenSource>
2608 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
2609 27137 : Parser<ManagedTokenSource>::left_denotation (const_TokenPtr tok,
2610 : std::unique_ptr<AST::Expr> left,
2611 : AST::AttrVec outer_attrs,
2612 : ParseRestrictions restrictions)
2613 : {
2614 : // Token passed in has already been skipped, so peek gives "next" token
2615 27137 : switch (tok->get_id ())
2616 : {
2617 : // FIXME: allow for outer attributes to be applied
2618 1 : case QUESTION_MARK:
2619 : {
2620 1 : location_t left_locus = left->get_locus ();
2621 : // error propagation expression - unary postfix
2622 1 : return std::make_unique<AST::ErrorPropagationExpr> (
2623 1 : std::move (left), std::move (outer_attrs), left_locus);
2624 : }
2625 3050 : case PLUS:
2626 : // sum expression - binary infix
2627 : /*return parse_binary_plus_expr (tok, std::move (left),
2628 : std::move (outer_attrs), restrictions);*/
2629 12200 : return parse_arithmetic_or_logical_expr (tok, std::move (left),
2630 : std::move (outer_attrs),
2631 : ArithmeticOrLogicalOperator::ADD,
2632 3050 : restrictions);
2633 1027 : case MINUS:
2634 : // difference expression - binary infix
2635 : /*return parse_binary_minus_expr (tok, std::move (left),
2636 : std::move (outer_attrs),
2637 : restrictions);*/
2638 4108 : return parse_arithmetic_or_logical_expr (
2639 : tok, std::move (left), std::move (outer_attrs),
2640 1027 : ArithmeticOrLogicalOperator::SUBTRACT, restrictions);
2641 242 : case ASTERISK:
2642 : // product expression - binary infix
2643 : /*return parse_binary_mult_expr (tok, std::move (left),
2644 : std::move (outer_attrs), restrictions);*/
2645 968 : return parse_arithmetic_or_logical_expr (
2646 : tok, std::move (left), std::move (outer_attrs),
2647 242 : ArithmeticOrLogicalOperator::MULTIPLY, restrictions);
2648 34 : case DIV:
2649 : // quotient expression - binary infix
2650 : /*return parse_binary_div_expr (tok, std::move (left),
2651 : std::move (outer_attrs), restrictions);*/
2652 136 : return parse_arithmetic_or_logical_expr (
2653 : tok, std::move (left), std::move (outer_attrs),
2654 34 : ArithmeticOrLogicalOperator::DIVIDE, restrictions);
2655 36 : case PERCENT:
2656 : // modulo expression - binary infix
2657 : /*return parse_binary_mod_expr (tok, std::move (left),
2658 : std::move (outer_attrs), restrictions);*/
2659 144 : return parse_arithmetic_or_logical_expr (
2660 : tok, std::move (left), std::move (outer_attrs),
2661 36 : ArithmeticOrLogicalOperator::MODULUS, restrictions);
2662 52 : case AMP:
2663 : // logical or bitwise and expression - binary infix
2664 : /*return parse_bitwise_and_expr (tok, std::move (left),
2665 : std::move (outer_attrs), restrictions);*/
2666 208 : return parse_arithmetic_or_logical_expr (
2667 : tok, std::move (left), std::move (outer_attrs),
2668 52 : ArithmeticOrLogicalOperator::BITWISE_AND, restrictions);
2669 25 : case PIPE:
2670 : // logical or bitwise or expression - binary infix
2671 : /*return parse_bitwise_or_expr (tok, std::move (left),
2672 : std::move (outer_attrs), restrictions);*/
2673 100 : return parse_arithmetic_or_logical_expr (
2674 : tok, std::move (left), std::move (outer_attrs),
2675 25 : ArithmeticOrLogicalOperator::BITWISE_OR, restrictions);
2676 63 : case CARET:
2677 : // logical or bitwise xor expression - binary infix
2678 : /*return parse_bitwise_xor_expr (tok, std::move (left),
2679 : std::move (outer_attrs), restrictions);*/
2680 252 : return parse_arithmetic_or_logical_expr (
2681 : tok, std::move (left), std::move (outer_attrs),
2682 63 : ArithmeticOrLogicalOperator::BITWISE_XOR, restrictions);
2683 51 : case LEFT_SHIFT:
2684 : // left shift expression - binary infix
2685 : /*return parse_left_shift_expr (tok, std::move (left),
2686 : std::move (outer_attrs), restrictions);*/
2687 204 : return parse_arithmetic_or_logical_expr (
2688 : tok, std::move (left), std::move (outer_attrs),
2689 51 : ArithmeticOrLogicalOperator::LEFT_SHIFT, restrictions);
2690 19 : case RIGHT_SHIFT:
2691 : // right shift expression - binary infix
2692 : /*return parse_right_shift_expr (tok, std::move (left),
2693 : std::move (outer_attrs), restrictions);*/
2694 76 : return parse_arithmetic_or_logical_expr (
2695 : tok, std::move (left), std::move (outer_attrs),
2696 19 : ArithmeticOrLogicalOperator::RIGHT_SHIFT, restrictions);
2697 679 : case EQUAL_EQUAL:
2698 : // equal to expression - binary infix (no associativity)
2699 : /*return parse_binary_equal_expr (tok, std::move (left),
2700 : std::move (outer_attrs),
2701 : restrictions);*/
2702 2716 : return parse_comparison_expr (tok, std::move (left),
2703 : std::move (outer_attrs),
2704 679 : ComparisonOperator::EQUAL, restrictions);
2705 1011 : case NOT_EQUAL:
2706 : // not equal to expression - binary infix (no associativity)
2707 : /*return parse_binary_not_equal_expr (tok, std::move (left),
2708 : std::move (outer_attrs),
2709 : restrictions);*/
2710 4044 : return parse_comparison_expr (tok, std::move (left),
2711 : std::move (outer_attrs),
2712 : ComparisonOperator::NOT_EQUAL,
2713 1011 : restrictions);
2714 643 : case RIGHT_ANGLE:
2715 : // greater than expression - binary infix (no associativity)
2716 : /*return parse_binary_greater_than_expr (tok, std::move (left),
2717 : std::move (outer_attrs),
2718 : restrictions);*/
2719 2572 : return parse_comparison_expr (tok, std::move (left),
2720 : std::move (outer_attrs),
2721 : ComparisonOperator::GREATER_THAN,
2722 643 : restrictions);
2723 623 : case LEFT_ANGLE:
2724 : // less than expression - binary infix (no associativity)
2725 : /*return parse_binary_less_than_expr (tok, std::move (left),
2726 : std::move (outer_attrs),
2727 : restrictions);*/
2728 2492 : return parse_comparison_expr (tok, std::move (left),
2729 : std::move (outer_attrs),
2730 : ComparisonOperator::LESS_THAN,
2731 623 : restrictions);
2732 190 : case GREATER_OR_EQUAL:
2733 : // greater than or equal to expression - binary infix (no associativity)
2734 : /*return parse_binary_greater_equal_expr (tok, std::move (left),
2735 : std::move (outer_attrs),
2736 : restrictions);*/
2737 760 : return parse_comparison_expr (tok, std::move (left),
2738 : std::move (outer_attrs),
2739 : ComparisonOperator::GREATER_OR_EQUAL,
2740 190 : restrictions);
2741 224 : case LESS_OR_EQUAL:
2742 : // less than or equal to expression - binary infix (no associativity)
2743 : /*return parse_binary_less_equal_expr (tok, std::move (left),
2744 : std::move (outer_attrs),
2745 : restrictions);*/
2746 896 : return parse_comparison_expr (tok, std::move (left),
2747 : std::move (outer_attrs),
2748 : ComparisonOperator::LESS_OR_EQUAL,
2749 224 : restrictions);
2750 71 : case OR:
2751 : // lazy logical or expression - binary infix
2752 284 : return parse_lazy_or_expr (tok, std::move (left), std::move (outer_attrs),
2753 71 : restrictions);
2754 263 : case LOGICAL_AND:
2755 : // lazy logical and expression - binary infix
2756 1052 : return parse_lazy_and_expr (tok, std::move (left),
2757 263 : std::move (outer_attrs), restrictions);
2758 5271 : case AS:
2759 : /* type cast expression - kind of binary infix (RHS is actually a
2760 : * TypeNoBounds) */
2761 21084 : return parse_type_cast_expr (tok, std::move (left),
2762 5271 : std::move (outer_attrs), restrictions);
2763 2527 : case EQUAL:
2764 : // assignment expression - binary infix (note right-to-left
2765 : // associativity)
2766 10108 : return parse_assig_expr (tok, std::move (left), std::move (outer_attrs),
2767 2527 : restrictions);
2768 160 : case PLUS_EQ:
2769 : /* plus-assignment expression - binary infix (note right-to-left
2770 : * associativity) */
2771 : /*return parse_plus_assig_expr (tok, std::move (left),
2772 : std::move (outer_attrs), restrictions);*/
2773 640 : return parse_compound_assignment_expr (tok, std::move (left),
2774 : std::move (outer_attrs),
2775 : CompoundAssignmentOperator::ADD,
2776 160 : restrictions);
2777 105 : case MINUS_EQ:
2778 : /* minus-assignment expression - binary infix (note right-to-left
2779 : * associativity) */
2780 : /*return parse_minus_assig_expr (tok, std::move (left),
2781 : std::move (outer_attrs), restrictions);*/
2782 420 : return parse_compound_assignment_expr (
2783 : tok, std::move (left), std::move (outer_attrs),
2784 105 : CompoundAssignmentOperator::SUBTRACT, restrictions);
2785 7 : case ASTERISK_EQ:
2786 : /* multiply-assignment expression - binary infix (note right-to-left
2787 : * associativity) */
2788 : /*return parse_mult_assig_expr (tok, std::move (left),
2789 : std::move (outer_attrs), restrictions);*/
2790 28 : return parse_compound_assignment_expr (
2791 : tok, std::move (left), std::move (outer_attrs),
2792 7 : CompoundAssignmentOperator::MULTIPLY, restrictions);
2793 7 : case DIV_EQ:
2794 : /* division-assignment expression - binary infix (note right-to-left
2795 : * associativity) */
2796 : /*return parse_div_assig_expr (tok, std::move (left),
2797 : std::move (outer_attrs), restrictions);*/
2798 28 : return parse_compound_assignment_expr (tok, std::move (left),
2799 : std::move (outer_attrs),
2800 : CompoundAssignmentOperator::DIVIDE,
2801 7 : restrictions);
2802 7 : case PERCENT_EQ:
2803 : /* modulo-assignment expression - binary infix (note right-to-left
2804 : * associativity) */
2805 : /*return parse_mod_assig_expr (tok, std::move (left),
2806 : std::move (outer_attrs), restrictions);*/
2807 28 : return parse_compound_assignment_expr (
2808 : tok, std::move (left), std::move (outer_attrs),
2809 7 : CompoundAssignmentOperator::MODULUS, restrictions);
2810 21 : case AMP_EQ:
2811 : /* bitwise and-assignment expression - binary infix (note right-to-left
2812 : * associativity) */
2813 : /*return parse_and_assig_expr (tok, std::move (left),
2814 : std::move (outer_attrs), restrictions);*/
2815 84 : return parse_compound_assignment_expr (
2816 : tok, std::move (left), std::move (outer_attrs),
2817 21 : CompoundAssignmentOperator::BITWISE_AND, restrictions);
2818 28 : case PIPE_EQ:
2819 : /* bitwise or-assignment expression - binary infix (note right-to-left
2820 : * associativity) */
2821 : /*return parse_or_assig_expr (tok, std::move (left),
2822 : std::move (outer_attrs), restrictions);*/
2823 112 : return parse_compound_assignment_expr (
2824 : tok, std::move (left), std::move (outer_attrs),
2825 28 : CompoundAssignmentOperator::BITWISE_OR, restrictions);
2826 336 : case CARET_EQ:
2827 : /* bitwise xor-assignment expression - binary infix (note right-to-left
2828 : * associativity) */
2829 : /*return parse_xor_assig_expr (tok, std::move (left),
2830 : std::move (outer_attrs), restrictions);*/
2831 1344 : return parse_compound_assignment_expr (
2832 : tok, std::move (left), std::move (outer_attrs),
2833 336 : CompoundAssignmentOperator::BITWISE_XOR, restrictions);
2834 7 : case LEFT_SHIFT_EQ:
2835 : /* left shift-assignment expression - binary infix (note right-to-left
2836 : * associativity) */
2837 : /*return parse_left_shift_assig_expr (tok, std::move (left),
2838 : std::move (outer_attrs),
2839 : restrictions);*/
2840 28 : return parse_compound_assignment_expr (
2841 : tok, std::move (left), std::move (outer_attrs),
2842 7 : CompoundAssignmentOperator::LEFT_SHIFT, restrictions);
2843 7 : case RIGHT_SHIFT_EQ:
2844 : /* right shift-assignment expression - binary infix (note right-to-left
2845 : * associativity) */
2846 : /*return parse_right_shift_assig_expr (tok, std::move (left),
2847 : std::move (outer_attrs),
2848 : restrictions);*/
2849 28 : return parse_compound_assignment_expr (
2850 : tok, std::move (left), std::move (outer_attrs),
2851 7 : CompoundAssignmentOperator::RIGHT_SHIFT, restrictions);
2852 78 : case DOT_DOT:
2853 : /* range exclusive expression - binary infix (no associativity)
2854 : * either "range" or "range from" */
2855 312 : return parse_led_range_exclusive_expr (tok, std::move (left),
2856 : std::move (outer_attrs),
2857 78 : restrictions);
2858 7 : case DOT_DOT_EQ:
2859 : /* range inclusive expression - binary infix (no associativity)
2860 : * unambiguously RangeInclusiveExpr */
2861 28 : return parse_range_inclusive_expr (tok, std::move (left),
2862 7 : std::move (outer_attrs), restrictions);
2863 0 : case SCOPE_RESOLUTION:
2864 : // path expression - binary infix? FIXME should this even be parsed
2865 : // here?
2866 0 : add_error (
2867 0 : Error (tok->get_locus (),
2868 : "found scope resolution operator in left denotation "
2869 : "function - this should probably be handled elsewhere"));
2870 :
2871 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
2872 8983 : case DOT:
2873 : {
2874 : /* field expression or method call - relies on parentheses after next
2875 : * identifier or await if token after is "await" (unary postfix) or
2876 : * tuple index if token after is a decimal int literal */
2877 :
2878 8983 : const_TokenPtr next_tok = lexer.peek_token ();
2879 8983 : if (next_tok->get_id () == IDENTIFIER
2880 8983 : && next_tok->get_str () == Values::Keywords::AWAIT)
2881 : {
2882 : // await expression
2883 0 : return parse_await_expr (tok, std::move (left),
2884 0 : std::move (outer_attrs));
2885 : }
2886 8983 : else if (next_tok->get_id () == INT_LITERAL)
2887 : {
2888 : // tuple index expression - TODO check for decimal int literal
2889 3612 : return parse_tuple_index_expr (tok, std::move (left),
2890 : std::move (outer_attrs),
2891 903 : restrictions);
2892 : }
2893 8080 : else if (next_tok->get_id () == FLOAT_LITERAL)
2894 : {
2895 : // Lexer has misidentified a tuple index as a float literal
2896 : // eg: `(x, (y, z)).1.0` -> 1.0 has been identified as a float
2897 : // literal. This means we should split it into three new separate
2898 : // tokens, the first tuple index, the dot and the second tuple
2899 : // index.
2900 2 : auto current_loc = next_tok->get_locus ();
2901 2 : auto str = next_tok->get_str ();
2902 2 : auto dot_pos = str.find (".");
2903 2 : auto prefix = str.substr (0, dot_pos);
2904 2 : auto suffix = str.substr (dot_pos + 1);
2905 2 : if (dot_pos == str.size () - 1)
2906 : {
2907 1 : auto prefix_len = prefix.length ();
2908 3 : lexer.split_current_token (
2909 2 : {Token::make_int (current_loc, std::move (prefix), prefix_len,
2910 : IntegerLiteralBase::Decimal,
2911 : CORETYPE_PURE_DECIMAL),
2912 : Token::make (DOT, current_loc + 1)});
2913 : }
2914 : else
2915 : {
2916 1 : auto prefix_len = prefix.length ();
2917 1 : auto suffix_len = suffix.length ();
2918 5 : lexer.split_current_token (
2919 2 : {Token::make_int (current_loc, std::move (prefix), prefix_len,
2920 : IntegerLiteralBase::Decimal,
2921 : CORETYPE_PURE_DECIMAL),
2922 : Token::make (DOT, current_loc + 1),
2923 2 : Token::make_int (current_loc + 2, std::move (suffix),
2924 : suffix_len, IntegerLiteralBase::Decimal,
2925 : CORETYPE_PURE_DECIMAL)});
2926 : }
2927 8 : return parse_tuple_index_expr (tok, std::move (left),
2928 : std::move (outer_attrs),
2929 2 : restrictions);
2930 2 : }
2931 12617 : else if (next_tok->get_id () == IDENTIFIER
2932 18578 : && lexer.peek_token (1)->get_id () != LEFT_PAREN
2933 19051 : && lexer.peek_token (1)->get_id () != SCOPE_RESOLUTION)
2934 : {
2935 : /* field expression (or should be) - FIXME: scope resolution right
2936 : * after identifier should always be method, I'm pretty sure */
2937 19928 : return parse_field_access_expr (tok, std::move (left),
2938 : std::move (outer_attrs),
2939 4982 : restrictions);
2940 : }
2941 : else
2942 : {
2943 : // method call (probably)
2944 12384 : return parse_method_call_expr (tok, std::move (left),
2945 : std::move (outer_attrs),
2946 3096 : restrictions);
2947 : }
2948 8983 : }
2949 979 : case LEFT_PAREN:
2950 : // function call - method call is based on dot notation first
2951 3916 : return parse_function_call_expr (tok, std::move (left),
2952 979 : std::move (outer_attrs), restrictions);
2953 303 : case LEFT_SQUARE:
2954 : // array or slice index expression (pseudo binary infix)
2955 1212 : return parse_index_expr (tok, std::move (left), std::move (outer_attrs),
2956 303 : restrictions);
2957 0 : default:
2958 0 : add_error (Error (tok->get_locus (),
2959 : "found unexpected token %qs in left denotation",
2960 : tok->get_token_description ()));
2961 :
2962 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
2963 : }
2964 : }
2965 :
2966 : /* Returns the left binding power for the given ArithmeticOrLogicalExpr type.
2967 : * TODO make constexpr? Would that even do anything useful? */
2968 : inline binding_powers
2969 4599 : get_lbp_for_arithmetic_or_logical_expr (
2970 : AST::ArithmeticOrLogicalExpr::ExprType expr_type)
2971 : {
2972 4599 : switch (expr_type)
2973 : {
2974 : case ArithmeticOrLogicalOperator::ADD:
2975 : return LBP_PLUS;
2976 : case ArithmeticOrLogicalOperator::SUBTRACT:
2977 : return LBP_MINUS;
2978 : case ArithmeticOrLogicalOperator::MULTIPLY:
2979 : return LBP_MUL;
2980 : case ArithmeticOrLogicalOperator::DIVIDE:
2981 : return LBP_DIV;
2982 : case ArithmeticOrLogicalOperator::MODULUS:
2983 : return LBP_MOD;
2984 : case ArithmeticOrLogicalOperator::BITWISE_AND:
2985 : return LBP_AMP;
2986 : case ArithmeticOrLogicalOperator::BITWISE_OR:
2987 : return LBP_PIPE;
2988 : case ArithmeticOrLogicalOperator::BITWISE_XOR:
2989 : return LBP_CARET;
2990 : case ArithmeticOrLogicalOperator::LEFT_SHIFT:
2991 : return LBP_L_SHIFT;
2992 : case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
2993 : return LBP_R_SHIFT;
2994 0 : default:
2995 : // WTF? should not happen, this is an error
2996 0 : rust_unreachable ();
2997 :
2998 : return LBP_PLUS;
2999 : }
3000 : }
3001 :
3002 : // Parses an arithmetic or logical expression (with Pratt parsing).
3003 : template <typename ManagedTokenSource>
3004 : tl::expected<std::unique_ptr<AST::ArithmeticOrLogicalExpr>, Parse::Error::Expr>
3005 4599 : Parser<ManagedTokenSource>::parse_arithmetic_or_logical_expr (
3006 : const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
3007 : AST::ArithmeticOrLogicalExpr::ExprType expr_type,
3008 : ParseRestrictions restrictions)
3009 : {
3010 : // parse RHS (as tok has already been consumed in parse_expression)
3011 4599 : auto right = parse_expr (get_lbp_for_arithmetic_or_logical_expr (expr_type),
3012 9198 : AST::AttrVec (), restrictions);
3013 4599 : if (!right)
3014 2 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3015 :
3016 : // TODO: check types. actually, do so during semantic analysis
3017 4597 : location_t locus = left->get_locus ();
3018 :
3019 4597 : return std::make_unique<AST::ArithmeticOrLogicalExpr> (
3020 9194 : std::move (left), std::move (right.value ()), expr_type, locus);
3021 4599 : }
3022 :
3023 : // Parses a binary addition expression (with Pratt parsing).
3024 : template <typename ManagedTokenSource>
3025 : tl::expected<std::unique_ptr<AST::ArithmeticOrLogicalExpr>, Parse::Error::Expr>
3026 0 : Parser<ManagedTokenSource>::parse_binary_plus_expr (
3027 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3028 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3029 : {
3030 : // parse RHS (as tok has already been consumed in parse_expression)
3031 0 : auto right = parse_expr (LBP_PLUS, AST::AttrVec (), restrictions);
3032 0 : if (!right)
3033 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3034 :
3035 : // TODO: check types. actually, do so during semantic analysis
3036 0 : location_t locus = left->get_locus ();
3037 :
3038 0 : return std::make_unique<AST::ArithmeticOrLogicalExpr> (
3039 0 : std::move (left), std::move (right.value ()),
3040 0 : ArithmeticOrLogicalOperator::ADD, locus);
3041 0 : }
3042 :
3043 : // Parses a binary subtraction expression (with Pratt parsing).
3044 : template <typename ManagedTokenSource>
3045 : tl::expected<std::unique_ptr<AST::ArithmeticOrLogicalExpr>, Parse::Error::Expr>
3046 0 : Parser<ManagedTokenSource>::parse_binary_minus_expr (
3047 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3048 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3049 : {
3050 : // parse RHS (as tok has already been consumed in parse_expression)
3051 0 : auto right = parse_expr (LBP_MINUS, AST::AttrVec (), restrictions);
3052 0 : if (!right)
3053 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3054 :
3055 : // TODO: check types. actually, do so during semantic analysis
3056 0 : location_t locus = left->get_locus ();
3057 :
3058 0 : return std::make_unique<AST::ArithmeticOrLogicalExpr> (
3059 0 : std::move (left), std::move (right.value ()),
3060 0 : ArithmeticOrLogicalOperator::SUBTRACT, locus);
3061 0 : }
3062 :
3063 : // Parses a binary multiplication expression (with Pratt parsing).
3064 : template <typename ManagedTokenSource>
3065 : tl::expected<std::unique_ptr<AST::ArithmeticOrLogicalExpr>, Parse::Error::Expr>
3066 0 : Parser<ManagedTokenSource>::parse_binary_mult_expr (
3067 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3068 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3069 : {
3070 : // parse RHS (as tok has already been consumed in parse_expression)
3071 0 : auto right = parse_expr (LBP_MUL, AST::AttrVec (), restrictions);
3072 0 : if (!right)
3073 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3074 :
3075 : // TODO: check types. actually, do so during semantic analysis
3076 0 : location_t locus = left->get_locus ();
3077 :
3078 0 : return std::make_unique<AST::ArithmeticOrLogicalExpr> (
3079 0 : std::move (left), std::move (right.value ()),
3080 0 : ArithmeticOrLogicalOperator::MULTIPLY, locus);
3081 0 : }
3082 :
3083 : // Parses a binary division expression (with Pratt parsing).
3084 : template <typename ManagedTokenSource>
3085 : tl::expected<std::unique_ptr<AST::ArithmeticOrLogicalExpr>, Parse::Error::Expr>
3086 0 : Parser<ManagedTokenSource>::parse_binary_div_expr (
3087 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3088 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3089 : {
3090 : // parse RHS (as tok has already been consumed in parse_expression)
3091 0 : auto right = parse_expr (LBP_DIV, AST::AttrVec (), restrictions);
3092 0 : if (!right)
3093 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3094 :
3095 : // TODO: check types. actually, do so during semantic analysis
3096 0 : location_t locus = left->get_locus ();
3097 :
3098 0 : return std::make_unique<AST::ArithmeticOrLogicalExpr> (
3099 0 : std::move (left), std::move (right.value ()),
3100 0 : ArithmeticOrLogicalOperator::DIVIDE, locus);
3101 0 : }
3102 :
3103 : // Parses a binary modulo expression (with Pratt parsing).
3104 : template <typename ManagedTokenSource>
3105 : tl::expected<std::unique_ptr<AST::ArithmeticOrLogicalExpr>, Parse::Error::Expr>
3106 0 : Parser<ManagedTokenSource>::parse_binary_mod_expr (
3107 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3108 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3109 : {
3110 : // parse RHS (as tok has already been consumed in parse_expression)
3111 0 : auto right = parse_expr (LBP_MOD, AST::AttrVec (), restrictions);
3112 0 : if (!right)
3113 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3114 :
3115 : // TODO: check types. actually, do so during semantic analysis
3116 0 : location_t locus = left->get_locus ();
3117 :
3118 0 : return std::make_unique<AST::ArithmeticOrLogicalExpr> (
3119 0 : std::move (left), std::move (right.value ()),
3120 0 : ArithmeticOrLogicalOperator::MODULUS, locus);
3121 0 : }
3122 :
3123 : /* Parses a binary bitwise (or eager logical) and expression (with Pratt
3124 : * parsing). */
3125 : template <typename ManagedTokenSource>
3126 : tl::expected<std::unique_ptr<AST::ArithmeticOrLogicalExpr>, Parse::Error::Expr>
3127 0 : Parser<ManagedTokenSource>::parse_bitwise_and_expr (
3128 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3129 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3130 : {
3131 : // parse RHS (as tok has already been consumed in parse_expression)
3132 0 : auto right = parse_expr (LBP_AMP, AST::AttrVec (), restrictions);
3133 0 : if (!right)
3134 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3135 :
3136 : // TODO: check types. actually, do so during semantic analysis
3137 0 : location_t locus = left->get_locus ();
3138 :
3139 0 : return std::make_unique<AST::ArithmeticOrLogicalExpr> (
3140 0 : std::move (left), std::move (right.value ()),
3141 0 : ArithmeticOrLogicalOperator::BITWISE_AND, locus);
3142 0 : }
3143 :
3144 : /* Parses a binary bitwise (or eager logical) or expression (with Pratt
3145 : * parsing). */
3146 : template <typename ManagedTokenSource>
3147 : tl::expected<std::unique_ptr<AST::ArithmeticOrLogicalExpr>, Parse::Error::Expr>
3148 0 : Parser<ManagedTokenSource>::parse_bitwise_or_expr (
3149 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3150 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3151 : {
3152 : // parse RHS (as tok has already been consumed in parse_expression)
3153 0 : auto right = parse_expr (LBP_PIPE, AST::AttrVec (), restrictions);
3154 0 : if (!right)
3155 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3156 :
3157 : // TODO: check types. actually, do so during semantic analysis
3158 0 : location_t locus = left->get_locus ();
3159 :
3160 0 : return std::make_unique<AST::ArithmeticOrLogicalExpr> (
3161 0 : std::move (left), std::move (right.value ()),
3162 0 : ArithmeticOrLogicalOperator::BITWISE_OR, locus);
3163 0 : }
3164 :
3165 : /* Parses a binary bitwise (or eager logical) xor expression (with Pratt
3166 : * parsing). */
3167 : template <typename ManagedTokenSource>
3168 : tl::expected<std::unique_ptr<AST::ArithmeticOrLogicalExpr>, Parse::Error::Expr>
3169 0 : Parser<ManagedTokenSource>::parse_bitwise_xor_expr (
3170 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3171 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3172 : {
3173 : // parse RHS (as tok has already been consumed in parse_expression)
3174 0 : auto right = parse_expr (LBP_CARET, AST::AttrVec (), restrictions);
3175 0 : if (!right)
3176 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3177 :
3178 : // TODO: check types. actually, do so during semantic analysis
3179 0 : location_t locus = left->get_locus ();
3180 :
3181 0 : return std::make_unique<AST::ArithmeticOrLogicalExpr> (
3182 0 : std::move (left), std::move (right.value ()),
3183 0 : ArithmeticOrLogicalOperator::BITWISE_XOR, locus);
3184 0 : }
3185 :
3186 : // Parses a binary left shift expression (with Pratt parsing).
3187 : template <typename ManagedTokenSource>
3188 : tl::expected<std::unique_ptr<AST::ArithmeticOrLogicalExpr>, Parse::Error::Expr>
3189 0 : Parser<ManagedTokenSource>::parse_left_shift_expr (
3190 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3191 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3192 : {
3193 : // parse RHS (as tok has already been consumed in parse_expression)
3194 0 : auto right = parse_expr (LBP_L_SHIFT, AST::AttrVec (), restrictions);
3195 0 : if (!right)
3196 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3197 :
3198 : // TODO: check types. actually, do so during semantic analysis
3199 0 : location_t locus = left->get_locus ();
3200 :
3201 0 : return std::make_unique<AST::ArithmeticOrLogicalExpr> (
3202 0 : std::move (left), std::move (right.value ()),
3203 0 : ArithmeticOrLogicalOperator::LEFT_SHIFT, locus);
3204 0 : }
3205 :
3206 : // Parses a binary right shift expression (with Pratt parsing).
3207 : template <typename ManagedTokenSource>
3208 : tl::expected<std::unique_ptr<AST::ArithmeticOrLogicalExpr>, Parse::Error::Expr>
3209 0 : Parser<ManagedTokenSource>::parse_right_shift_expr (
3210 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3211 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3212 : {
3213 : // parse RHS (as tok has already been consumed in parse_expression)
3214 0 : auto right = parse_expr (LBP_R_SHIFT, AST::AttrVec (), restrictions);
3215 0 : if (!right)
3216 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3217 :
3218 : // TODO: check types. actually, do so during semantic analysis
3219 0 : location_t locus = left->get_locus ();
3220 :
3221 0 : return std::make_unique<AST::ArithmeticOrLogicalExpr> (
3222 0 : std::move (left), std::move (right.value ()),
3223 0 : ArithmeticOrLogicalOperator::RIGHT_SHIFT, locus);
3224 0 : }
3225 :
3226 : /* Returns the left binding power for the given ComparisonExpr type.
3227 : * TODO make constexpr? Would that even do anything useful? */
3228 : inline binding_powers
3229 3370 : get_lbp_for_comparison_expr (AST::ComparisonExpr::ExprType expr_type)
3230 : {
3231 3370 : switch (expr_type)
3232 : {
3233 : case ComparisonOperator::EQUAL:
3234 : return LBP_EQUAL;
3235 : case ComparisonOperator::NOT_EQUAL:
3236 : return LBP_NOT_EQUAL;
3237 : case ComparisonOperator::GREATER_THAN:
3238 : return LBP_GREATER_THAN;
3239 : case ComparisonOperator::LESS_THAN:
3240 : return LBP_SMALLER_THAN;
3241 : case ComparisonOperator::GREATER_OR_EQUAL:
3242 : return LBP_GREATER_EQUAL;
3243 : case ComparisonOperator::LESS_OR_EQUAL:
3244 : return LBP_SMALLER_EQUAL;
3245 0 : default:
3246 : // WTF? should not happen, this is an error
3247 0 : rust_unreachable ();
3248 :
3249 : return LBP_EQUAL;
3250 : }
3251 : }
3252 :
3253 : /* Parses a ComparisonExpr of given type and LBP. TODO find a way to only
3254 : * specify one and have the other looked up - e.g. specify ExprType and
3255 : * binding power is looked up? */
3256 : template <typename ManagedTokenSource>
3257 : tl::expected<std::unique_ptr<AST::ComparisonExpr>, Parse::Error::Expr>
3258 3370 : Parser<ManagedTokenSource>::parse_comparison_expr (
3259 : const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
3260 : AST::ComparisonExpr::ExprType expr_type, ParseRestrictions restrictions)
3261 : {
3262 : // parse RHS (as tok has already been consumed in parse_expression)
3263 3370 : auto right = parse_expr (get_lbp_for_comparison_expr (expr_type),
3264 6740 : AST::AttrVec (), restrictions);
3265 3370 : if (!right)
3266 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3267 :
3268 : // TODO: check types. actually, do so during semantic analysis
3269 3370 : location_t locus = left->get_locus ();
3270 :
3271 3370 : return std::make_unique<AST::ComparisonExpr> (std::move (left),
3272 3370 : std::move (right.value ()),
3273 3370 : expr_type, locus);
3274 3370 : }
3275 :
3276 : // Parses a binary equal to expression (with Pratt parsing).
3277 : template <typename ManagedTokenSource>
3278 : tl::expected<std::unique_ptr<AST::ComparisonExpr>, Parse::Error::Expr>
3279 0 : Parser<ManagedTokenSource>::parse_binary_equal_expr (
3280 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3281 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3282 : {
3283 : // parse RHS (as tok has already been consumed in parse_expression)
3284 0 : auto right = parse_expr (LBP_EQUAL, AST::AttrVec (), restrictions);
3285 0 : if (!right)
3286 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3287 :
3288 : // TODO: check types. actually, do so during semantic analysis
3289 0 : location_t locus = left->get_locus ();
3290 :
3291 0 : return std::make_unique<AST::ComparisonExpr> (std::move (left),
3292 0 : std::move (right.value ()),
3293 0 : ComparisonOperator::EQUAL,
3294 0 : locus);
3295 0 : }
3296 :
3297 : // Parses a binary not equal to expression (with Pratt parsing).
3298 : template <typename ManagedTokenSource>
3299 : tl::expected<std::unique_ptr<AST::ComparisonExpr>, Parse::Error::Expr>
3300 0 : Parser<ManagedTokenSource>::parse_binary_not_equal_expr (
3301 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3302 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3303 : {
3304 : // parse RHS (as tok has already been consumed in parse_expression)
3305 0 : auto right = parse_expr (LBP_NOT_EQUAL, AST::AttrVec (), restrictions);
3306 0 : if (!right)
3307 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3308 :
3309 : // TODO: check types. actually, do so during semantic analysis
3310 0 : location_t locus = left->get_locus ();
3311 :
3312 0 : return std::make_unique<AST::ComparisonExpr> (std::move (left),
3313 0 : std::move (right.value ()),
3314 0 : ComparisonOperator::NOT_EQUAL,
3315 0 : locus);
3316 0 : }
3317 :
3318 : // Parses a binary greater than expression (with Pratt parsing).
3319 : template <typename ManagedTokenSource>
3320 : tl::expected<std::unique_ptr<AST::ComparisonExpr>, Parse::Error::Expr>
3321 0 : Parser<ManagedTokenSource>::parse_binary_greater_than_expr (
3322 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3323 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3324 : {
3325 : // parse RHS (as tok has already been consumed in parse_expression)
3326 0 : auto right = parse_expr (LBP_GREATER_THAN, AST::AttrVec (), restrictions);
3327 0 : if (!right)
3328 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3329 :
3330 : // TODO: check types. actually, do so during semantic analysis
3331 0 : location_t locus = left->get_locus ();
3332 :
3333 0 : return std::make_unique<AST::ComparisonExpr> (
3334 0 : std::move (left), std::move (right.value ()),
3335 0 : ComparisonOperator::GREATER_THAN, locus);
3336 0 : }
3337 :
3338 : // Parses a binary less than expression (with Pratt parsing).
3339 : template <typename ManagedTokenSource>
3340 : tl::expected<std::unique_ptr<AST::ComparisonExpr>, Parse::Error::Expr>
3341 0 : Parser<ManagedTokenSource>::parse_binary_less_than_expr (
3342 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3343 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3344 : {
3345 : // parse RHS (as tok has already been consumed in parse_expression)
3346 0 : auto right = parse_expr (LBP_SMALLER_THAN, AST::AttrVec (), restrictions);
3347 0 : if (!right)
3348 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3349 :
3350 : // TODO: check types. actually, do so during semantic analysis
3351 0 : location_t locus = left->get_locus ();
3352 :
3353 0 : return std::make_unique<AST::ComparisonExpr> (std::move (left),
3354 0 : std::move (right.value ()),
3355 0 : ComparisonOperator::LESS_THAN,
3356 0 : locus);
3357 0 : }
3358 :
3359 : // Parses a binary greater than or equal to expression (with Pratt parsing).
3360 : template <typename ManagedTokenSource>
3361 : tl::expected<std::unique_ptr<AST::ComparisonExpr>, Parse::Error::Expr>
3362 0 : Parser<ManagedTokenSource>::parse_binary_greater_equal_expr (
3363 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3364 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3365 : {
3366 : // parse RHS (as tok has already been consumed in parse_expression)
3367 0 : auto right = parse_expr (LBP_GREATER_EQUAL, AST::AttrVec (), restrictions);
3368 0 : if (!right)
3369 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3370 :
3371 : // TODO: check types. actually, do so during semantic analysis
3372 0 : location_t locus = left->get_locus ();
3373 :
3374 0 : return std::make_unique<AST::ComparisonExpr> (
3375 0 : std::move (left), std::move (right.value ()),
3376 0 : ComparisonOperator::GREATER_OR_EQUAL, locus);
3377 0 : }
3378 :
3379 : // Parses a binary less than or equal to expression (with Pratt parsing).
3380 : template <typename ManagedTokenSource>
3381 : tl::expected<std::unique_ptr<AST::ComparisonExpr>, Parse::Error::Expr>
3382 0 : Parser<ManagedTokenSource>::parse_binary_less_equal_expr (
3383 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3384 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3385 : {
3386 : // parse RHS (as tok has already been consumed in parse_expression)
3387 0 : auto right = parse_expr (LBP_SMALLER_EQUAL, AST::AttrVec (), restrictions);
3388 0 : if (!right)
3389 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3390 :
3391 : // TODO: check types. actually, do so during semantic analysis
3392 0 : location_t locus = left->get_locus ();
3393 :
3394 0 : return std::make_unique<AST::ComparisonExpr> (
3395 0 : std::move (left), std::move (right.value ()),
3396 0 : ComparisonOperator::LESS_OR_EQUAL, locus);
3397 0 : }
3398 :
3399 : // Parses a binary lazy boolean or expression (with Pratt parsing).
3400 : template <typename ManagedTokenSource>
3401 : tl::expected<std::unique_ptr<AST::LazyBooleanExpr>, Parse::Error::Expr>
3402 71 : Parser<ManagedTokenSource>::parse_lazy_or_expr (
3403 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3404 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3405 : {
3406 : // parse RHS (as tok has already been consumed in parse_expression)
3407 71 : auto right = parse_expr (LBP_LOGICAL_OR, AST::AttrVec (), restrictions);
3408 71 : if (!right)
3409 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3410 :
3411 : // TODO: check types. actually, do so during semantic analysis
3412 71 : location_t locus = left->get_locus ();
3413 :
3414 71 : return std::make_unique<AST::LazyBooleanExpr> (
3415 71 : std::move (left), std::move (right.value ()),
3416 142 : LazyBooleanOperator::LOGICAL_OR, locus);
3417 71 : }
3418 :
3419 : // Parses a binary lazy boolean and expression (with Pratt parsing).
3420 : template <typename ManagedTokenSource>
3421 : tl::expected<std::unique_ptr<AST::LazyBooleanExpr>, Parse::Error::Expr>
3422 263 : Parser<ManagedTokenSource>::parse_lazy_and_expr (
3423 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3424 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3425 : {
3426 : // parse RHS (as tok has already been consumed in parse_expression)
3427 263 : auto right = parse_expr (LBP_LOGICAL_AND, AST::AttrVec (), restrictions);
3428 263 : if (!right)
3429 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3430 :
3431 : // TODO: check types. actually, do so during semantic analysis
3432 263 : location_t locus = left->get_locus ();
3433 :
3434 263 : return std::make_unique<AST::LazyBooleanExpr> (
3435 263 : std::move (left), std::move (right.value ()),
3436 526 : LazyBooleanOperator::LOGICAL_AND, locus);
3437 263 : }
3438 :
3439 : // Parses a pseudo-binary infix type cast expression (with Pratt parsing).
3440 : template <typename ManagedTokenSource>
3441 : tl::expected<std::unique_ptr<AST::TypeCastExpr>, Parse::Error::Expr>
3442 5271 : Parser<ManagedTokenSource>::parse_type_cast_expr (
3443 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> expr_to_cast,
3444 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED,
3445 : ParseRestrictions restrictions ATTRIBUTE_UNUSED)
3446 : {
3447 : // parse RHS (as tok has already been consumed in parse_expression)
3448 5271 : auto type = parse_type_no_bounds ();
3449 5271 : if (!type)
3450 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3451 : // FIXME: how do I get precedence put in here?
3452 :
3453 : // TODO: check types. actually, do so during semantic analysis
3454 5271 : location_t locus = expr_to_cast->get_locus ();
3455 :
3456 5271 : return std::make_unique<AST::TypeCastExpr> (std::move (expr_to_cast),
3457 5271 : std::move (type), locus);
3458 5271 : }
3459 :
3460 : // Parses a binary assignment expression (with Pratt parsing).
3461 : template <typename ManagedTokenSource>
3462 : tl::expected<std::unique_ptr<AST::AssignmentExpr>, Parse::Error::Expr>
3463 2527 : Parser<ManagedTokenSource>::parse_assig_expr (
3464 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3465 : AST::AttrVec outer_attrs, ParseRestrictions restrictions)
3466 : {
3467 : // parse RHS (as tok has already been consumed in parse_expression)
3468 2527 : auto right = parse_expr (LBP_ASSIG - 1, AST::AttrVec (), restrictions);
3469 2527 : if (!right)
3470 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3471 : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
3472 :
3473 2527 : location_t locus = left->get_locus ();
3474 :
3475 2527 : return std::make_unique<AST::AssignmentExpr> (std::move (left),
3476 2527 : std::move (right.value ()),
3477 2527 : std::move (outer_attrs), locus);
3478 2527 : }
3479 :
3480 : /* Returns the left binding power for the given CompoundAssignmentExpr type.
3481 : * TODO make constexpr? Would that even do anything useful? */
3482 : inline binding_powers
3483 685 : get_lbp_for_compound_assignment_expr (
3484 : AST::CompoundAssignmentExpr::ExprType expr_type)
3485 : {
3486 685 : switch (expr_type)
3487 : {
3488 : case CompoundAssignmentOperator::ADD:
3489 : return LBP_PLUS;
3490 : case CompoundAssignmentOperator::SUBTRACT:
3491 : return LBP_MINUS;
3492 : case CompoundAssignmentOperator::MULTIPLY:
3493 : return LBP_MUL;
3494 : case CompoundAssignmentOperator::DIVIDE:
3495 : return LBP_DIV;
3496 : case CompoundAssignmentOperator::MODULUS:
3497 : return LBP_MOD;
3498 : case CompoundAssignmentOperator::BITWISE_AND:
3499 : return LBP_AMP;
3500 : case CompoundAssignmentOperator::BITWISE_OR:
3501 : return LBP_PIPE;
3502 : case CompoundAssignmentOperator::BITWISE_XOR:
3503 : return LBP_CARET;
3504 : case CompoundAssignmentOperator::LEFT_SHIFT:
3505 : return LBP_L_SHIFT;
3506 : case CompoundAssignmentOperator::RIGHT_SHIFT:
3507 : return LBP_R_SHIFT;
3508 0 : default:
3509 : // WTF? should not happen, this is an error
3510 0 : rust_unreachable ();
3511 :
3512 : return LBP_PLUS;
3513 : }
3514 : }
3515 :
3516 : // Parses a compound assignment expression (with Pratt parsing).
3517 : template <typename ManagedTokenSource>
3518 : tl::expected<std::unique_ptr<AST::CompoundAssignmentExpr>, Parse::Error::Expr>
3519 685 : Parser<ManagedTokenSource>::parse_compound_assignment_expr (
3520 : const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
3521 : AST::CompoundAssignmentExpr::ExprType expr_type,
3522 : ParseRestrictions restrictions)
3523 : {
3524 : // parse RHS (as tok has already been consumed in parse_expression)
3525 685 : auto right = parse_expr (get_lbp_for_compound_assignment_expr (expr_type) - 1,
3526 1370 : AST::AttrVec (), restrictions);
3527 685 : if (!right)
3528 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3529 : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
3530 :
3531 : // TODO: check types. actually, do so during semantic analysis
3532 685 : location_t locus = left->get_locus ();
3533 :
3534 685 : return std::make_unique<AST::CompoundAssignmentExpr> (
3535 1370 : std::move (left), std::move (right.value ()), expr_type, locus);
3536 685 : }
3537 :
3538 : // Parses a binary add-assignment expression (with Pratt parsing).
3539 : template <typename ManagedTokenSource>
3540 : tl::expected<std::unique_ptr<AST::CompoundAssignmentExpr>, Parse::Error::Expr>
3541 0 : Parser<ManagedTokenSource>::parse_plus_assig_expr (
3542 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3543 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3544 : {
3545 : // parse RHS (as tok has already been consumed in parse_expression)
3546 0 : auto right = parse_expr (LBP_PLUS_ASSIG - 1, AST::AttrVec (), restrictions);
3547 0 : if (!right)
3548 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3549 : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
3550 :
3551 : // TODO: check types. actually, do so during semantic analysis
3552 0 : location_t locus = left->get_locus ();
3553 :
3554 0 : return std::make_unique<AST::CompoundAssignmentExpr> (
3555 0 : std::move (left), std::move (right.value ()),
3556 0 : CompoundAssignmentOperator::ADD, locus);
3557 0 : }
3558 :
3559 : // Parses a binary minus-assignment expression (with Pratt parsing).
3560 : template <typename ManagedTokenSource>
3561 : tl::expected<std::unique_ptr<AST::CompoundAssignmentExpr>, Parse::Error::Expr>
3562 0 : Parser<ManagedTokenSource>::parse_minus_assig_expr (
3563 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3564 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3565 : {
3566 : // parse RHS (as tok has already been consumed in parse_expression)
3567 0 : auto right = parse_expr (LBP_MINUS_ASSIG - 1, AST::AttrVec (), restrictions);
3568 0 : if (!right)
3569 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3570 : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
3571 :
3572 : // TODO: check types. actually, do so during semantic analysis
3573 0 : location_t locus = left->get_locus ();
3574 :
3575 0 : return std::make_unique<AST::CompoundAssignmentExpr> (
3576 0 : std::move (left), std::move (right.value ()),
3577 0 : CompoundAssignmentOperator::SUBTRACT, locus);
3578 0 : }
3579 :
3580 : // Parses a binary multiplication-assignment expression (with Pratt parsing).
3581 : template <typename ManagedTokenSource>
3582 : tl::expected<std::unique_ptr<AST::CompoundAssignmentExpr>, Parse::Error::Expr>
3583 0 : Parser<ManagedTokenSource>::parse_mult_assig_expr (
3584 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3585 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3586 : {
3587 : // parse RHS (as tok has already been consumed in parse_expression)
3588 0 : auto right = parse_expr (LBP_MULT_ASSIG - 1, AST::AttrVec (), restrictions);
3589 0 : if (!right)
3590 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3591 : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
3592 :
3593 : // TODO: check types. actually, do so during semantic analysis
3594 0 : location_t locus = left->get_locus ();
3595 :
3596 0 : return std::make_unique<AST::CompoundAssignmentExpr> (
3597 0 : std::move (left), std::move (right.value ()),
3598 0 : CompoundAssignmentOperator::MULTIPLY, locus);
3599 0 : }
3600 :
3601 : // Parses a binary division-assignment expression (with Pratt parsing).
3602 : template <typename ManagedTokenSource>
3603 : tl::expected<std::unique_ptr<AST::CompoundAssignmentExpr>, Parse::Error::Expr>
3604 0 : Parser<ManagedTokenSource>::parse_div_assig_expr (
3605 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3606 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3607 : {
3608 : // parse RHS (as tok has already been consumed in parse_expression)
3609 0 : auto right = parse_expr (LBP_DIV_ASSIG - 1, AST::AttrVec (), restrictions);
3610 0 : if (!right)
3611 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3612 : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
3613 :
3614 : // TODO: check types. actually, do so during semantic analysis
3615 0 : location_t locus = left->get_locus ();
3616 :
3617 0 : return std::make_unique<AST::CompoundAssignmentExpr> (
3618 0 : std::move (left), std::move (right.value ()),
3619 0 : CompoundAssignmentOperator::DIVIDE, locus);
3620 0 : }
3621 :
3622 : // Parses a binary modulo-assignment expression (with Pratt parsing).
3623 : template <typename ManagedTokenSource>
3624 : tl::expected<std::unique_ptr<AST::CompoundAssignmentExpr>, Parse::Error::Expr>
3625 0 : Parser<ManagedTokenSource>::parse_mod_assig_expr (
3626 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3627 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3628 : {
3629 : // parse RHS (as tok has already been consumed in parse_expression)
3630 0 : auto right = parse_expr (LBP_MOD_ASSIG - 1, AST::AttrVec (), restrictions);
3631 0 : if (!right)
3632 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3633 : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
3634 :
3635 : // TODO: check types. actually, do so during semantic analysis
3636 0 : location_t locus = left->get_locus ();
3637 :
3638 0 : return std::make_unique<AST::CompoundAssignmentExpr> (
3639 0 : std::move (left), std::move (right.value ()),
3640 0 : CompoundAssignmentOperator::MODULUS, locus);
3641 0 : }
3642 :
3643 : // Parses a binary and-assignment expression (with Pratt parsing).
3644 : template <typename ManagedTokenSource>
3645 : tl::expected<std::unique_ptr<AST::CompoundAssignmentExpr>, Parse::Error::Expr>
3646 0 : Parser<ManagedTokenSource>::parse_and_assig_expr (
3647 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3648 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3649 : {
3650 : // parse RHS (as tok has already been consumed in parse_expression)
3651 0 : auto right = parse_expr (LBP_AMP_ASSIG - 1, AST::AttrVec (), restrictions);
3652 0 : if (!right)
3653 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3654 : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
3655 :
3656 : // TODO: check types. actually, do so during semantic analysis
3657 0 : location_t locus = left->get_locus ();
3658 :
3659 0 : return std::make_unique<AST::CompoundAssignmentExpr> (
3660 0 : std::move (left), std::move (right.value ()),
3661 0 : CompoundAssignmentOperator::BITWISE_AND, locus);
3662 0 : }
3663 :
3664 : // Parses a binary or-assignment expression (with Pratt parsing).
3665 : template <typename ManagedTokenSource>
3666 : tl::expected<std::unique_ptr<AST::CompoundAssignmentExpr>, Parse::Error::Expr>
3667 0 : Parser<ManagedTokenSource>::parse_or_assig_expr (
3668 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3669 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3670 : {
3671 : // parse RHS (as tok has already been consumed in parse_expression)
3672 0 : auto right = parse_expr (LBP_PIPE_ASSIG - 1, AST::AttrVec (), restrictions);
3673 0 : if (!right)
3674 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3675 : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
3676 :
3677 : // TODO: check types. actually, do so during semantic analysis
3678 0 : location_t locus = left->get_locus ();
3679 :
3680 0 : return std::make_unique<AST::CompoundAssignmentExpr> (
3681 0 : std::move (left), std::move (right.value ()),
3682 0 : CompoundAssignmentOperator::BITWISE_OR, locus);
3683 0 : }
3684 :
3685 : // Parses a binary xor-assignment expression (with Pratt parsing).
3686 : template <typename ManagedTokenSource>
3687 : tl::expected<std::unique_ptr<AST::CompoundAssignmentExpr>, Parse::Error::Expr>
3688 0 : Parser<ManagedTokenSource>::parse_xor_assig_expr (
3689 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3690 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3691 : {
3692 : // parse RHS (as tok has already been consumed in parse_expression)
3693 0 : auto right = parse_expr (LBP_CARET_ASSIG - 1, AST::AttrVec (), restrictions);
3694 0 : if (!right)
3695 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3696 : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
3697 :
3698 : // TODO: check types. actually, do so during semantic analysis
3699 0 : location_t locus = left->get_locus ();
3700 :
3701 0 : return std::make_unique<AST::CompoundAssignmentExpr> (
3702 0 : std::move (left), std::move (right.value ()),
3703 0 : CompoundAssignmentOperator::BITWISE_XOR, locus);
3704 0 : }
3705 :
3706 : // Parses a binary left shift-assignment expression (with Pratt parsing).
3707 : template <typename ManagedTokenSource>
3708 : tl::expected<std::unique_ptr<AST::CompoundAssignmentExpr>, Parse::Error::Expr>
3709 0 : Parser<ManagedTokenSource>::parse_left_shift_assig_expr (
3710 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3711 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3712 : {
3713 : // parse RHS (as tok has already been consumed in parse_expression)
3714 0 : auto right
3715 0 : = parse_expr (LBP_L_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions);
3716 0 : if (!right)
3717 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3718 : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
3719 :
3720 : // TODO: check types. actually, do so during semantic analysis
3721 0 : location_t locus = left->get_locus ();
3722 :
3723 0 : return std::make_unique<AST::CompoundAssignmentExpr> (
3724 0 : std::move (left), std::move (right.value ()),
3725 0 : CompoundAssignmentOperator::LEFT_SHIFT, locus);
3726 0 : }
3727 :
3728 : // Parses a binary right shift-assignment expression (with Pratt parsing).
3729 : template <typename ManagedTokenSource>
3730 : tl::expected<std::unique_ptr<AST::CompoundAssignmentExpr>, Parse::Error::Expr>
3731 0 : Parser<ManagedTokenSource>::parse_right_shift_assig_expr (
3732 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3733 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3734 : {
3735 : // parse RHS (as tok has already been consumed in parse_expression)
3736 0 : auto right
3737 0 : = parse_expr (LBP_R_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions);
3738 0 : if (!right)
3739 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3740 : // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
3741 :
3742 : // TODO: check types. actually, do so during semantic analysis
3743 0 : location_t locus = left->get_locus ();
3744 :
3745 0 : return std::make_unique<AST::CompoundAssignmentExpr> (
3746 0 : std::move (left), std::move (right.value ()),
3747 0 : CompoundAssignmentOperator::RIGHT_SHIFT, locus);
3748 0 : }
3749 :
3750 : // Parses a postfix unary await expression (with Pratt parsing).
3751 : template <typename ManagedTokenSource>
3752 : tl::expected<std::unique_ptr<AST::AwaitExpr>, Parse::Error::Expr>
3753 0 : Parser<ManagedTokenSource>::parse_await_expr (
3754 : const_TokenPtr tok, std::unique_ptr<AST::Expr> expr_to_await,
3755 : AST::AttrVec outer_attrs)
3756 : {
3757 : /* skip "await" identifier (as "." has already been consumed in
3758 : * parse_expression) this assumes that the identifier was already identified
3759 : * as await */
3760 0 : if (!skip_token (IDENTIFIER))
3761 : {
3762 0 : Error error (tok->get_locus (), "failed to skip %<await%> in await expr "
3763 : "- this is probably a deep issue");
3764 0 : add_error (std::move (error));
3765 :
3766 : // skip somewhere?
3767 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
3768 0 : }
3769 :
3770 : // TODO: check inside async block in semantic analysis
3771 0 : location_t locus = expr_to_await->get_locus ();
3772 :
3773 0 : return std::unique_ptr<AST::AwaitExpr> (
3774 0 : new AST::AwaitExpr (std::move (expr_to_await), std::move (outer_attrs),
3775 0 : locus));
3776 : }
3777 :
3778 : /* Parses an exclusive range ('..') in left denotation position (i.e.
3779 : * RangeFromExpr or RangeFromToExpr). */
3780 : template <typename ManagedTokenSource>
3781 : tl::expected<std::unique_ptr<AST::RangeExpr>, Parse::Error::Expr>
3782 78 : Parser<ManagedTokenSource>::parse_led_range_exclusive_expr (
3783 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3784 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3785 : {
3786 : // FIXME: this probably parses expressions accidently or whatever
3787 : // try parsing RHS (as tok has already been consumed in parse_expression)
3788 : // Can be nullptr, in which case it is a RangeFromExpr, otherwise a
3789 : // RangeFromToExpr.
3790 78 : restrictions.expr_can_be_null = true;
3791 78 : auto right = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions);
3792 :
3793 78 : location_t locus = left->get_locus ();
3794 :
3795 78 : if (!right)
3796 : {
3797 : // range from expr
3798 9 : return std::make_unique<AST::RangeFromExpr> (std::move (left), locus);
3799 : }
3800 : else
3801 : {
3802 69 : return std::make_unique<AST::RangeFromToExpr> (std::move (left),
3803 69 : std::move (right.value ()),
3804 69 : locus);
3805 : }
3806 : // FIXME: make non-associative
3807 78 : }
3808 :
3809 : /* Parses an exclusive range ('..') in null denotation position (i.e.
3810 : * RangeToExpr or RangeFullExpr). */
3811 : template <typename ManagedTokenSource>
3812 : tl::expected<std::unique_ptr<AST::RangeExpr>, Parse::Error::Expr>
3813 9 : Parser<ManagedTokenSource>::parse_nud_range_exclusive_expr (
3814 : const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED)
3815 : {
3816 9 : auto restrictions = ParseRestrictions ();
3817 9 : restrictions.expr_can_be_null = true;
3818 :
3819 : // FIXME: this probably parses expressions accidently or whatever
3820 : // try parsing RHS (as tok has already been consumed in parse_expression)
3821 9 : auto right = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions);
3822 :
3823 9 : location_t locus = tok->get_locus ();
3824 :
3825 9 : if (!right)
3826 : {
3827 : // range from expr
3828 1 : return std::make_unique<AST::RangeFullExpr> (locus);
3829 : }
3830 : else
3831 : {
3832 8 : return std::make_unique<AST::RangeToExpr> (std::move (right.value ()),
3833 8 : locus);
3834 : }
3835 : // FIXME: make non-associative
3836 9 : }
3837 :
3838 : // Parses a full binary range inclusive expression.
3839 : template <typename ManagedTokenSource>
3840 : tl::expected<std::unique_ptr<AST::RangeFromToInclExpr>, Parse::Error::Expr>
3841 7 : Parser<ManagedTokenSource>::parse_range_inclusive_expr (
3842 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
3843 : AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
3844 : {
3845 : // parse RHS (as tok has already been consumed in parse_expression)
3846 7 : auto right = parse_expr (LBP_DOT_DOT_EQ, AST::AttrVec (), restrictions);
3847 7 : if (!right)
3848 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3849 : // FIXME: make non-associative
3850 :
3851 : // TODO: check types. actually, do so during semantic analysis
3852 7 : location_t locus = left->get_locus ();
3853 :
3854 7 : return std::make_unique<AST::RangeFromToInclExpr> (std::move (left),
3855 7 : std::move (right.value ()),
3856 7 : locus);
3857 7 : }
3858 :
3859 : // Parses an inclusive range-to prefix unary expression.
3860 : template <typename ManagedTokenSource>
3861 : tl::expected<std::unique_ptr<AST::RangeToInclExpr>, Parse::Error::Expr>
3862 0 : Parser<ManagedTokenSource>::parse_range_to_inclusive_expr (
3863 : const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED)
3864 : {
3865 : // parse RHS (as tok has already been consumed in parse_expression)
3866 0 : auto right = parse_expr (LBP_DOT_DOT_EQ);
3867 0 : if (!right)
3868 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3869 : // FIXME: make non-associative
3870 :
3871 : // TODO: check types. actually, do so during semantic analysis
3872 :
3873 0 : return std::make_unique<AST::RangeToInclExpr> (std::move (right.value ()),
3874 0 : tok->get_locus ());
3875 0 : }
3876 :
3877 : // Parses a pseudo-binary infix tuple index expression.
3878 : template <typename ManagedTokenSource>
3879 : tl::expected<std::unique_ptr<AST::TupleIndexExpr>, Parse::Error::Expr>
3880 905 : Parser<ManagedTokenSource>::parse_tuple_index_expr (
3881 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> tuple_expr,
3882 : AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
3883 : {
3884 : // parse int literal (as token already skipped)
3885 905 : const_TokenPtr index_tok = expect_token (INT_LITERAL);
3886 905 : if (index_tok == nullptr)
3887 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
3888 :
3889 1810 : std::string index = index_tok->get_str ();
3890 :
3891 : // convert to integer
3892 905 : if (!index_tok->is_pure_decimal ())
3893 : {
3894 27 : Error error (index_tok->get_locus (),
3895 : "tuple index should be a pure decimal literal");
3896 27 : add_error (std::move (error));
3897 27 : }
3898 905 : int index_int = atoi (index.c_str ());
3899 :
3900 905 : location_t locus = tuple_expr->get_locus ();
3901 :
3902 905 : return std::make_unique<AST::TupleIndexExpr> (std::move (tuple_expr),
3903 : index_int,
3904 905 : std::move (outer_attrs), locus);
3905 905 : }
3906 :
3907 : // Parses a pseudo-binary infix array (or slice) index expression.
3908 : template <typename ManagedTokenSource>
3909 : tl::expected<std::unique_ptr<AST::ArrayIndexExpr>, Parse::Error::Expr>
3910 303 : Parser<ManagedTokenSource>::parse_index_expr (
3911 : const_TokenPtr, std::unique_ptr<AST::Expr> array_expr,
3912 : AST::AttrVec outer_attrs, ParseRestrictions)
3913 : {
3914 : // parse RHS (as tok has already been consumed in parse_expression)
3915 : /*std::unique_ptr<AST::Expr> index_expr
3916 : = parse_expr (LBP_ARRAY_REF, AST::AttrVec (),
3917 : restrictions);*/
3918 : // TODO: conceptually, should treat [] as brackets, so just parse all expr
3919 303 : auto index_expr = parse_expr ();
3920 303 : if (!index_expr)
3921 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::CHILD_ERROR);
3922 :
3923 : // skip ']' at end of array
3924 303 : if (!skip_token (RIGHT_SQUARE))
3925 : {
3926 : // skip somewhere?
3927 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
3928 : }
3929 :
3930 : // TODO: check types. actually, do so during semantic analysis
3931 303 : location_t locus = array_expr->get_locus ();
3932 :
3933 303 : return std::make_unique<AST::ArrayIndexExpr> (std::move (array_expr),
3934 303 : std::move (index_expr.value ()),
3935 303 : std::move (outer_attrs), locus);
3936 303 : }
3937 :
3938 : // Parses a pseudo-binary infix struct field access expression.
3939 : template <typename ManagedTokenSource>
3940 : tl::expected<std::unique_ptr<AST::FieldAccessExpr>, Parse::Error::Expr>
3941 4982 : Parser<ManagedTokenSource>::parse_field_access_expr (
3942 : const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> struct_expr,
3943 : AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
3944 : {
3945 : /* get field name identifier (assume that this is a field access expr and
3946 : * not await, for instance) */
3947 4982 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
3948 4982 : if (ident_tok == nullptr)
3949 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
3950 :
3951 9964 : Identifier ident{ident_tok};
3952 :
3953 4982 : location_t locus = struct_expr->get_locus ();
3954 :
3955 : // TODO: check types. actually, do so during semantic analysis
3956 4982 : return std::make_unique<AST::FieldAccessExpr> (std::move (struct_expr),
3957 : std::move (ident),
3958 : std::move (outer_attrs),
3959 4982 : locus);
3960 4982 : }
3961 :
3962 : // Parses a pseudo-binary infix method call expression.
3963 : template <typename ManagedTokenSource>
3964 : tl::expected<std::unique_ptr<AST::MethodCallExpr>, Parse::Error::Expr>
3965 3096 : Parser<ManagedTokenSource>::parse_method_call_expr (
3966 : const_TokenPtr tok, std::unique_ptr<AST::Expr> receiver_expr,
3967 : AST::AttrVec outer_attrs, ParseRestrictions)
3968 : {
3969 : // parse path expr segment
3970 3096 : AST::PathExprSegment segment = parse_path_expr_segment ();
3971 3096 : if (segment.is_error ())
3972 : {
3973 0 : Error error (tok->get_locus (),
3974 : "failed to parse path expr segment of method call expr");
3975 0 : add_error (std::move (error));
3976 :
3977 : return tl::unexpected<Parse::Error::Expr> (
3978 0 : Parse::Error::Expr::CHILD_ERROR);
3979 0 : }
3980 :
3981 : // skip left parentheses
3982 3096 : if (!skip_token (LEFT_PAREN))
3983 : {
3984 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
3985 : }
3986 :
3987 : // parse method params (if they exist)
3988 3096 : std::vector<std::unique_ptr<AST::Expr>> params;
3989 :
3990 3096 : const_TokenPtr t = lexer.peek_token ();
3991 5156 : while (t->get_id () != RIGHT_PAREN)
3992 : {
3993 2060 : auto param = parse_expr ();
3994 2060 : if (!param)
3995 : {
3996 0 : Error error (t->get_locus (),
3997 : "failed to parse method param in method call");
3998 0 : add_error (std::move (error));
3999 :
4000 : return tl::unexpected<Parse::Error::Expr> (
4001 0 : Parse::Error::Expr::CHILD_ERROR);
4002 0 : }
4003 2060 : params.push_back (std::move (param.value ()));
4004 :
4005 4120 : if (lexer.peek_token ()->get_id () != COMMA)
4006 : break;
4007 :
4008 1 : lexer.skip_token ();
4009 1 : t = lexer.peek_token ();
4010 : }
4011 :
4012 : // skip right paren
4013 3096 : if (!skip_token (RIGHT_PAREN))
4014 : {
4015 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
4016 : }
4017 :
4018 : // TODO: check types. actually do so in semantic analysis pass.
4019 3096 : location_t locus = receiver_expr->get_locus ();
4020 :
4021 3096 : return std::make_unique<AST::MethodCallExpr> (std::move (receiver_expr),
4022 : std::move (segment),
4023 : std::move (params),
4024 3096 : std::move (outer_attrs), locus);
4025 3096 : }
4026 :
4027 : // Parses a pseudo-binary infix function call expression.
4028 : template <typename ManagedTokenSource>
4029 : tl::expected<std::unique_ptr<AST::CallExpr>, Parse::Error::Expr>
4030 979 : Parser<ManagedTokenSource>::parse_function_call_expr (
4031 : const_TokenPtr, std::unique_ptr<AST::Expr> function_expr,
4032 : AST::AttrVec outer_attrs, ParseRestrictions)
4033 : {
4034 : // parse function params (if they exist)
4035 979 : std::vector<std::unique_ptr<AST::Expr>> params;
4036 :
4037 979 : const_TokenPtr t = lexer.peek_token ();
4038 1855 : while (t->get_id () != RIGHT_PAREN)
4039 : {
4040 876 : auto param = parse_expr ();
4041 876 : if (!param)
4042 : {
4043 0 : Error error (t->get_locus (),
4044 : "failed to parse function param in function call");
4045 0 : add_error (std::move (error));
4046 :
4047 : return tl::unexpected<Parse::Error::Expr> (
4048 0 : Parse::Error::Expr::CHILD_ERROR);
4049 0 : }
4050 876 : params.push_back (std::move (param.value ()));
4051 :
4052 1752 : if (lexer.peek_token ()->get_id () != COMMA)
4053 : break;
4054 :
4055 24 : lexer.skip_token ();
4056 24 : t = lexer.peek_token ();
4057 : }
4058 :
4059 : // skip ')' at end of param list
4060 979 : if (!skip_token (RIGHT_PAREN))
4061 : {
4062 : // skip somewhere?
4063 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
4064 : }
4065 :
4066 : // TODO: check types. actually, do so during semantic analysis
4067 979 : location_t locus = function_expr->get_locus ();
4068 :
4069 979 : return std::make_unique<AST::CallExpr> (std::move (function_expr),
4070 : std::move (params),
4071 979 : std::move (outer_attrs), locus);
4072 979 : }
4073 :
4074 : /* Parses a struct expr struct with a path in expression already parsed (but
4075 : * not
4076 : * '{' token). */
4077 : template <typename ManagedTokenSource>
4078 : tl::expected<std::unique_ptr<AST::StructExprStruct>, Parse::Error::Expr>
4079 1418 : Parser<ManagedTokenSource>::parse_struct_expr_struct_partial (
4080 : AST::PathInExpression path, AST::AttrVec outer_attrs)
4081 : {
4082 : // assume struct expr struct (as struct-enum disambiguation requires name
4083 : // lookup) again, make statement if final ';'
4084 1418 : if (!skip_token (LEFT_CURLY))
4085 : {
4086 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
4087 : }
4088 :
4089 : // parse inner attributes
4090 1418 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4091 :
4092 : // branch based on next token
4093 1418 : const_TokenPtr t = lexer.peek_token ();
4094 1418 : location_t path_locus = path.get_locus ();
4095 1418 : switch (t->get_id ())
4096 : {
4097 78 : case RIGHT_CURLY:
4098 : // struct with no body
4099 78 : lexer.skip_token ();
4100 :
4101 78 : return std::make_unique<AST::StructExprStruct> (std::move (path),
4102 : std::move (inner_attrs),
4103 : std::move (outer_attrs),
4104 78 : path_locus);
4105 1340 : case DOT_DOT:
4106 : /* technically this would give a struct base-only struct, but this
4107 : * algorithm should work too. As such, AST type not happening. */
4108 : case IDENTIFIER:
4109 : case HASH:
4110 : case INT_LITERAL:
4111 : {
4112 : // struct with struct expr fields
4113 :
4114 : // parse struct expr fields
4115 1340 : std::vector<std::unique_ptr<AST::StructExprField>> fields;
4116 :
4117 3634 : while (t->get_id () != RIGHT_CURLY && t->get_id () != DOT_DOT)
4118 : {
4119 2294 : auto field = parse_struct_expr_field ();
4120 2294 : if (!field)
4121 : {
4122 1 : if (field.error () == Parse::Error::StructExprField::STRUCT_BASE)
4123 : break;
4124 1 : if (field.error ()
4125 : == Parse::Error::StructExprField::STRUCT_BASE_ATTRIBUTES)
4126 : return tl::unexpected<Parse::Error::Expr> (
4127 1 : Parse::Error::Expr::CHILD_ERROR);
4128 :
4129 0 : Error error (t->get_locus (),
4130 : "failed to parse struct (or enum) expr field");
4131 0 : add_error (std::move (error));
4132 :
4133 : return tl::unexpected<Parse::Error::Expr> (
4134 0 : Parse::Error::Expr::CHILD_ERROR);
4135 0 : }
4136 :
4137 : // DEBUG:
4138 2293 : rust_debug ("struct/enum expr field validated to not be null");
4139 :
4140 2293 : fields.push_back (std::move (field.value ()));
4141 :
4142 : // DEBUG:
4143 2293 : rust_debug ("struct/enum expr field pushed back");
4144 :
4145 4586 : if (lexer.peek_token ()->get_id () != COMMA)
4146 : {
4147 : // DEBUG:
4148 1096 : rust_debug ("lack of comma detected in struct/enum expr "
4149 : "fields - break");
4150 1096 : break;
4151 : }
4152 1197 : lexer.skip_token ();
4153 :
4154 : // DEBUG:
4155 1197 : rust_debug ("struct/enum expr fields comma skipped ");
4156 :
4157 1197 : t = lexer.peek_token ();
4158 : }
4159 :
4160 : // DEBUG:
4161 1339 : rust_debug ("struct/enum expr about to parse struct base ");
4162 :
4163 : // parse struct base if it exists
4164 : AST::StructBase struct_base = AST::StructBase::error ();
4165 2678 : if (lexer.peek_token ()->get_id () == DOT_DOT)
4166 : {
4167 63 : location_t dot_dot_location = lexer.peek_token ()->get_locus ();
4168 63 : lexer.skip_token ();
4169 :
4170 : // parse required struct base expr
4171 63 : auto base_expr = parse_expr ();
4172 63 : if (!base_expr)
4173 : {
4174 0 : Error error (lexer.peek_token ()->get_locus (),
4175 : "failed to parse struct base expression in struct "
4176 : "expression");
4177 0 : add_error (std::move (error));
4178 :
4179 : return tl::unexpected<Parse::Error::Expr> (
4180 0 : Parse::Error::Expr::CHILD_ERROR);
4181 0 : }
4182 :
4183 : // DEBUG:
4184 63 : rust_debug ("struct/enum expr - parsed and validated base expr");
4185 :
4186 126 : struct_base = AST::StructBase (std::move (base_expr.value ()),
4187 63 : dot_dot_location);
4188 :
4189 : // DEBUG:
4190 63 : rust_debug ("assigned struct base to new struct base ");
4191 63 : }
4192 :
4193 1339 : if (!skip_token (RIGHT_CURLY))
4194 : {
4195 : return tl::unexpected<Parse::Error::Expr> (
4196 0 : Parse::Error::Expr::MALFORMED);
4197 : }
4198 :
4199 : // DEBUG:
4200 1339 : rust_debug (
4201 : "struct/enum expr skipped right curly - done and ready to return");
4202 :
4203 1339 : return std::make_unique<AST::StructExprStructFields> (
4204 : std::move (path), std::move (fields), path_locus,
4205 : std::move (struct_base), std::move (inner_attrs),
4206 1339 : std::move (outer_attrs));
4207 1340 : }
4208 0 : default:
4209 0 : add_error (
4210 0 : Error (t->get_locus (),
4211 : "unrecognised token %qs in struct (or enum) expression - "
4212 : "expected %<}%>, identifier, integer literal, or %<..%>",
4213 : t->get_token_description ()));
4214 :
4215 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
4216 : }
4217 1418 : }
4218 :
4219 : /* Parses a struct expr tuple with a path in expression already parsed (but
4220 : * not
4221 : * '(' token).
4222 : * FIXME: this currently outputs a call expr, as they cannot be disambiguated.
4223 : * A better solution would be to just get this to call that function directly.
4224 : * */
4225 : template <typename ManagedTokenSource>
4226 : tl::expected<std::unique_ptr<AST::CallExpr>, Parse::Error::Expr>
4227 11346 : Parser<ManagedTokenSource>::parse_struct_expr_tuple_partial (
4228 : AST::PathInExpression path, AST::AttrVec outer_attrs)
4229 : {
4230 11346 : if (!skip_token (LEFT_PAREN))
4231 : {
4232 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
4233 : }
4234 :
4235 11346 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4236 :
4237 11346 : std::vector<std::unique_ptr<AST::Expr>> exprs;
4238 :
4239 11346 : const_TokenPtr t = lexer.peek_token ();
4240 23893 : while (t->get_id () != RIGHT_PAREN)
4241 : {
4242 : // parse expression (required)
4243 12547 : auto expr = parse_expr ();
4244 12547 : if (!expr)
4245 : {
4246 0 : Error error (t->get_locus (), "failed to parse expression in "
4247 : "struct (or enum) expression tuple");
4248 0 : add_error (std::move (error));
4249 :
4250 : return tl::unexpected<Parse::Error::Expr> (
4251 0 : Parse::Error::Expr::CHILD_ERROR);
4252 0 : }
4253 12547 : exprs.push_back (std::move (expr.value ()));
4254 :
4255 25094 : if (lexer.peek_token ()->get_id () != COMMA)
4256 : break;
4257 :
4258 4018 : lexer.skip_token ();
4259 :
4260 4018 : t = lexer.peek_token ();
4261 : }
4262 :
4263 11346 : if (!skip_token (RIGHT_PAREN))
4264 : {
4265 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
4266 : }
4267 :
4268 11346 : location_t path_locus = path.get_locus ();
4269 :
4270 11346 : auto pathExpr = std::make_unique<AST::PathInExpression> (std::move (path));
4271 :
4272 11346 : return std::make_unique<AST::CallExpr> (std::move (pathExpr),
4273 : std::move (exprs),
4274 11346 : std::move (outer_attrs), path_locus);
4275 22692 : }
4276 :
4277 : // Parses a closure expression with pratt parsing (from null denotation).
4278 : template <typename ManagedTokenSource>
4279 : tl::expected<std::unique_ptr<AST::ClosureExpr>, Parse::Error::Expr>
4280 73 : Parser<ManagedTokenSource>::parse_closure_expr_pratt (const_TokenPtr tok,
4281 : AST::AttrVec outer_attrs)
4282 : {
4283 : // TODO: does this need pratt parsing (for precedence)? probably not, but
4284 : // idk
4285 73 : location_t locus = tok->get_locus ();
4286 73 : bool has_move = false;
4287 73 : if (tok->get_id () == MOVE)
4288 : {
4289 1 : has_move = true;
4290 1 : tok = lexer.peek_token ();
4291 1 : lexer.skip_token ();
4292 : // skip token and reassign
4293 : }
4294 :
4295 : // handle parameter list
4296 73 : std::vector<AST::ClosureParam> params;
4297 :
4298 73 : switch (tok->get_id ())
4299 : {
4300 : case OR:
4301 : // no parameters, don't skip token
4302 : break;
4303 61 : case PIPE:
4304 : {
4305 : // actually may have parameters
4306 : // don't skip token
4307 61 : const_TokenPtr t = lexer.peek_token ();
4308 133 : while (t->get_id () != PIPE)
4309 : {
4310 72 : AST::ClosureParam param = parse_closure_param ();
4311 72 : if (param.is_error ())
4312 : {
4313 : // TODO is this really an error?
4314 0 : Error error (t->get_locus (), "could not parse closure param");
4315 0 : add_error (std::move (error));
4316 :
4317 : return tl::unexpected<Parse::Error::Expr> (
4318 0 : Parse::Error::Expr::CHILD_ERROR);
4319 0 : }
4320 72 : params.push_back (std::move (param));
4321 :
4322 144 : if (lexer.peek_token ()->get_id () != COMMA)
4323 : {
4324 122 : if (lexer.peek_token ()->get_id () == OR)
4325 1 : lexer.split_current_token (PIPE, PIPE);
4326 : // not an error but means param list is done
4327 : break;
4328 : }
4329 : // skip comma
4330 11 : lexer.skip_token ();
4331 :
4332 22 : if (lexer.peek_token ()->get_id () == OR)
4333 0 : lexer.split_current_token (PIPE, PIPE);
4334 :
4335 11 : t = lexer.peek_token ();
4336 : }
4337 :
4338 61 : if (!skip_token (PIPE))
4339 : {
4340 : return tl::unexpected<Parse::Error::Expr> (
4341 0 : Parse::Error::Expr::MALFORMED);
4342 : }
4343 : break;
4344 61 : }
4345 0 : default:
4346 0 : add_error (Error (tok->get_locus (),
4347 : "unexpected token %qs in closure expression - expected "
4348 : "%<|%> or %<||%>",
4349 : tok->get_token_description ()));
4350 :
4351 : // skip somewhere?
4352 0 : return tl::unexpected<Parse::Error::Expr> (Parse::Error::Expr::MALFORMED);
4353 : }
4354 :
4355 : // again branch based on next token
4356 73 : tok = lexer.peek_token ();
4357 73 : if (tok->get_id () == RETURN_TYPE)
4358 : {
4359 : // must be return type closure with block expr
4360 :
4361 : // skip "return type" token
4362 31 : lexer.skip_token ();
4363 :
4364 : // parse actual type, which is required
4365 31 : auto type = parse_type_no_bounds ();
4366 31 : if (!type)
4367 : {
4368 : // error
4369 0 : Error error (tok->get_locus (), "failed to parse type for closure");
4370 0 : add_error (std::move (error));
4371 :
4372 : // skip somewhere?
4373 : return tl::unexpected<Parse::Error::Expr> (
4374 0 : Parse::Error::Expr::CHILD_ERROR);
4375 0 : }
4376 :
4377 : // parse block expr, which is required
4378 31 : auto block = parse_block_expr ();
4379 31 : if (!block)
4380 : {
4381 : // error
4382 0 : Error error (lexer.peek_token ()->get_locus (),
4383 : "failed to parse block expr in closure");
4384 0 : add_error (std::move (error));
4385 :
4386 : // skip somewhere?
4387 : return tl::unexpected<Parse::Error::Expr> (
4388 0 : Parse::Error::Expr::CHILD_ERROR);
4389 0 : }
4390 :
4391 31 : return std::make_unique<AST::ClosureExprInnerTyped> (
4392 31 : std::move (type), std::move (block.value ()), std::move (params), locus,
4393 31 : has_move, std::move (outer_attrs));
4394 31 : }
4395 : else
4396 : {
4397 : // must be expr-only closure
4398 :
4399 : // parse expr, which is required
4400 42 : auto expr = parse_expr ();
4401 42 : if (!expr)
4402 : {
4403 0 : Error error (tok->get_locus (),
4404 : "failed to parse expression in closure");
4405 0 : add_error (std::move (error));
4406 :
4407 : // skip somewhere?
4408 : return tl::unexpected<Parse::Error::Expr> (
4409 0 : Parse::Error::Expr::CHILD_ERROR);
4410 0 : }
4411 :
4412 42 : return std::make_unique<AST::ClosureExprInner> (std::move (expr.value ()),
4413 : std::move (params), locus,
4414 : has_move,
4415 42 : std::move (outer_attrs));
4416 42 : }
4417 73 : }
4418 :
4419 : } // namespace Rust
|