diff options
Diffstat (limited to 'gcc/rust/parse/rust-parse-impl.h')
| -rw-r--r-- | gcc/rust/parse/rust-parse-impl.h | 1384 |
1 files changed, 691 insertions, 693 deletions
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index d5383ad..6cb8f0e 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -19,21 +19,24 @@ /* Template implementation for Rust::Parser. Previously in rust-parse.cc (before * Parser was template). Separated from rust-parse.h for readability. */ -/* DO NOT INCLUDE ANYWHERE - this is automatically included with rust-parse.h +/* DO NOT INCLUDE ANYWHERE - this is automatically included + * by rust-parse-impl-*.cc * This is also the reason why there are no include guards. */ +#include "expected.h" +#include "rust-ast.h" #include "rust-common.h" #include "rust-expr.h" #include "rust-item.h" #include "rust-common.h" +#include "rust-parse.h" #include "rust-token.h" #define INCLUDE_ALGORITHM #include "rust-diagnostics.h" -#include "rust-make-unique.h" #include "rust-dir-owner.h" #include "rust-attribute-values.h" #include "rust-keyword-values.h" -#include "rust-session-manager.h" +#include "rust-edition.h" #include "optional.h" @@ -228,19 +231,22 @@ Parser<ManagedTokenSource>::skip_generics_right_angle () // this is good - skip token lexer.skip_token (); return true; - case RIGHT_SHIFT: { + case RIGHT_SHIFT: + { // new implementation that should be better lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE); lexer.skip_token (); return true; } - case GREATER_OR_EQUAL: { + case GREATER_OR_EQUAL: + { // new implementation that should be better lexer.split_current_token (RIGHT_ANGLE, EQUAL); lexer.skip_token (); return true; } - case RIGHT_SHIFT_EQ: { + case RIGHT_SHIFT_EQ: + { // new implementation that should be better lexer.split_current_token (RIGHT_ANGLE, GREATER_OR_EQUAL); lexer.skip_token (); @@ -425,10 +431,6 @@ Parser<ManagedTokenSource>::parse_items () std::unique_ptr<AST::Item> item = parse_item (false); if (item == nullptr) { - Error error (lexer.peek_token ()->get_locus (), - "failed to parse item in crate"); - add_error (std::move (error)); - // TODO: should all items be cleared? items = std::vector<std::unique_ptr<AST::Item>> (); break; @@ -652,10 +654,7 @@ Parser<ManagedTokenSource>::parse_simple_path () // Parse all other simple path segments while (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION) { - // Skip scope resolution operator - lexer.skip_token (); - - AST::SimplePathSegment new_segment = parse_simple_path_segment (); + AST::SimplePathSegment new_segment = parse_simple_path_segment (1); // Return path as currently constructed if segment in error state. if (new_segment.is_error ()) @@ -683,35 +682,36 @@ Parser<ManagedTokenSource>::parse_simple_path () } /* Parses a single SimplePathSegment (does not handle the scope resolution - * operators) */ + * operators) + * Starts parsing at an offset of base_peek */ template <typename ManagedTokenSource> AST::SimplePathSegment -Parser<ManagedTokenSource>::parse_simple_path_segment () +Parser<ManagedTokenSource>::parse_simple_path_segment (int base_peek) { using namespace Values; - const_TokenPtr t = lexer.peek_token (); + const_TokenPtr t = lexer.peek_token (base_peek); switch (t->get_id ()) { case IDENTIFIER: - lexer.skip_token (); + lexer.skip_token (base_peek); return AST::SimplePathSegment (t->get_str (), t->get_locus ()); case SUPER: - lexer.skip_token (); + lexer.skip_token (base_peek); return AST::SimplePathSegment (Keywords::SUPER, t->get_locus ()); case SELF: - lexer.skip_token (); + lexer.skip_token (base_peek); return AST::SimplePathSegment (Keywords::SELF, t->get_locus ()); case CRATE: - lexer.skip_token (); + lexer.skip_token (base_peek); return AST::SimplePathSegment (Keywords::CRATE, t->get_locus ()); case DOLLAR_SIGN: - if (lexer.peek_token (1)->get_id () == CRATE) + if (lexer.peek_token (base_peek + 1)->get_id () == CRATE) { - lexer.skip_token (1); + lexer.skip_token (base_peek + 1); return AST::SimplePathSegment ("$crate", t->get_locus ()); } @@ -791,7 +791,8 @@ Parser<ManagedTokenSource>::parse_attr_input () { case LEFT_PAREN: case LEFT_SQUARE: - case LEFT_CURLY: { + case LEFT_CURLY: + { // must be a delimited token tree, so parse that std::unique_ptr<AST::AttrInput> input_tree ( new AST::DelimTokenTree (parse_delim_token_tree ())); @@ -800,7 +801,8 @@ Parser<ManagedTokenSource>::parse_attr_input () return input_tree; } - case EQUAL: { + case EQUAL: + { // = LiteralExpr lexer.skip_token (); @@ -878,7 +880,10 @@ Parser<ManagedTokenSource>::parse_attr_input () return attr_input_lit; } break; + case RIGHT_PAREN: case RIGHT_SQUARE: + case RIGHT_CURLY: + case END_OF_FILE: // means AttrInput is missing, which is allowed return nullptr; default: @@ -973,16 +978,7 @@ Parser<ManagedTokenSource>::parse_delim_token_tree () std::unique_ptr<AST::TokenTree> tok_tree = parse_token_tree (); if (tok_tree == nullptr) - { - // TODO: is this error handling appropriate? - Error error ( - t->get_locus (), - "failed to parse token tree in delimited token tree - found %qs", - t->get_token_description ()); - add_error (std::move (error)); - - return AST::DelimTokenTree::create_empty (); - } + return AST::DelimTokenTree::create_empty (); token_trees_in_tree.push_back (std::move (tok_tree)); @@ -1044,6 +1040,7 @@ Parser<ManagedTokenSource>::parse_identifier_or_keyword_token () } else { + add_error (Error (t->get_locus (), "expected keyword or identifier")); return nullptr; } } @@ -1069,11 +1066,12 @@ Parser<ManagedTokenSource>::parse_token_tree () case RIGHT_SQUARE: case RIGHT_CURLY: // error - should not be called when this a token - add_error ( - Error (t->get_locus (), - "unexpected closing delimiter %qs - token tree requires " - "either paired delimiters or non-delimiter tokens", - t->get_token_description ())); + add_error (Error (t->get_locus (), "unexpected closing delimiter %qs", + t->get_token_description ())); + + add_error (Error (Error::Kind::Hint, t->get_locus (), + "token tree requires either paired delimiters or " + "non-delimiter tokens")); lexer.skip_token (); return nullptr; @@ -1454,8 +1452,7 @@ Parser<ManagedTokenSource>::parse_async_item (AST::Visibility vis, auto offset = (lexer.peek_token ()->get_id () == CONST) ? 1 : 0; const_TokenPtr t = lexer.peek_token (offset); - if (Session::get_instance ().options.get_edition () - == CompileOptions::Edition::E2015) + if (get_rust_edition () == Edition::E2015) { add_error (Error (t->get_locus (), ErrorCode::E0670, "%<async fn%> is not permitted in Rust 2015")); @@ -1708,10 +1705,9 @@ Parser<ManagedTokenSource>::parse_decl_macro_def (AST::Visibility vis, return nullptr; } - AST::MacroRule macro_rule - = AST::MacroRule (std::move (matcher), std::move (transcriber), locus); std::vector<AST::MacroRule> macro_rules; - macro_rules.push_back (macro_rule); + macro_rules.emplace_back (std::move (matcher), std::move (transcriber), + locus); return std::unique_ptr<AST::MacroRulesDefinition> ( AST::MacroRulesDefinition::decl_macro (std::move (rule_name), @@ -1853,20 +1849,13 @@ Parser<ManagedTokenSource>::parse_macro_invocation_semi ( t = lexer.peek_token (); // parse token trees until the initial delimiter token is found again - while (!token_id_matches_delims (t->get_id (), delim_type)) + while (!token_id_matches_delims (t->get_id (), delim_type) + && t->get_id () != END_OF_FILE) { std::unique_ptr<AST::TokenTree> tree = parse_token_tree (); if (tree == nullptr) - { - Error error (t->get_locus (), - "failed to parse token tree for macro invocation semi " - "- found %qs", - t->get_token_description ()); - add_error (std::move (error)); - - return nullptr; - } + return nullptr; token_trees.push_back (std::move (tree)); @@ -2119,7 +2108,8 @@ Parser<ManagedTokenSource>::parse_macro_match () { case LEFT_PAREN: case LEFT_SQUARE: - case LEFT_CURLY: { + case LEFT_CURLY: + { // must be macro matcher as delimited AST::MacroMatcher matcher = parse_macro_matcher (); if (matcher.is_error ()) @@ -2133,7 +2123,8 @@ Parser<ManagedTokenSource>::parse_macro_match () return std::unique_ptr<AST::MacroMatcher> ( new AST::MacroMatcher (std::move (matcher))); } - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { // have to do more lookahead to determine if fragment or repetition const_TokenPtr t2 = lexer.peek_token (1); switch (t2->get_id ()) @@ -2404,7 +2395,8 @@ Parser<ManagedTokenSource>::parse_visibility () skip_token (RIGHT_PAREN); return AST::Visibility::create_super (path_loc, vis_loc); - case IN: { + case IN: + { lexer.skip_token (); // parse the "in" path as well @@ -2468,7 +2460,8 @@ Parser<ManagedTokenSource>::parse_module (AST::Visibility vis, new AST::Module (std::move (name), std::move (vis), std::move (outer_attrs), locus, safety, lexer.get_filename (), inline_module_stack)); - case LEFT_CURLY: { + case LEFT_CURLY: + { lexer.skip_token (); // parse inner attributes @@ -2732,7 +2725,8 @@ Parser<ManagedTokenSource>::parse_use_tree () return std::unique_ptr<AST::UseTreeGlob> ( new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH, AST::SimplePath::create_empty (), locus)); - case LEFT_CURLY: { + case LEFT_CURLY: + { // nested tree UseTree type lexer.skip_token (); @@ -2796,58 +2790,12 @@ Parser<ManagedTokenSource>::parse_use_tree () } else { - /* Due to aforementioned implementation issues, the trailing :: token is - * consumed by the path, so it can not be used as a disambiguator. - * NOPE, not true anymore - TODO what are the consequences of this? */ - const_TokenPtr t = lexer.peek_token (); + switch (t->get_id ()) { - case ASTERISK: - // glob UseTree type - lexer.skip_token (); - - return std::unique_ptr<AST::UseTreeGlob> ( - new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED, - std::move (path), locus)); - case LEFT_CURLY: { - // nested tree UseTree type - lexer.skip_token (); - - std::vector<std::unique_ptr<AST::UseTree>> use_trees; - - // TODO: think of better control structure - const_TokenPtr t = lexer.peek_token (); - while (t->get_id () != RIGHT_CURLY) - { - std::unique_ptr<AST::UseTree> use_tree = parse_use_tree (); - if (use_tree == nullptr) - { - break; - } - - use_trees.push_back (std::move (use_tree)); - - if (lexer.peek_token ()->get_id () != COMMA) - break; - - lexer.skip_token (); - t = lexer.peek_token (); - } - - // skip end curly delimiter - if (!skip_token (RIGHT_CURLY)) - { - // skip after somewhere? - return nullptr; - } - - return std::unique_ptr<AST::UseTreeList> ( - new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED, - std::move (path), std::move (use_trees), - locus)); - } - case AS: { + case AS: + { // rebind UseTree type lexer.skip_token (); @@ -2886,16 +2834,72 @@ Parser<ManagedTokenSource>::parse_use_tree () // don't skip semicolon - handled in parse_use_tree // lexer.skip_token(); - - return std::unique_ptr<AST::UseTreeRebind> ( - new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path), - locus)); case COMMA: case RIGHT_CURLY: // this may occur in recursive calls - assume it is ok and ignore it return std::unique_ptr<AST::UseTreeRebind> ( new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path), locus)); + case SCOPE_RESOLUTION: + // keep going + break; + default: + add_error (Error (t->get_locus (), + "unexpected token %qs in use tree with valid path", + t->get_token_description ())); + return nullptr; + } + + skip_token (); + t = lexer.peek_token (); + + switch (t->get_id ()) + { + case ASTERISK: + // glob UseTree type + lexer.skip_token (); + + return std::unique_ptr<AST::UseTreeGlob> ( + new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED, + std::move (path), locus)); + case LEFT_CURLY: + { + // nested tree UseTree type + lexer.skip_token (); + + std::vector<std::unique_ptr<AST::UseTree>> use_trees; + + // TODO: think of better control structure + const_TokenPtr t = lexer.peek_token (); + while (t->get_id () != RIGHT_CURLY) + { + std::unique_ptr<AST::UseTree> use_tree = parse_use_tree (); + if (use_tree == nullptr) + { + break; + } + + use_trees.push_back (std::move (use_tree)); + + if (lexer.peek_token ()->get_id () != COMMA) + break; + + lexer.skip_token (); + t = lexer.peek_token (); + } + + // skip end curly delimiter + if (!skip_token (RIGHT_CURLY)) + { + // skip after somewhere? + return nullptr; + } + + return std::unique_ptr<AST::UseTreeList> ( + new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED, + std::move (path), std::move (use_trees), + locus)); + } default: add_error (Error (t->get_locus (), "unexpected token %qs in use tree with valid path", @@ -2987,8 +2991,9 @@ Parser<ManagedTokenSource>::parse_function (AST::Visibility vis, else { std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr (); - if (block_expr != nullptr) - body = std::move (block_expr); + if (block_expr == nullptr) + return nullptr; + body = std::move (block_expr); } return std::unique_ptr<AST::Function> ( @@ -3102,9 +3107,10 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) switch (token->get_id ()) { - case LIFETIME: { + case LIFETIME: + { auto lifetime = parse_lifetime (false); - if (lifetime.is_error ()) + if (!lifetime) { rust_error_at ( token->get_locus (), @@ -3124,11 +3130,12 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) } param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam ( - std::move (lifetime), std::move (lifetime_bounds), + std::move (lifetime.value ()), std::move (lifetime_bounds), std::move (outer_attrs), token->get_locus ())); break; } - case IDENTIFIER: { + case IDENTIFIER: + { auto type_ident = token->get_str (); lexer.skip_token (); @@ -3163,7 +3170,8 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) std::move (outer_attrs))); break; } - case CONST: { + case CONST: + { lexer.skip_token (); auto name_token = expect_token (IDENTIFIER); @@ -3176,24 +3184,28 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token) return nullptr; // optional default value - auto default_expr = AST::GenericArg::create_error (); + tl::optional<AST::GenericArg> default_expr = tl::nullopt; if (lexer.peek_token ()->get_id () == EQUAL) { lexer.skip_token (); auto tok = lexer.peek_token (); default_expr = parse_generic_arg (); - if (default_expr.is_error ()) - rust_error_at (tok->get_locus (), - "invalid token for start of default value for " - "const generic parameter: expected %<block%>, " - "%<identifier%> or %<literal%>, got %qs", - token_id_to_str (tok->get_id ())); + if (!default_expr) + { + rust_error_at (tok->get_locus (), + "invalid token for start of default value for " + "const generic parameter: expected %<block%>, " + "%<identifier%> or %<literal%>, got %qs", + token_id_to_str (tok->get_id ())); + return nullptr; + } // At this point, we *know* that we are parsing a const // expression - if (default_expr.get_kind () == AST::GenericArg::Kind::Either) - default_expr = default_expr.disambiguate_to_const (); + if (default_expr.value ().get_kind () + == AST::GenericArg::Kind::Either) + default_expr = default_expr.value ().disambiguate_to_const (); } param = std::unique_ptr<AST::ConstGenericParam> ( @@ -3232,8 +3244,12 @@ Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token) // Did we parse a generic type param yet auto type_seen = false; + // Did we parse a const param with a default value yet + auto const_with_default_seen = false; // Did the user write a lifetime parameter after a type one auto order_error = false; + // Did the user write a const param with a default value after a type one + auto const_with_default_order_error = false; // parse lifetime params while (!is_end_token (lexer.peek_token ()->get_id ())) @@ -3241,12 +3257,29 @@ Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token) auto param = parse_generic_param (is_end_token); if (param) { - // TODO: Handle `Const` here as well if necessary if (param->get_kind () == AST::GenericParam::Kind::Type) - type_seen = true; + { + type_seen = true; + if (const_with_default_seen) + const_with_default_order_error = true; + } else if (param->get_kind () == AST::GenericParam::Kind::Lifetime && type_seen) - order_error = true; + { + order_error = true; + if (const_with_default_seen) + const_with_default_order_error = true; + } + else if (param->get_kind () == AST::GenericParam::Kind::Const) + { + type_seen = true; + AST::ConstGenericParam *const_param + = static_cast<AST::ConstGenericParam *> (param.get ()); + if (const_param->has_default_value ()) + const_with_default_seen = true; + else if (const_with_default_seen) + const_with_default_order_error = true; + } generic_params.emplace_back (std::move (param)); maybe_skip_token (COMMA); @@ -3263,6 +3296,13 @@ Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token) "must be declared prior to type and const parameters"); add_error (std::move (error)); } + if (const_with_default_order_error) + { + Error error (generic_params.front ()->get_locus (), + "invalid order for generic parameters: generic parameters " + "with a default must be trailing"); + add_error (std::move (error)); + } generic_params.shrink_to_fit (); return generic_params; @@ -3278,16 +3318,16 @@ Parser<ManagedTokenSource>::parse_lifetime_params () while (lexer.peek_token ()->get_id () != END_OF_FILE) { - AST::LifetimeParam lifetime_param = parse_lifetime_param (); + auto lifetime_param = parse_lifetime_param (); - if (lifetime_param.is_error ()) + if (!lifetime_param) { // can't treat as error as only way to get out with trailing comma break; } - lifetime_params.push_back (std::unique_ptr<AST::LifetimeParam> ( - new AST::LifetimeParam (std::move (lifetime_param)))); + lifetime_params.emplace_back ( + new AST::LifetimeParam (std::move (lifetime_param.value ()))); if (lexer.peek_token ()->get_id () != COMMA) break; @@ -3313,9 +3353,9 @@ Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token) // if end_token is not specified, it defaults to EOF, so should work fine while (!is_end_token (lexer.peek_token ()->get_id ())) { - AST::LifetimeParam lifetime_param = parse_lifetime_param (); + auto lifetime_param = parse_lifetime_param (); - if (lifetime_param.is_error ()) + if (!lifetime_param) { /* TODO: is it worth throwing away all lifetime params just because * one failed? */ @@ -3326,8 +3366,8 @@ Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token) return {}; } - lifetime_params.push_back (std::unique_ptr<AST::LifetimeParam> ( - new AST::LifetimeParam (std::move (lifetime_param)))); + lifetime_params.emplace_back ( + new AST::LifetimeParam (std::move (lifetime_param))); if (lexer.peek_token ()->get_id () != COMMA) break; @@ -3343,7 +3383,8 @@ Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token) /* Parses lifetime generic parameters (objects). Will also consume any * trailing comma. No extra checks for end token. - * TODO: is this best solution? implements most of the same algorithm. */ + * TODO: is this best solution? implements most of the same algorithm. + * TODO: seems to be unused, remove? */ template <typename ManagedTokenSource> std::vector<AST::LifetimeParam> Parser<ManagedTokenSource>::parse_lifetime_params_objs () @@ -3353,15 +3394,15 @@ Parser<ManagedTokenSource>::parse_lifetime_params_objs () // bad control structure as end token cannot be guaranteed while (true) { - AST::LifetimeParam lifetime_param = parse_lifetime_param (); + auto lifetime_param = parse_lifetime_param (); - if (lifetime_param.is_error ()) + if (!lifetime_param) { // not an error as only way to exit if trailing comma break; } - lifetime_params.push_back (std::move (lifetime_param)); + lifetime_params.push_back (std::move (lifetime_param.value ())); if (lexer.peek_token ()->get_id () != COMMA) break; @@ -3388,9 +3429,9 @@ Parser<ManagedTokenSource>::parse_lifetime_params_objs ( while (!is_end_token (lexer.peek_token ()->get_id ())) { - AST::LifetimeParam lifetime_param = parse_lifetime_param (); + auto lifetime_param = parse_lifetime_param (); - if (lifetime_param.is_error ()) + if (!lifetime_param) { /* TODO: is it worth throwing away all lifetime params just because * one failed? */ @@ -3401,7 +3442,7 @@ Parser<ManagedTokenSource>::parse_lifetime_params_objs ( return {}; } - lifetime_params.push_back (std::move (lifetime_param)); + lifetime_params.push_back (std::move (lifetime_param.value ())); if (lexer.peek_token ()->get_id () != COMMA) break; @@ -3460,7 +3501,7 @@ Parser<ManagedTokenSource>::parse_non_ptr_sequence ( /* Parses a single lifetime generic parameter (not including comma). */ template <typename ManagedTokenSource> -AST::LifetimeParam +tl::expected<AST::LifetimeParam, ParseLifetimeParamError> Parser<ManagedTokenSource>::parse_lifetime_param () { // parse outer attributes, which are optional and may not exist @@ -3470,8 +3511,8 @@ Parser<ManagedTokenSource>::parse_lifetime_param () const_TokenPtr lifetime_tok = lexer.peek_token (); if (lifetime_tok->get_id () != LIFETIME) { - // if lifetime is missing, must not be a lifetime param, so return null - return AST::LifetimeParam::create_error (); + // if lifetime is missing, must not be a lifetime param, so return error + return tl::make_unexpected<ParseLifetimeParamError> ({}); } lexer.skip_token (); AST::Lifetime lifetime (AST::Lifetime::NAMED, lifetime_tok->get_str (), @@ -3683,7 +3724,7 @@ Parser<ManagedTokenSource>::parse_function_param () if (lexer.peek_token ()->get_id () == ELLIPSIS) // Unnamed variadic { lexer.skip_token (); // Skip ellipsis - return Rust::make_unique<AST::VariadicParam> ( + return std::make_unique<AST::VariadicParam> ( AST::VariadicParam (std::move (outer_attrs), locus)); } @@ -3705,7 +3746,7 @@ Parser<ManagedTokenSource>::parse_function_param () if (lexer.peek_token ()->get_id () == ELLIPSIS) // Named variadic { lexer.skip_token (); // Skip ellipsis - return Rust::make_unique<AST::VariadicParam> ( + return std::make_unique<AST::VariadicParam> ( AST::VariadicParam (std::move (param_pattern), std::move (outer_attrs), locus)); } @@ -3716,7 +3757,7 @@ Parser<ManagedTokenSource>::parse_function_param () { return nullptr; } - return Rust::make_unique<AST::FunctionParam> ( + return std::make_unique<AST::FunctionParam> ( AST::FunctionParam (std::move (param_pattern), std::move (param_type), std::move (outer_attrs), locus)); } @@ -3817,12 +3858,13 @@ template <typename ManagedTokenSource> std::unique_ptr<AST::LifetimeWhereClauseItem> Parser<ManagedTokenSource>::parse_lifetime_where_clause_item () { - AST::Lifetime lifetime = parse_lifetime (false); - if (lifetime.is_error ()) + auto parsed_lifetime = parse_lifetime (false); + if (!parsed_lifetime) { // TODO: error here? return nullptr; } + auto lifetime = parsed_lifetime.value (); if (!skip_token (COLON)) { @@ -4015,7 +4057,7 @@ Parser<ManagedTokenSource>::parse_type_param_bound () { case LIFETIME: return std::unique_ptr<AST::Lifetime> ( - new AST::Lifetime (parse_lifetime (false))); + new AST::Lifetime (parse_lifetime (false).value ())); case LEFT_PAREN: case QUESTION_MARK: case FOR: @@ -4088,13 +4130,13 @@ Parser<ManagedTokenSource>::parse_lifetime_bounds () while (true) { - AST::Lifetime lifetime = parse_lifetime (false); + auto lifetime = parse_lifetime (false); // quick exit for parsing failure - if (lifetime.is_error ()) + if (!lifetime) break; - lifetime_bounds.push_back (std::move (lifetime)); + lifetime_bounds.push_back (std::move (lifetime.value ())); /* plus is maybe not allowed at end - spec defines it weirdly, so * assuming allowed at end */ @@ -4118,9 +4160,9 @@ Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token) while (!is_end_token (lexer.peek_token ()->get_id ())) { - AST::Lifetime lifetime = parse_lifetime (false); + auto lifetime = parse_lifetime (false); - if (lifetime.is_error ()) + if (!lifetime) { /* TODO: is it worth throwing away all lifetime bound info just * because one failed? */ @@ -4131,7 +4173,7 @@ Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token) return {}; } - lifetime_bounds.push_back (std::move (lifetime)); + lifetime_bounds.push_back (std::move (lifetime.value ())); /* plus is maybe not allowed at end - spec defines it weirdly, so * assuming allowed at end */ @@ -4148,14 +4190,20 @@ Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token) /* Parses a lifetime token (named, 'static, or '_). Also handles lifetime not * existing. */ template <typename ManagedTokenSource> -AST::Lifetime +tl::expected<AST::Lifetime, ParseLifetimeError> Parser<ManagedTokenSource>::parse_lifetime (bool allow_elided) { const_TokenPtr lifetime_tok = lexer.peek_token (); if (lifetime_tok->get_id () != LIFETIME) { - return (allow_elided) ? AST::Lifetime::elided () - : AST::Lifetime::error (); + if (allow_elided) + { + return AST::Lifetime::elided (); + } + else + { + return tl::make_unexpected<ParseLifetimeError> ({}); + } } lexer.skip_token (); @@ -4347,7 +4395,8 @@ Parser<ManagedTokenSource>::parse_struct (AST::Visibility vis, const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case LEFT_CURLY: { + case LEFT_CURLY: + { // struct with body // skip curly bracket @@ -4750,7 +4799,8 @@ Parser<ManagedTokenSource>::parse_enum_item () const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case LEFT_PAREN: { + case LEFT_PAREN: + { // tuple enum item lexer.skip_token (); @@ -4771,7 +4821,8 @@ Parser<ManagedTokenSource>::parse_enum_item () std::move (item_name), std::move (vis), std::move (tuple_fields), std::move (outer_attrs), item_name_tok->get_locus ())); } - case LEFT_CURLY: { + case LEFT_CURLY: + { // struct enum item lexer.skip_token (); @@ -4788,7 +4839,8 @@ Parser<ManagedTokenSource>::parse_enum_item () std::move (item_name), std::move (vis), std::move (struct_fields), std::move (outer_attrs), item_name_tok->get_locus ())); } - case EQUAL: { + case EQUAL: + { // discriminant enum item lexer.skip_token (); @@ -5151,6 +5203,13 @@ Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs, Identifier ident{ident_tok}; + // Parse optional generic parameters for GATs (Generic Associated Types) + std::vector<std::unique_ptr<AST::GenericParam>> generic_params; + if (lexer.peek_token ()->get_id () == LEFT_ANGLE) + { + generic_params = parse_generic_params_in_angles (); + } + std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; // parse optional colon @@ -5171,13 +5230,14 @@ Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs, } return std::unique_ptr<AST::TraitItemType> ( - new AST::TraitItemType (std::move (ident), std::move (bounds), - std::move (outer_attrs), vis, locus)); + new AST::TraitItemType (std::move (ident), std::move (generic_params), + std::move (bounds), std::move (outer_attrs), vis, + locus)); } // Parses a constant trait item. template <typename ManagedTokenSource> -std::unique_ptr<AST::TraitItemConst> +std::unique_ptr<AST::ConstantItem> Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs) { location_t locus = lexer.peek_token ()->get_locus (); @@ -5215,10 +5275,9 @@ Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs) return nullptr; } - return std::unique_ptr<AST::TraitItemConst> ( - new AST::TraitItemConst (std::move (ident), std::move (type), - std::move (const_body), std::move (outer_attrs), - locus)); + return std::unique_ptr<AST::ConstantItem> (new AST::ConstantItem ( + std::move (ident), AST::Visibility::create_private (), std::move (type), + std::move (const_body), std::move (outer_attrs), locus)); } /* Parses a struct "impl" item (both inherent impl and trait impl can be @@ -5441,7 +5500,8 @@ Parser<ManagedTokenSource>::parse_inherent_impl_item () case SUPER: case SELF: case CRATE: - case PUB: { + case PUB: + { // visibility, so not a macro invocation semi - must be constant, // function, or method AST::Visibility vis = parse_visibility (); @@ -5572,7 +5632,8 @@ Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method ( // param auto initial_param = parse_self_param (); - if (!initial_param.has_value () && initial_param.error () != NOT_SELF) + if (!initial_param.has_value () + && initial_param.error () != ParseSelfError::NOT_SELF) return nullptr; /* FIXME: ensure that self param doesn't accidently consume tokens for a @@ -5771,7 +5832,8 @@ Parser<ManagedTokenSource>::parse_trait_impl_function_or_method ( // param auto initial_param = parse_self_param (); - if (!initial_param.has_value () && initial_param.error () != NOT_SELF) + if (!initial_param.has_value () + && initial_param.error () != ParseSelfError::NOT_SELF) return nullptr; // FIXME: ensure that self param doesn't accidently consume tokens for a @@ -5937,106 +5999,6 @@ Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis, std::move (outer_attrs), locus)); } -template <typename ManagedTokenSource> -AST::NamedFunctionParam -Parser<ManagedTokenSource>::parse_named_function_param () -{ - AST::AttrVec outer_attrs = parse_outer_attributes (); - location_t locus = lexer.peek_token ()->get_locus (); - - if (lexer.peek_token ()->get_id () == ELLIPSIS) // Unnamed variadic - { - lexer.skip_token (); // Skip ellipsis - return AST::NamedFunctionParam (std::move (outer_attrs), locus); - } - - // parse identifier/_ - std::string name; - - const_TokenPtr t = lexer.peek_token (); - location_t name_location = t->get_locus (); - switch (t->get_id ()) - { - case IDENTIFIER: - name = t->get_str (); - lexer.skip_token (); - break; - case UNDERSCORE: - name = "_"; - lexer.skip_token (); - break; - default: - // this is not a function param, but not necessarily an error - return AST::NamedFunctionParam::create_error (); - } - - if (!skip_token (COLON)) - { - // skip after somewhere? - return AST::NamedFunctionParam::create_error (); - } - - if (lexer.peek_token ()->get_id () == ELLIPSIS) // Named variadic - { - lexer.skip_token (); // Skip ellipsis - return AST::NamedFunctionParam (std::move (name), std::move (outer_attrs), - locus); - } - - // parse (required) type - std::unique_ptr<AST::Type> param_type = parse_type (); - if (param_type == nullptr) - { - Error error ( - lexer.peek_token ()->get_locus (), - "could not parse param type in extern block function declaration"); - add_error (std::move (error)); - - skip_after_semicolon (); - return AST::NamedFunctionParam::create_error (); - } - - return AST::NamedFunctionParam (std::move (name), std::move (param_type), - std::move (outer_attrs), name_location); -} - -template <typename ManagedTokenSource> -template <typename EndTokenPred> -std::vector<AST::NamedFunctionParam> -Parser<ManagedTokenSource>::parse_named_function_params ( - EndTokenPred is_end_token) -{ - std::vector<AST::NamedFunctionParam> params; - if (is_end_token (lexer.peek_token ()->get_id ())) - return params; - - auto initial_param = parse_named_function_param (); - if (initial_param.is_error ()) - return params; - - params.push_back (std::move (initial_param)); - auto t = lexer.peek_token (); - while (t->get_id () == COMMA) - { - lexer.skip_token (); - if (is_end_token (lexer.peek_token ()->get_id ())) - break; - - auto param = parse_named_function_param (); - if (param.is_error ()) - { - Error error (lexer.peek_token ()->get_locus (), - "failed to parse param in c function params"); - add_error (error); - return std::vector<AST::NamedFunctionParam> (); - } - params.push_back (std::move (param)); - t = lexer.peek_token (); - } - params.shrink_to_fit (); - return params; -} - // Parses a single extern block item (static or function declaration). template <typename ManagedTokenSource> std::unique_ptr<AST::ExternalItem> @@ -6055,7 +6017,8 @@ Parser<ManagedTokenSource>::parse_external_item () { case IDENTIFIER: return parse_macro_invocation_semi (outer_attrs); - case STATIC_KW: { + case STATIC_KW: + { // parse extern static item lexer.skip_token (); @@ -6256,15 +6219,15 @@ Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs, expr = parse_expr (); if (expr == nullptr) { - Error error (lexer.peek_token ()->get_locus (), - "failed to parse expression in let statement"); - add_error (std::move (error)); - skip_after_semicolon (); return nullptr; } } + tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt; + if (maybe_skip_token (ELSE)) + else_expr = parse_block_expr (); + if (restrictions.consume_semi) { // `stmt` macro variables are parsed without a semicolon, but should be @@ -6279,7 +6242,7 @@ Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs, return std::unique_ptr<AST::LetStmt> ( new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type), - std::move (outer_attrs), locus)); + std::move (else_expr), std::move (outer_attrs), locus)); } // Parses a type path. @@ -6340,7 +6303,7 @@ Parser<ManagedTokenSource>::parse_type_path () } template <typename ManagedTokenSource> -AST::GenericArg +tl::optional<AST::GenericArg> Parser<ManagedTokenSource>::parse_generic_arg () { auto tok = lexer.peek_token (); @@ -6348,7 +6311,8 @@ Parser<ManagedTokenSource>::parse_generic_arg () switch (tok->get_id ()) { - case IDENTIFIER: { + case IDENTIFIER: + { // This is a bit of a weird situation: With an identifier token, we // could either have a valid type or a macro (FIXME: anything else?). So // we need one bit of lookahead to differentiate if this is really @@ -6361,7 +6325,7 @@ Parser<ManagedTokenSource>::parse_generic_arg () if (type) return AST::GenericArg::create_type (std::move (type)); else - return AST::GenericArg::create_error (); + return tl::nullopt; } else if (next_tok->get_id () == COLON) { @@ -6378,7 +6342,7 @@ Parser<ManagedTokenSource>::parse_generic_arg () if (type) return AST::GenericArg::create_type (std::move (type)); else - return AST::GenericArg::create_error (); + return tl::nullopt; } lexer.skip_token (); return AST::GenericArg::create_ambiguous (tok->get_str (), @@ -6396,20 +6360,21 @@ Parser<ManagedTokenSource>::parse_generic_arg () case FALSE_LITERAL: expr = parse_literal_expr (); break; - // FIXME: Because of this, error reporting is garbage for const generic - // parameter's default values - default: { + // FIXME: Because of this, error reporting is garbage for const generic + // parameter's default values + default: + { auto type = parse_type (); // FIXME: Find a better way to do this? if (type) return AST::GenericArg::create_type (std::move (type)); else - return AST::GenericArg::create_error (); + return tl::nullopt; } } if (!expr) - return AST::GenericArg::create_error (); + return tl::nullopt; return AST::GenericArg::create_const (std::move (expr)); } @@ -6438,14 +6403,14 @@ Parser<ManagedTokenSource>::parse_path_generic_args () location_t locus = t->get_locus (); while (!is_right_angle_tok (t->get_id ())) { - AST::Lifetime lifetime = parse_lifetime (false); - if (lifetime.is_error ()) + auto lifetime = parse_lifetime (false); + if (!lifetime) { // not necessarily an error break; } - lifetime_args.push_back (std::move (lifetime)); + lifetime_args.push_back (std::move (lifetime.value ())); // if next token isn't comma, then it must be end of list if (lexer.peek_token ()->get_id () != COMMA) @@ -6474,9 +6439,9 @@ Parser<ManagedTokenSource>::parse_path_generic_args () break; auto arg = parse_generic_arg (); - if (!arg.is_error ()) + if (arg) { - generic_args.emplace_back (std::move (arg)); + generic_args.emplace_back (std::move (arg.value ())); } // FIXME: Do we need to break if we encounter an error? @@ -6597,7 +6562,8 @@ Parser<ManagedTokenSource>::parse_type_path_segment () switch (t->get_id ()) { case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // parse generic args AST::GenericArgs generic_args = parse_path_generic_args (); @@ -6606,7 +6572,8 @@ Parser<ManagedTokenSource>::parse_type_path_segment () has_separating_scope_resolution, std::move (generic_args), locus)); } - case LEFT_PAREN: { + case LEFT_PAREN: + { // parse type path function AST::TypePathFunction type_path_function = parse_type_path_function (locus); @@ -7059,10 +7026,12 @@ Parser<ManagedTokenSource>::parse_self_param () // now test whether it has a lifetime if (lexer.peek_token ()->get_id () == LIFETIME) { - lifetime = parse_lifetime (true); - // something went wrong somehow - if (lifetime.is_error ()) + if (auto parsed_lifetime = parse_lifetime (true)) + { + lifetime = parsed_lifetime.value (); + } + else { Error error (lexer.peek_token ()->get_locus (), "failed to parse lifetime in self param"); @@ -7124,14 +7093,14 @@ Parser<ManagedTokenSource>::parse_self_param () if (has_reference) { - return Rust::make_unique<AST::SelfParam> (std::move (lifetime), has_mut, - locus); + return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut, + locus); } else { // note that type may be nullptr here and that's fine - return Rust::make_unique<AST::SelfParam> (std::move (type), has_mut, - locus); + return std::make_unique<AST::SelfParam> (std::move (type), has_mut, + locus); } } @@ -7153,16 +7122,14 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, case SELF: case SELF_ALIAS: case DOLLAR_SIGN: - case SCOPE_RESOLUTION: { + case SCOPE_RESOLUTION: + { AST::PathInExpression path = parse_path_in_expression (); std::unique_ptr<AST::Expr> null_denotation; if (lexer.peek_token ()->get_id () == EXCLAM) { - // Bind a reference to avoid -Wredundant-move on post-P1825R0 - // compilers. Change to non-reference type and remove the moves - // below once C++20 is required to build gcc. - std::unique_ptr<AST::MacroInvocation> &&invoc + std::unique_ptr<AST::MacroInvocation> invoc = parse_macro_invocation_partial (std::move (path), std::move (outer_attrs)); @@ -7170,7 +7137,7 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, { invoc->add_semicolon (); // Macro invocation with semicolon. - return std::move (invoc); + return invoc; } TokenId after_macro = lexer.peek_token ()->get_id (); @@ -7178,14 +7145,14 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, if (restrictions.allow_close_after_expr_stmt && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY || after_macro == RIGHT_SQUARE)) - return std::move (invoc); + return invoc; if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type () == AST::CURLY && after_macro != DOT && after_macro != QUESTION_MARK) { rust_debug ("braced macro statement"); - return std::move (invoc); + return invoc; } null_denotation = std::move (invoc); @@ -7251,9 +7218,9 @@ Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs, // Parses a block expression, including the curly braces at start and end. template <typename ManagedTokenSource> std::unique_ptr<AST::BlockExpr> -Parser<ManagedTokenSource>::parse_block_expr (AST::AttrVec outer_attrs, - AST::LoopLabel label, - location_t pratt_parsed_loc) +Parser<ManagedTokenSource>::parse_block_expr ( + AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label, + location_t pratt_parsed_loc) { location_t locus = pratt_parsed_loc; if (locus == UNKNOWN_LOCATION) @@ -7278,11 +7245,7 @@ Parser<ManagedTokenSource>::parse_block_expr (AST::AttrVec outer_attrs, ExprOrStmt expr_or_stmt = parse_stmt_or_expr (); if (expr_or_stmt.is_error ()) { - Error error ( - t->get_locus (), - "failed to parse statement or expression in block expression"); - add_error (std::move (error)); - + skip_after_end_block (); return nullptr; } @@ -7323,6 +7286,51 @@ Parser<ManagedTokenSource>::parse_block_expr (AST::AttrVec outer_attrs, std::move (label), locus, end_locus)); } +/* Parse an anonymous const expression. This can be a regular const expression + * or an underscore for deferred const inference */ +template <typename ManagedTokenSource> +tl::expected<AST::AnonConst, AnonConstError> +Parser<ManagedTokenSource>::parse_anon_const () +{ + auto current = lexer.peek_token (); + auto locus = current->get_locus (); + + // Special case deferred inference constants + if (maybe_skip_token (UNDERSCORE)) + return AST::AnonConst (locus); + + auto expr = parse_expr (); + + if (!expr) + return tl::make_unexpected (AnonConstError::InvalidSizeExpr); + + return AST::AnonConst (std::move (expr), locus); +} + +/* Parse a "const block", a block preceded by the `const` keyword whose + * statements can be const evaluated and used in constant contexts */ +template <typename ManagedTokenSource> +std::unique_ptr<AST::ConstBlock> +Parser<ManagedTokenSource>::parse_const_block_expr (AST::AttrVec outer_attrs, + location_t locus) +{ + auto block = parse_block_expr (); + + if (!block) + { + add_error (Error (locus, "failed to parse inner block in const block")); + skip_after_end_block (); + + return nullptr; + } + + auto block_locus = block->get_locus (); + + return std::make_unique<AST::ConstBlock> (AST::AnonConst (std::move (block), + block_locus), + locus, std::move (outer_attrs)); +} + /* Parses a "grouped" expression (expression in parentheses), used to control * precedence. */ template <typename ManagedTokenSource> @@ -7603,6 +7611,34 @@ Parser<ManagedTokenSource>::parse_return_expr (AST::AttrVec outer_attrs, locus)); } +// Parses a try expression. +template <typename ManagedTokenSource> +std::unique_ptr<AST::TryExpr> +Parser<ManagedTokenSource>::parse_try_expr (AST::AttrVec outer_attrs, + location_t pratt_parsed_loc) +{ + location_t locus = pratt_parsed_loc; + if (locus == UNKNOWN_LOCATION) + { + locus = lexer.peek_token ()->get_locus (); + skip_token (TRY); + } + + std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr (); + + if (!block_expr) + { + Error error (lexer.peek_token ()->get_locus (), + "failed to parse try block expression"); + add_error (std::move (error)); + + return nullptr; + } + + return std::unique_ptr<AST::TryExpr> ( + new AST::TryExpr (std::move (block_expr), std::move (outer_attrs), locus)); +} + /* Parses a break expression (including any label to break to AND any return * expression). */ template <typename ManagedTokenSource> @@ -7617,12 +7653,10 @@ Parser<ManagedTokenSource>::parse_break_expr (AST::AttrVec outer_attrs, skip_token (BREAK); } - // parse label (lifetime) if it exists - create dummy first - AST::Lifetime label = AST::Lifetime::error (); - if (lexer.peek_token ()->get_id () == LIFETIME) - { - label = parse_lifetime (false); - } + auto parsed_label = parse_lifetime (false); + auto label = (parsed_label) + ? tl::optional<AST::Lifetime> (parsed_label.value ()) + : tl::nullopt; // parse break return expression if it exists ParseRestrictions restrictions; @@ -7648,12 +7682,10 @@ Parser<ManagedTokenSource>::parse_continue_expr (AST::AttrVec outer_attrs, skip_token (CONTINUE); } - // parse label (lifetime) if it exists - create dummy first - AST::Lifetime label = AST::Lifetime::error (); - if (lexer.peek_token ()->get_id () == LIFETIME) - { - label = parse_lifetime (false); - } + auto parsed_label = parse_lifetime (false); + auto label = (parsed_label) + ? tl::optional<AST::Lifetime> (parsed_label.value ()) + : tl::nullopt; return std::unique_ptr<AST::ContinueExpr> ( new AST::ContinueExpr (std::move (label), std::move (outer_attrs), locus)); @@ -7661,14 +7693,15 @@ Parser<ManagedTokenSource>::parse_continue_expr (AST::AttrVec outer_attrs, // Parses a loop label used in loop expressions. template <typename ManagedTokenSource> -AST::LoopLabel +tl::expected<AST::LoopLabel, ParseLoopLabelError> Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok) { // parse lifetime - if doesn't exist, assume no label if (tok->get_id () != LIFETIME) { // not necessarily an error - return AST::LoopLabel::error (); + return tl::unexpected<ParseLoopLabelError> ( + ParseLoopLabelError::NOT_LOOP_LABEL); } /* FIXME: check for named lifetime requirement here? or check in semantic * analysis phase? */ @@ -7677,10 +7710,12 @@ Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok) if (!skip_token (COLON)) { // skip somewhere? - return AST::LoopLabel::error (); + return tl::unexpected<ParseLoopLabelError> ( + ParseLoopLabelError::MISSING_COLON); } - return AST::LoopLabel (std::move (label), tok->get_locus ()); + return tl::expected<AST::LoopLabel, ParseLoopLabelError> ( + AST::LoopLabel (std::move (label), tok->get_locus ())); } /* Parses an if expression of any kind, including with else, else if, else if @@ -7733,14 +7768,7 @@ Parser<ManagedTokenSource>::parse_if_expr (AST::AttrVec outer_attrs, // parse required block expr std::unique_ptr<AST::BlockExpr> if_body = parse_block_expr (); if (if_body == nullptr) - { - Error error (lexer.peek_token ()->get_locus (), - "failed to parse if body block expression in if expression"); - add_error (std::move (error)); - - // skip somewhere? - return nullptr; - } + return nullptr; // branch to parse end or else (and then else, else if, or else if let) if (lexer.peek_token ()->get_id () != ELSE) @@ -7761,7 +7789,8 @@ Parser<ManagedTokenSource>::parse_if_expr (AST::AttrVec outer_attrs, const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case LEFT_CURLY: { + case LEFT_CURLY: + { // double selection - else // parse else block expr (required) std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr (); @@ -7782,7 +7811,8 @@ Parser<ManagedTokenSource>::parse_if_expr (AST::AttrVec outer_attrs, std::move (else_body), std::move (outer_attrs), locus)); } - case IF: { + case IF: + { // multiple selection - else if or else if let // branch on whether next token is 'let' or not if (lexer.peek_token (1)->get_id () == LET) @@ -7943,7 +7973,8 @@ Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs, const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case LEFT_CURLY: { + case LEFT_CURLY: + { // double selection - else // parse else block expr (required) std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr (); @@ -7965,7 +7996,8 @@ Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs, std::move (else_body), std::move (outer_attrs), locus)); } - case IF: { + case IF: + { // multiple selection - else if or else if let // branch on whether next token is 'let' or not if (lexer.peek_token (1)->get_id () == LET) @@ -8033,16 +8065,16 @@ Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs, template <typename ManagedTokenSource> std::unique_ptr<AST::LoopExpr> Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs, - AST::LoopLabel label, + tl::optional<AST::LoopLabel> label, location_t pratt_parsed_loc) { location_t locus = pratt_parsed_loc; if (locus == UNKNOWN_LOCATION) { - if (label.is_error ()) - locus = lexer.peek_token ()->get_locus (); + if (label) + locus = label->get_locus (); else - locus = label.get_locus (); + locus = lexer.peek_token ()->get_locus (); if (!skip_token (LOOP)) { @@ -8052,20 +8084,14 @@ Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs, } else { - if (!label.is_error ()) - locus = label.get_locus (); + if (label) + locus = label->get_locus (); } // parse loop body, which is required std::unique_ptr<AST::BlockExpr> loop_body = parse_block_expr (); if (loop_body == nullptr) - { - Error error (lexer.peek_token ()->get_locus (), - "could not parse loop body in (infinite) loop expression"); - add_error (std::move (error)); - - return nullptr; - } + return nullptr; return std::unique_ptr<AST::LoopExpr> ( new AST::LoopExpr (std::move (loop_body), locus, std::move (label), @@ -8076,17 +8102,17 @@ Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs, * via parse_labelled_loop_expr, which would call this. */ template <typename ManagedTokenSource> std::unique_ptr<AST::WhileLoopExpr> -Parser<ManagedTokenSource>::parse_while_loop_expr (AST::AttrVec outer_attrs, - AST::LoopLabel label, - location_t pratt_parsed_loc) +Parser<ManagedTokenSource>::parse_while_loop_expr ( + AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label, + location_t pratt_parsed_loc) { location_t locus = pratt_parsed_loc; if (locus == UNKNOWN_LOCATION) { - if (label.is_error ()) - locus = lexer.peek_token ()->get_locus (); + if (label) + locus = label->get_locus (); else - locus = label.get_locus (); + locus = lexer.peek_token ()->get_locus (); if (!skip_token (WHILE)) { @@ -8096,8 +8122,8 @@ Parser<ManagedTokenSource>::parse_while_loop_expr (AST::AttrVec outer_attrs, } else { - if (!label.is_error ()) - locus = label.get_locus (); + if (label) + locus = label->get_locus (); } // ensure it isn't a while let loop @@ -8149,14 +8175,14 @@ Parser<ManagedTokenSource>::parse_while_loop_expr (AST::AttrVec outer_attrs, * parsed via parse_labelled_loop_expr, which would call this. */ template <typename ManagedTokenSource> std::unique_ptr<AST::WhileLetLoopExpr> -Parser<ManagedTokenSource>::parse_while_let_loop_expr (AST::AttrVec outer_attrs, - AST::LoopLabel label) +Parser<ManagedTokenSource>::parse_while_let_loop_expr ( + AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label) { location_t locus = UNKNOWN_LOCATION; - if (label.is_error ()) - locus = lexer.peek_token ()->get_locus (); + if (label) + locus = label->get_locus (); else - locus = label.get_locus (); + locus = lexer.peek_token ()->get_locus (); maybe_skip_token (WHILE); /* check for possible accidental recognition of a while loop as a while let @@ -8177,7 +8203,14 @@ Parser<ManagedTokenSource>::parse_while_let_loop_expr (AST::AttrVec outer_attrs, // parse predicate patterns std::vector<std::unique_ptr<AST::Pattern>> predicate_patterns = parse_match_arm_patterns (EQUAL); - // TODO: have to ensure that there is at least 1 pattern? + // ensure that there is at least 1 pattern + if (predicate_patterns.empty ()) + { + Error error (lexer.peek_token ()->get_locus (), + "should be at least 1 pattern"); + add_error (std::move (error)); + return nullptr; + } if (!skip_token (EQUAL)) { @@ -8223,14 +8256,14 @@ Parser<ManagedTokenSource>::parse_while_let_loop_expr (AST::AttrVec outer_attrs, * parse_labelled_loop_expr, which would call this. */ template <typename ManagedTokenSource> std::unique_ptr<AST::ForLoopExpr> -Parser<ManagedTokenSource>::parse_for_loop_expr (AST::AttrVec outer_attrs, - AST::LoopLabel label) +Parser<ManagedTokenSource>::parse_for_loop_expr ( + AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label) { location_t locus = UNKNOWN_LOCATION; - if (label.is_error ()) - locus = lexer.peek_token ()->get_locus (); + if (label) + locus = label->get_locus (); else - locus = label.get_locus (); + locus = lexer.peek_token ()->get_locus (); maybe_skip_token (FOR); // parse pattern, which is required @@ -8308,8 +8341,9 @@ Parser<ManagedTokenSource>::parse_labelled_loop_expr (const_TokenPtr tok, } // parse loop label (required) - AST::LoopLabel label = parse_loop_label (tok); - if (label.is_error ()) + // TODO: Convert this return type to tl::expected instead of tl::optional + auto parsed_label = parse_loop_label (tok); + if (!parsed_label) { Error error (lexer.peek_token ()->get_locus (), "failed to parse loop label in labelled loop expr"); @@ -8319,6 +8353,10 @@ Parser<ManagedTokenSource>::parse_labelled_loop_expr (const_TokenPtr tok, return nullptr; } + auto label = parsed_label + ? tl::optional<AST::LoopLabel> (parsed_label.value ()) + : tl::nullopt; + // branch on next token const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) @@ -8693,10 +8731,10 @@ Parser<ManagedTokenSource>::parse_array_expr (AST::AttrVec outer_attrs, std::vector<std::unique_ptr<AST::Expr>> exprs; auto array_elems - = Rust::make_unique<AST::ArrayElemsValues> (std::move (exprs), locus); - return Rust::make_unique<AST::ArrayExpr> (std::move (array_elems), - std::move (inner_attrs), - std::move (outer_attrs), locus); + = std::make_unique<AST::ArrayElemsValues> (std::move (exprs), locus); + return std::make_unique<AST::ArrayExpr> (std::move (array_elems), + std::move (inner_attrs), + std::move (outer_attrs), locus); } else { @@ -9012,7 +9050,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) // slice type or array type - requires further disambiguation return parse_slice_or_array_type (); case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path in type AST::QualifiedPathInType path = parse_qualified_path_in_type (); if (path.is_error ()) @@ -9041,7 +9080,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) case LOGICAL_AND: // reference type return parse_reference_type (); - case LIFETIME: { + case LIFETIME: + { /* probably a lifetime bound, so probably type param bounds in * TraitObjectType */ std::vector<std::unique_ptr<AST::TypeParamBound>> bounds @@ -9057,7 +9097,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) case SELF_ALIAS: case CRATE: case DOLLAR_SIGN: - case SCOPE_RESOLUTION: { + case SCOPE_RESOLUTION: + { // macro invocation or type path - requires further disambiguation. /* for parsing path component of each rule, perhaps parse it as a * typepath and attempt conversion to simplepath if a trailing '!' is @@ -9087,7 +9128,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) t = lexer.peek_token (); switch (t->get_id ()) { - case EXCLAM: { + case EXCLAM: + { // macro invocation // convert to simple path AST::SimplePath macro_path = path.as_simple_path (); @@ -9113,7 +9155,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) std::move (tok_tree)), {}, locus); } - case PLUS: { + case PLUS: + { // type param bounds std::vector<std::unique_ptr<AST::TypeParamBound>> bounds; @@ -9198,14 +9241,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) t = lexer.peek_token (); if (t->get_id () != PLUS) { - // convert trait bound to value object - AST::TraitBound value_bound (*initial_bound); - - // DEBUG: removed as unique ptr, so should auto-delete - // delete initial_bound; - return std::unique_ptr<AST::ImplTraitTypeOneBound> ( - new AST::ImplTraitTypeOneBound (std::move (value_bound), + new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus)); } @@ -9233,7 +9270,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors) new AST::ImplTraitType (std::move (bounds), locus)); } case DYN: - case QUESTION_MARK: { + case QUESTION_MARK: + { // either TraitObjectType or TraitObjectTypeOneBound bool has_dyn = false; if (t->get_id () == DYN) @@ -9486,7 +9524,8 @@ Parser<ManagedTokenSource>::parse_for_prefixed_type () case SELF: case SELF_ALIAS: case CRATE: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { // path, so trait type // parse type path to finish parsing trait bound @@ -9696,8 +9735,12 @@ Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus) AST::Lifetime lifetime = AST::Lifetime::elided (); if (lexer.peek_token ()->get_id () == LIFETIME) { - lifetime = parse_lifetime (true); - if (lifetime.is_error ()) + auto parsed_lifetime = parse_lifetime (true); + if (parsed_lifetime) + { + lifetime = parsed_lifetime.value (); + } + else { Error error (lexer.peek_token ()->get_locus (), "failed to parse lifetime in reference type"); @@ -9828,13 +9871,15 @@ Parser<ManagedTokenSource>::parse_slice_or_array_type () return std::unique_ptr<AST::SliceType> ( new AST::SliceType (std::move (inner_type), locus)); - case SEMICOLON: { + case SEMICOLON: + { // array type lexer.skip_token (); // parse required array size expression - std::unique_ptr<AST::Expr> size = parse_expr (); - if (size == nullptr) + auto size = parse_anon_const (); + + if (!size) { Error error (lexer.peek_token ()->get_locus (), "failed to parse size expression in array type"); @@ -9849,7 +9894,8 @@ Parser<ManagedTokenSource>::parse_slice_or_array_type () } return std::unique_ptr<AST::ArrayType> ( - new AST::ArrayType (std::move (inner_type), std::move (size), locus)); + new AST::ArrayType (std::move (inner_type), std::move (*size), + locus)); } default: // error @@ -9879,7 +9925,8 @@ Parser<ManagedTokenSource>::parse_type_no_bounds () // slice type or array type - requires further disambiguation return parse_slice_or_array_type (); case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path in type AST::QualifiedPathInType path = parse_qualified_path_in_type (); if (path.is_error ()) @@ -9920,7 +9967,8 @@ Parser<ManagedTokenSource>::parse_type_no_bounds () case SELF_ALIAS: case CRATE: case DOLLAR_SIGN: - case SCOPE_RESOLUTION: { + case SCOPE_RESOLUTION: + { // macro invocation or type path - requires further disambiguation. /* for parsing path component of each rule, perhaps parse it as a * typepath and attempt conversion to simplepath if a trailing '!' is @@ -9948,7 +9996,8 @@ Parser<ManagedTokenSource>::parse_type_no_bounds () t = lexer.peek_token (); switch (t->get_id ()) { - case EXCLAM: { + case EXCLAM: + { // macro invocation // convert to simple path AST::SimplePath macro_path = path.as_simple_path (); @@ -10032,14 +10081,12 @@ Parser<ManagedTokenSource>::parse_type_no_bounds () return nullptr; } - // convert trait bound to value object - AST::TraitBound value_bound (*initial_bound); - return std::unique_ptr<AST::ImplTraitTypeOneBound> ( - new AST::ImplTraitTypeOneBound (std::move (value_bound), locus)); + new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus)); } case DYN: - case QUESTION_MARK: { + case QUESTION_MARK: + { // either TraitObjectTypeOneBound bool has_dyn = false; if (t->get_id () == DYN) @@ -10302,7 +10349,7 @@ Parser<ManagedTokenSource>::parse_literal_or_range_pattern () return std::unique_ptr<AST::LiteralPattern> ( new AST::LiteralPattern (range_lower->get_str (), type, range_lower->get_locus (), - range_lower->get_type_hint ())); + range_lower->get_type_hint (), has_minus)); } } @@ -10380,7 +10427,8 @@ Parser<ManagedTokenSource>::parse_range_pattern_bound () case SELF_ALIAS: case CRATE: case SCOPE_RESOLUTION: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { // path in expression AST::PathInExpression path = parse_path_in_expression (); if (path.is_error ()) @@ -10396,7 +10444,8 @@ Parser<ManagedTokenSource>::parse_range_pattern_bound () new AST::RangePatternBoundPath (std::move (path))); } case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path in expression AST::QualifiedPathInExpression path = parse_qualified_path_in_expression (); @@ -10438,16 +10487,22 @@ Parser<ManagedTokenSource>::parse_pattern () return first; std::vector<std::unique_ptr<AST::Pattern>> alts; - alts.push_back (std::move (first)); + if (first != nullptr) + alts.push_back (std::move (first)); do { lexer.skip_token (); - alts.push_back (parse_pattern_no_alt ()); + auto follow = parse_pattern_no_alt (); + if (follow != nullptr) + alts.push_back (std::move (follow)); } while (lexer.peek_token ()->get_id () == PIPE); + if (alts.empty ()) + return nullptr; + /* alternates */ return std::unique_ptr<AST::Pattern> ( new AST::AltPattern (std::move (alts), start_locus)); @@ -10541,7 +10596,8 @@ Parser<ManagedTokenSource>::parse_pattern_no_alt () // slice pattern return parse_slice_pattern (); case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path in expression or qualified range pattern bound AST::QualifiedPathInExpression path = parse_qualified_path_in_expression (); @@ -10577,7 +10633,8 @@ Parser<ManagedTokenSource>::parse_pattern_no_alt () case SELF_ALIAS: case CRATE: case SCOPE_RESOLUTION: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { // path in expression or range pattern bound AST::PathInExpression path = parse_path_in_expression (); @@ -10586,7 +10643,8 @@ Parser<ManagedTokenSource>::parse_pattern_no_alt () { case DOT_DOT_EQ: case DOT_DOT: - case ELLIPSIS: { + case ELLIPSIS: + { // qualified range pattern bound, so parse rest of range pattern AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ()); lexer.skip_token (); @@ -10604,7 +10662,8 @@ Parser<ManagedTokenSource>::parse_pattern_no_alt () case EXCLAM: return parse_macro_invocation_partial (std::move (path), AST::AttrVec ()); - case LEFT_PAREN: { + case LEFT_PAREN: + { // tuple struct lexer.skip_token (); @@ -10629,7 +10688,8 @@ Parser<ManagedTokenSource>::parse_pattern_no_alt () new AST::TupleStructPattern (std::move (path), std::move (items))); } - case LEFT_CURLY: { + case LEFT_CURLY: + { // struct lexer.skip_token (); @@ -10761,9 +10821,9 @@ Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern () return nullptr; } - // create ranged tuple pattern items with only upper items - std::unique_ptr<AST::TuplePatternItemsRanged> items ( - new AST::TuplePatternItemsRanged ( + // create tuple pattern items with only upper pattern items + std::unique_ptr<AST::TuplePatternItemsHasRest> items ( + new AST::TuplePatternItemsHasRest ( std::vector<std::unique_ptr<AST::Pattern>> (), std::move (patterns))); return std::unique_ptr<AST::TuplePattern> ( new AST::TuplePattern (std::move (items), paren_locus)); @@ -10771,8 +10831,8 @@ Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern () else if (lexer.peek_token ()->get_id () == RIGHT_PAREN) { skip_token (RIGHT_PAREN); - auto items = std::unique_ptr<AST::TuplePatternItemsMultiple> ( - new AST::TuplePatternItemsMultiple ( + auto items = std::unique_ptr<AST::TuplePatternItemsNoRest> ( + new AST::TuplePatternItemsNoRest ( std::vector<std::unique_ptr<AST::Pattern>> ())); return std::unique_ptr<AST::TuplePattern> ( new AST::TuplePattern (std::move (items), paren_locus)); @@ -10799,7 +10859,8 @@ Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern () return std::unique_ptr<AST::GroupedPattern> ( new AST::GroupedPattern (std::move (initial_pattern), paren_locus)); - case COMMA: { + case COMMA: + { // tuple pattern lexer.skip_token (); @@ -10835,8 +10896,8 @@ Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern () // non-ranged tuple pattern lexer.skip_token (); - std::unique_ptr<AST::TuplePatternItemsMultiple> items ( - new AST::TuplePatternItemsMultiple (std::move (patterns))); + std::unique_ptr<AST::TuplePatternItemsNoRest> items ( + new AST::TuplePatternItemsNoRest (std::move (patterns))); return std::unique_ptr<AST::TuplePattern> ( new AST::TuplePattern (std::move (items), paren_locus)); } @@ -10876,9 +10937,9 @@ Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern () return nullptr; } - std::unique_ptr<AST::TuplePatternItemsRanged> items ( - new AST::TuplePatternItemsRanged (std::move (patterns), - std::move (upper_patterns))); + std::unique_ptr<AST::TuplePatternItemsHasRest> items ( + new AST::TuplePatternItemsHasRest (std::move (patterns), + std::move (upper_patterns))); return std::unique_ptr<AST::TuplePattern> ( new AST::TuplePattern (std::move (items), paren_locus)); } @@ -10912,27 +10973,47 @@ Parser<ManagedTokenSource>::parse_slice_pattern () { location_t square_locus = lexer.peek_token ()->get_locus (); std::vector<std::unique_ptr<AST::Pattern>> patterns; + tl::optional<std::vector<std::unique_ptr<AST::Pattern>>> upper_patterns + = tl::nullopt; + + // lambda function to determine which vector to push new patterns into + auto get_pattern_ref + = [&] () -> std::vector<std::unique_ptr<AST::Pattern>> & { + return upper_patterns.has_value () ? upper_patterns.value () : patterns; + }; + skip_token (LEFT_SQUARE); if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) { skip_token (RIGHT_SQUARE); + std::unique_ptr<AST::SlicePatternItemsNoRest> items ( + new AST::SlicePatternItemsNoRest (std::move (patterns))); return std::unique_ptr<AST::SlicePattern> ( - new AST::SlicePattern (std::move (patterns), square_locus)); + new AST::SlicePattern (std::move (items), square_locus)); } // parse initial pattern (required) - std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern (); - if (initial_pattern == nullptr) + if (lexer.peek_token ()->get_id () == DOT_DOT) { - Error error (lexer.peek_token ()->get_locus (), - "failed to parse initial pattern in slice pattern"); - add_error (std::move (error)); - - return nullptr; + lexer.skip_token (); + upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> (); } + else + { + // Not a rest pattern `..`, parse normally + std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern (); + if (initial_pattern == nullptr) + { + Error error (lexer.peek_token ()->get_locus (), + "failed to parse initial pattern in slice pattern"); + add_error (std::move (error)); - patterns.push_back (std::move (initial_pattern)); + return nullptr; + } + + patterns.push_back (std::move (initial_pattern)); + } const_TokenPtr t = lexer.peek_token (); while (t->get_id () == COMMA) @@ -10943,6 +11024,23 @@ Parser<ManagedTokenSource>::parse_slice_pattern () if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) break; + if (lexer.peek_token ()->get_id () == DOT_DOT) + { + if (upper_patterns.has_value ()) + { + // DOT_DOT has been parsed before + Error error (lexer.peek_token ()->get_locus (), "%s", + "`..` can only be used once per slice pattern"); + add_error (std::move (error)); + + return nullptr; + } + upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> (); + lexer.skip_token (); + t = lexer.peek_token (); + continue; + } + // parse pattern (required) std::unique_ptr<AST::Pattern> pattern = parse_pattern (); if (pattern == nullptr) @@ -10953,7 +11051,7 @@ Parser<ManagedTokenSource>::parse_slice_pattern () return nullptr; } - patterns.push_back (std::move (pattern)); + get_pattern_ref ().push_back (std::move (pattern)); t = lexer.peek_token (); } @@ -10963,8 +11061,21 @@ Parser<ManagedTokenSource>::parse_slice_pattern () return nullptr; } + if (upper_patterns.has_value ()) + { + // Slice pattern with rest + std::unique_ptr<AST::SlicePatternItemsHasRest> items ( + new AST::SlicePatternItemsHasRest ( + std::move (patterns), std::move (upper_patterns.value ()))); + return std::unique_ptr<AST::SlicePattern> ( + new AST::SlicePattern (std::move (items), square_locus)); + } + + // Rest-less slice pattern + std::unique_ptr<AST::SlicePatternItemsNoRest> items ( + new AST::SlicePatternItemsNoRest (std::move (patterns))); return std::unique_ptr<AST::SlicePattern> ( - new AST::SlicePattern (std::move (patterns), square_locus)); + new AST::SlicePattern (std::move (items), square_locus)); } /* Parses an identifier pattern (pattern that binds a value matched to a @@ -11011,7 +11122,7 @@ Parser<ManagedTokenSource>::parse_identifier_pattern () lexer.skip_token (); // parse required pattern to bind - bind_pattern = parse_pattern (); + bind_pattern = parse_pattern_no_alt (); if (bind_pattern == nullptr) { Error error (lexer.peek_token ()->get_locus (), @@ -11056,7 +11167,8 @@ Parser<ManagedTokenSource>::parse_ident_leading_pattern () { case EXCLAM: return parse_macro_invocation_partial (std::move (path), AST::AttrVec ()); - case LEFT_PAREN: { + case LEFT_PAREN: + { // tuple struct lexer.skip_token (); @@ -11089,7 +11201,8 @@ Parser<ManagedTokenSource>::parse_ident_leading_pattern () return std::unique_ptr<AST::TupleStructPattern> ( new AST::TupleStructPattern (std::move (path), std::move (items))); } - case LEFT_CURLY: { + case LEFT_CURLY: + { // struct lexer.skip_token (); @@ -11110,7 +11223,8 @@ Parser<ManagedTokenSource>::parse_ident_leading_pattern () } case DOT_DOT_EQ: case DOT_DOT: - case ELLIPSIS: { + case ELLIPSIS: + { // range AST::RangeKind kind = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ()); @@ -11127,14 +11241,16 @@ Parser<ManagedTokenSource>::parse_ident_leading_pattern () std::move (upper_bound), kind, t->get_locus ())); } - case PATTERN_BIND: { + case PATTERN_BIND: + { // only allow on single-segment paths if (path.is_single_segment ()) { // identifier with pattern bind lexer.skip_token (); - std::unique_ptr<AST::Pattern> bind_pattern = parse_pattern (); + std::unique_ptr<AST::Pattern> bind_pattern + = parse_pattern_no_alt (); if (bind_pattern == nullptr) { Error error ( @@ -11219,9 +11335,9 @@ Parser<ManagedTokenSource>::parse_tuple_struct_items () rust_debug ( "finished parsing tuple struct items ranged (upper/none only)"); - return std::unique_ptr<AST::TupleStructItemsRange> ( - new AST::TupleStructItemsRange (std::move (lower_patterns), - std::move (upper_patterns))); + return std::unique_ptr<AST::TupleStructItemsHasRest> ( + new AST::TupleStructItemsHasRest (std::move (lower_patterns), + std::move (upper_patterns))); } // has at least some lower patterns @@ -11263,9 +11379,10 @@ Parser<ManagedTokenSource>::parse_tuple_struct_items () switch (t->get_id ()) { case RIGHT_PAREN: - return std::unique_ptr<AST::TupleStructItemsNoRange> ( - new AST::TupleStructItemsNoRange (std::move (lower_patterns))); - case DOT_DOT: { + return std::unique_ptr<AST::TupleStructItemsNoRest> ( + new AST::TupleStructItemsNoRest (std::move (lower_patterns))); + case DOT_DOT: + { // has an upper range that must be parsed separately lexer.skip_token (); @@ -11295,9 +11412,9 @@ Parser<ManagedTokenSource>::parse_tuple_struct_items () t = lexer.peek_token (); } - return std::unique_ptr<AST::TupleStructItemsRange> ( - new AST::TupleStructItemsRange (std::move (lower_patterns), - std::move (upper_patterns))); + return std::unique_ptr<AST::TupleStructItemsHasRest> ( + new AST::TupleStructItemsHasRest (std::move (lower_patterns), + std::move (upper_patterns))); } default: // error @@ -11317,7 +11434,7 @@ Parser<ManagedTokenSource>::parse_struct_pattern_elems () std::vector<std::unique_ptr<AST::StructPatternField>> fields; AST::AttrVec etc_attrs; - bool has_etc = false; + bool has_rest = false; // try parsing struct pattern fields const_TokenPtr t = lexer.peek_token (); @@ -11330,7 +11447,7 @@ Parser<ManagedTokenSource>::parse_struct_pattern_elems () { lexer.skip_token (); etc_attrs = std::move (outer_attrs); - has_etc = true; + has_rest = true; break; } @@ -11355,7 +11472,7 @@ Parser<ManagedTokenSource>::parse_struct_pattern_elems () t = lexer.peek_token (); } - if (has_etc) + if (has_rest) return AST::StructPatternElements (std::move (fields), std::move (etc_attrs)); else @@ -11385,7 +11502,8 @@ Parser<ManagedTokenSource>::parse_struct_pattern_field_partial ( const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { - case INT_LITERAL: { + case INT_LITERAL: + { // tuple index std::string index_str = t->get_str (); int index = atoi (index_str.c_str ()); @@ -11419,7 +11537,8 @@ Parser<ManagedTokenSource>::parse_struct_pattern_field_partial ( // branch on next token switch (lexer.peek_token (1)->get_id ()) { - case COLON: { + case COLON: + { // identifier-pattern Identifier ident{t}; lexer.skip_token (); @@ -11444,7 +11563,8 @@ Parser<ManagedTokenSource>::parse_struct_pattern_field_partial ( t->get_locus ())); } case COMMA: - case RIGHT_CURLY: { + case RIGHT_CURLY: + { // identifier only Identifier ident = {t}; lexer.skip_token (); @@ -11463,7 +11583,8 @@ Parser<ManagedTokenSource>::parse_struct_pattern_field_partial ( return nullptr; } case REF: - case MUT: { + case MUT: + { // only identifier bool has_ref = false; if (t->get_id () == REF) @@ -11535,7 +11656,8 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr () t = lexer.peek_token (); switch (t->get_id ()) { - case LET: { + case LET: + { // let statement std::unique_ptr<AST::LetStmt> stmt ( parse_let_stmt (std::move (outer_attrs))); @@ -11553,42 +11675,48 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr () case STATIC_KW: case AUTO: case TRAIT: - case IMPL: { + case IMPL: + { std::unique_ptr<AST::VisItem> item ( parse_vis_item (std::move (outer_attrs))); return ExprOrStmt (std::move (item)); } - /* TODO: implement union keyword but not really because of - * context-dependence crappy hack way to parse a union written below to - * separate it from the good code. */ - // case UNION: - case UNSAFE: { // maybe - unsafe traits are a thing + /* TODO: implement union keyword but not really because of + * context-dependence crappy hack way to parse a union written below to + * separate it from the good code. */ + // case UNION: + case UNSAFE: + { // maybe - unsafe traits are a thing /* if any of these (should be all possible VisItem prefixes), parse a * VisItem - can't parse item because would require reparsing outer * attributes */ const_TokenPtr t2 = lexer.peek_token (1); switch (t2->get_id ()) { - case LEFT_CURLY: { + case LEFT_CURLY: + { // unsafe block: parse as expression expr = parse_expr (std::move (outer_attrs), restrictions); break; } case AUTO: - case TRAIT: { + case TRAIT: + { // unsafe trait std::unique_ptr<AST::VisItem> item ( parse_vis_item (std::move (outer_attrs))); return ExprOrStmt (std::move (item)); } case EXTERN_KW: - case FN_KW: { + case FN_KW: + { // unsafe function std::unique_ptr<AST::VisItem> item ( parse_vis_item (std::move (outer_attrs))); return ExprOrStmt (std::move (item)); } - case IMPL: { + case IMPL: + { // unsafe trait impl std::unique_ptr<AST::VisItem> item ( parse_vis_item (std::move (outer_attrs))); @@ -11633,7 +11761,8 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr () case SELF_ALIAS: case CRATE: case SCOPE_RESOLUTION: - case DOLLAR_SIGN: { + case DOLLAR_SIGN: + { AST::PathInExpression path = parse_path_in_expression (); std::unique_ptr<AST::Expr> null_denotation; @@ -11642,6 +11771,8 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr () std::unique_ptr<AST::MacroInvocation> invoc = parse_macro_invocation_partial (std::move (path), std::move (outer_attrs)); + if (invoc == nullptr) + return ExprOrStmt::create_error (); if (restrictions.consume_semi && maybe_skip_token (SEMICOLON)) { @@ -11653,9 +11784,12 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr () TokenId after_macro = lexer.peek_token ()->get_id (); - if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type () - == AST::CURLY - && after_macro != DOT && after_macro != QUESTION_MARK) + AST::DelimType delim_type = invoc->get_invoc_data () + .get_delim_tok_tree () + .get_delim_type (); + + if (delim_type == AST::CURLY && after_macro != DOT + && after_macro != QUESTION_MARK) { rust_debug ("braced macro statement"); return ExprOrStmt ( @@ -11757,7 +11891,8 @@ Parser<ManagedTokenSource>::parse_struct_expr_field () std::move (outer_attrs), t->get_locus ())); } - case INT_LITERAL: { + case INT_LITERAL: + { // parse tuple index field int index = atoi (t->get_str ().c_str ()); lexer.skip_token (); @@ -11802,11 +11937,12 @@ Parser<ManagedTokenSource>::parse_struct_expr_field () } // "Unexpected token" panic mode - flags gcc error at unexpected token +// TODO: seems to be unused, remove? template <typename ManagedTokenSource> void Parser<ManagedTokenSource>::unexpected_token (const_TokenPtr t) { - Error error (t->get_locus (), "unexpected token %qs\n", + Error error (t->get_locus (), "unexpected token %qs", t->get_token_description ()); add_error (std::move (error)); } @@ -11997,7 +12133,7 @@ Parser<ManagedTokenSource>::skip_after_end_attribute () { const_TokenPtr t = lexer.peek_token (); - while (t->get_id () != RIGHT_SQUARE) + while (t->get_id () != RIGHT_SQUARE && t->get_id () != END_OF_FILE) { lexer.skip_token (); t = lexer.peek_token (); @@ -12028,20 +12164,14 @@ Parser<ManagedTokenSource>::parse_expr (int right_binding_power, return nullptr; } - if (current_token->get_id () == LEFT_SHIFT) - { - lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE); - current_token = lexer.peek_token (); - } - - lexer.skip_token (); - ParseRestrictions null_denotation_restrictions = restrictions; null_denotation_restrictions.expr_can_be_stmt = false; // parse null denotation (unary part of expression) std::unique_ptr<AST::Expr> expr - = null_denotation (current_token, {}, null_denotation_restrictions); + = null_denotation ({}, null_denotation_restrictions); + if (expr == nullptr) + return nullptr; return left_denotations (std::move (expr), right_binding_power, std::move (outer_attrs), restrictions); @@ -12109,8 +12239,7 @@ Parser<ManagedTokenSource>::parse_expr (AST::AttrVec outer_attrs, /* Determines action to take when finding token at beginning of expression. */ template <typename ManagedTokenSource> std::unique_ptr<AST::Expr> -Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok, - AST::AttrVec outer_attrs, +Parser<ManagedTokenSource>::null_denotation (AST::AttrVec outer_attrs, ParseRestrictions restrictions) { /* note: tok is previous character in input stream, not current one, as @@ -12120,6 +12249,8 @@ Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok, * denotation and then a left denotation), null denotations handle primaries * and unary operands (but only prefix unary operands) */ + auto tok = lexer.peek_token (); + switch (tok->get_id ()) { case IDENTIFIER: @@ -12127,27 +12258,27 @@ Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok, case SELF_ALIAS: case DOLLAR_SIGN: case CRATE: - case SUPER: { + case SUPER: + case SCOPE_RESOLUTION: + { // DEBUG rust_debug ("beginning null denotation identifier handling"); /* best option: parse as path, then extract identifier, macro, * struct/enum, or just path info from it */ - AST::PathInExpression path = parse_path_in_expression_pratt (tok); + AST::PathInExpression path = parse_path_in_expression (); return null_denotation_path (std::move (path), std::move (outer_attrs), restrictions); } - case SCOPE_RESOLUTION: { - // TODO: fix: this is for global paths, i.e. std::string::whatever - Error error (tok->get_locus (), - "found null denotation scope resolution operator, and " - "have not written handling for it"); - add_error (std::move (error)); - - return nullptr; - } default: + if (tok->get_id () == LEFT_SHIFT) + { + lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE); + tok = lexer.peek_token (); + } + + lexer.skip_token (); return null_denotation_not_path (std::move (tok), std::move (outer_attrs), restrictions); } @@ -12180,7 +12311,8 @@ Parser<ManagedTokenSource>::null_denotation_path ( // macro return parse_macro_invocation_partial (std::move (path), std::move (outer_attrs)); - case LEFT_CURLY: { + case LEFT_CURLY: + { bool not_a_block = lexer.peek_token (1)->get_id () == IDENTIFIER && (lexer.peek_token (2)->get_id () == COMMA || (lexer.peek_token (2)->get_id () == COLON @@ -12256,7 +12388,8 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( { // FIXME: Handle in null_denotation_path? case LEFT_SHIFT: - case LEFT_ANGLE: { + case LEFT_ANGLE: + { // qualified path // HACK: add outer attrs to path AST::QualifiedPathInExpression path @@ -12314,23 +12447,24 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( return parse_grouped_or_tuple_expr (std::move (outer_attrs), tok->get_locus ()); - /*case PLUS: { // unary plus operator - // invoke parse_expr recursively with appropriate priority, etc. for - below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS); + /*case PLUS: { // unary plus operator + // invoke parse_expr recursively with appropriate priority, etc. for + below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS); - if (expr == nullptr) - return nullptr; - // can only apply to integer and float expressions - if (expr->get_type() != integer_type_node || expr->get_type() != - float_type_node) { rust_error_at(tok->get_locus(), "operand of unary - plus must be int or float but it is %s", print_type(expr->get_type())); - return nullptr; - } + if (expr == nullptr) + return nullptr; + // can only apply to integer and float expressions + if (expr->get_type() != integer_type_node || expr->get_type() != + float_type_node) { rust_error_at(tok->get_locus(), "operand of unary + plus must be int or float but it is %s", print_type(expr->get_type())); + return nullptr; + } - return Tree(expr, tok->get_locus()); - }*/ - // Rust has no unary plus operator - case MINUS: { // unary minus + return Tree(expr, tok->get_locus()); + }*/ + // Rust has no unary plus operator + case MINUS: + { // unary minus ParseRestrictions entered_from_unary; entered_from_unary.entered_from_unary = true; if (!restrictions.can_be_struct_expr) @@ -12357,7 +12491,8 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( new AST::NegationExpr (std::move (expr), NegationOperator::NEGATE, std::move (outer_attrs), tok->get_locus ())); } - case EXCLAM: { // logical or bitwise not + case EXCLAM: + { // logical or bitwise not ParseRestrictions entered_from_unary; entered_from_unary.entered_from_unary = true; if (!restrictions.can_be_struct_expr) @@ -12382,7 +12517,8 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( new AST::NegationExpr (std::move (expr), NegationOperator::NOT, std::move (outer_attrs), tok->get_locus ())); } - case ASTERISK: { + case ASTERISK: + { /* pointer dereference only - HACK: as struct expressions should * always be value expressions, cannot be dereferenced */ ParseRestrictions entered_from_unary; @@ -12395,7 +12531,8 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( new AST::DereferenceExpr (std::move (expr), std::move (outer_attrs), tok->get_locus ())); } - case AMP: { + case AMP: + { // (single) "borrow" expression - shared (mutable) or immutable std::unique_ptr<AST::Expr> expr = nullptr; Mutability mutability = Mutability::Imm; @@ -12452,7 +12589,8 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( new AST::BorrowExpr (std::move (expr), mutability, raw_borrow, false, std::move (outer_attrs), tok->get_locus ())); } - case LOGICAL_AND: { + case LOGICAL_AND: + { // (double) "borrow" expression - shared (mutable) or immutable std::unique_ptr<AST::Expr> expr = nullptr; Mutability mutability = Mutability::Imm; @@ -12491,6 +12629,9 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( case RETURN_KW: // FIXME: is this really a null denotation expression? return parse_return_expr (std::move (outer_attrs), tok->get_locus ()); + case TRY: + // FIXME: is this really a null denotation expression? + return parse_try_expr (std::move (outer_attrs), tok->get_locus ()); case BREAK: // FIXME: is this really a null denotation expression? return parse_break_expr (std::move (outer_attrs), tok->get_locus ()); @@ -12498,8 +12639,8 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( return parse_continue_expr (std::move (outer_attrs), tok->get_locus ()); case LEFT_CURLY: // ok - this is an expression with block for once. - return parse_block_expr (std::move (outer_attrs), - AST::LoopLabel::error (), tok->get_locus ()); + return parse_block_expr (std::move (outer_attrs), tl::nullopt, + tok->get_locus ()); case IF: // if or if let, so more lookahead to find out if (lexer.peek_token ()->get_id () == LET) @@ -12515,7 +12656,7 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( case LIFETIME: return parse_labelled_loop_expr (tok, std::move (outer_attrs)); case LOOP: - return parse_loop_expr (std::move (outer_attrs), AST::LoopLabel::error (), + return parse_loop_expr (std::move (outer_attrs), tl::nullopt, tok->get_locus ()); case WHILE: if (lexer.peek_token ()->get_id () == LET) @@ -12524,13 +12665,11 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( } else { - return parse_while_loop_expr (std::move (outer_attrs), - AST::LoopLabel::error (), + return parse_while_loop_expr (std::move (outer_attrs), tl::nullopt, tok->get_locus ()); } case FOR: - return parse_for_loop_expr (std::move (outer_attrs), - AST::LoopLabel::error ()); + return parse_for_loop_expr (std::move (outer_attrs), tl::nullopt); case MATCH_KW: // also an expression with block return parse_match_expr (std::move (outer_attrs), tok->get_locus ()); @@ -12548,6 +12687,9 @@ Parser<ManagedTokenSource>::null_denotation_not_path ( "use of %qs is not allowed on the right-side of an assignment", tok->get_token_description ())); return nullptr; + case CONST: + return parse_const_block_expr (std::move (outer_attrs), + tok->get_locus ()); default: if (!restrictions.expr_can_be_null) add_error (Error (tok->get_locus (), @@ -12570,8 +12712,9 @@ Parser<ManagedTokenSource>::left_denotation (const_TokenPtr tok, // Token passed in has already been skipped, so peek gives "next" token switch (tok->get_id ()) { - // FIXME: allow for outer attributes to be applied - case QUESTION_MARK: { + // FIXME: allow for outer attributes to be applied + case QUESTION_MARK: + { location_t left_locus = left->get_locus (); // error propagation expression - unary postfix return std::unique_ptr<AST::ErrorPropagationExpr> ( @@ -12825,7 +12968,8 @@ Parser<ManagedTokenSource>::left_denotation (const_TokenPtr tok, "function - this should probably be handled elsewhere")); return nullptr; - case DOT: { + case DOT: + { /* field expression or method call - relies on parentheses after next * identifier or await if token after is "await" (unary postfix) or * tuple index if token after is a decimal int literal */ @@ -12899,12 +13043,6 @@ Parser<ManagedTokenSource>::left_denotation (const_TokenPtr tok, // array or slice index expression (pseudo binary infix) return parse_index_expr (tok, std::move (left), std::move (outer_attrs), restrictions); - case FLOAT_LITERAL: - /* HACK: get around lexer mis-identifying '.0' or '.1' or whatever as a - * float literal - TODO does this happen anymore? It shouldn't. */ - return parse_tuple_index_expr_float (tok, std::move (left), - std::move (outer_attrs), - restrictions); default: add_error (Error (tok->get_locus (), "found unexpected token %qs in left denotation", @@ -14141,7 +14279,8 @@ Parser<ManagedTokenSource>::parse_struct_expr_struct_partial ( * algorithm should work too. As such, AST type not happening. */ case IDENTIFIER: case HASH: - case INT_LITERAL: { + case INT_LITERAL: + { // struct with struct expr fields // parse struct expr fields @@ -14299,119 +14438,6 @@ Parser<ManagedTokenSource>::parse_struct_expr_tuple_partial ( std::move (outer_attrs), path_locus)); } -/* Parses a path in expression with the first token passed as a parameter (as - * it is skipped in token stream). Note that this only parses segment-first - * paths, not global ones. */ -template <typename ManagedTokenSource> -AST::PathInExpression -Parser<ManagedTokenSource>::parse_path_in_expression_pratt (const_TokenPtr tok) -{ - // HACK-y way of making up for pratt-parsing consuming first token - - // DEBUG - rust_debug ("current peek token when starting path pratt parse: '%s'", - lexer.peek_token ()->get_token_description ()); - - // create segment vector - std::vector<AST::PathExprSegment> segments; - - std::string initial_str; - - switch (tok->get_id ()) - { - case IDENTIFIER: - initial_str = tok->get_str (); - break; - case SUPER: - initial_str = Values::Keywords::SUPER; - break; - case SELF: - initial_str = Values::Keywords::SELF; - break; - case SELF_ALIAS: - initial_str = Values::Keywords::SELF_ALIAS; - break; - case CRATE: - initial_str = Values::Keywords::CRATE; - break; - case DOLLAR_SIGN: - if (lexer.peek_token ()->get_id () == CRATE) - { - initial_str = "$crate"; - break; - } - gcc_fallthrough (); - default: - add_error (Error (tok->get_locus (), - "unrecognised token %qs in path in expression", - tok->get_token_description ())); - - return AST::PathInExpression::create_error (); - } - - // parse required initial segment - AST::PathExprSegment initial_segment (initial_str, tok->get_locus ()); - // parse generic args (and turbofish), if they exist - /* use lookahead to determine if they actually exist (don't want to - * accidently parse over next ident segment) */ - if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION - && lexer.peek_token (1)->get_id () == LEFT_ANGLE) - { - // skip scope resolution - lexer.skip_token (); - - AST::GenericArgs generic_args = parse_path_generic_args (); - - initial_segment - = AST::PathExprSegment (AST::PathIdentSegment (initial_str, - tok->get_locus ()), - tok->get_locus (), std::move (generic_args)); - } - if (initial_segment.is_error ()) - { - // skip after somewhere? - // don't necessarily throw error but yeah - - // DEBUG - rust_debug ("initial segment is error - returning null"); - - return AST::PathInExpression::create_error (); - } - segments.push_back (std::move (initial_segment)); - - // parse optional segments (as long as scope resolution operator exists) - const_TokenPtr t = lexer.peek_token (); - while (t->get_id () == SCOPE_RESOLUTION) - { - // skip scope resolution operator - lexer.skip_token (); - - // parse the actual segment - it is an error if it doesn't exist now - AST::PathExprSegment segment = parse_path_expr_segment (); - if (segment.is_error ()) - { - // skip after somewhere? - Error error (t->get_locus (), - "could not parse path expression segment"); - add_error (std::move (error)); - - return AST::PathInExpression::create_error (); - } - - segments.push_back (std::move (segment)); - - t = lexer.peek_token (); - } - - // DEBUG: - rust_debug ( - "current token (just about to return path to null denotation): '%s'", - lexer.peek_token ()->get_token_description ()); - - return AST::PathInExpression (std::move (segments), {}, tok->get_locus (), - false); -} - // Parses a closure expression with pratt parsing (from null denotation). template <typename ManagedTokenSource> std::unique_ptr<AST::ClosureExpr> @@ -14438,7 +14464,8 @@ Parser<ManagedTokenSource>::parse_closure_expr_pratt (const_TokenPtr tok, case OR: // no parameters, don't skip token break; - case PIPE: { + case PIPE: + { // actually may have parameters // don't skip token const_TokenPtr t = lexer.peek_token (); @@ -14548,35 +14575,6 @@ Parser<ManagedTokenSource>::parse_closure_expr_pratt (const_TokenPtr tok, } } -/* Parses a tuple index expression (pratt-parsed) from a 'float' token as a - * result of lexer misidentification. */ -template <typename ManagedTokenSource> -std::unique_ptr<AST::TupleIndexExpr> -Parser<ManagedTokenSource>::parse_tuple_index_expr_float ( - const_TokenPtr tok, std::unique_ptr<AST::Expr> tuple_expr, - AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED) -{ - // only works on float literals - if (tok->get_id () != FLOAT_LITERAL) - return nullptr; - - // DEBUG: - rust_debug ("exact string form of float: '%s'", tok->get_str ().c_str ()); - - // get float string and remove dot and initial 0 - std::string index_str = tok->get_str (); - index_str.erase (index_str.begin ()); - - // get int from string - int index = atoi (index_str.c_str ()); - - location_t locus = tuple_expr->get_locus (); - - return std::unique_ptr<AST::TupleIndexExpr> ( - new AST::TupleIndexExpr (std::move (tuple_expr), index, - std::move (outer_attrs), locus)); -} - // Returns true if the next token is END, ELSE, or EOF; template <typename ManagedTokenSource> bool |
