LCOV - code coverage report
Current view: top level - gcc/rust/ast - rust-ast-collector.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 82.3 % 2282 1877
Test Date: 2026-10-24 16:24:59 Functions: 90.0 % 370 333
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-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              : #include "rust-ast-collector.h"
      20              : #include "rust-ast.h"
      21              : #include "rust-builtin-ast-nodes.h"
      22              : #include "rust-diagnostics.h"
      23              : #include "rust-expr.h"
      24              : #include "rust-item.h"
      25              : #include "rust-keyword-values.h"
      26              : #include "rust-path.h"
      27              : #include "rust-system.h"
      28              : #include "rust-token.h"
      29              : 
      30              : namespace Rust {
      31              : namespace AST {
      32              : 
      33              : std::vector<TokenPtr>
      34          174 : TokenCollector::collect_tokens () const
      35              : {
      36          174 :   std::vector<TokenPtr> result;
      37         9436 :   for (auto item : tokens)
      38              :     {
      39         9262 :       if (item.get_kind () == CollectItem::Kind::Token)
      40              :         {
      41         3104 :           result.emplace_back (item.get_token ());
      42              :         }
      43         9262 :     }
      44          174 :   return result;
      45              : }
      46              : 
      47              : std::vector<CollectItem>
      48         4449 : TokenCollector::collect () const
      49              : {
      50         4449 :   return tokens;
      51              : }
      52              : 
      53              : void
      54         4446 : TokenCollector::visit (AST::Crate &crate)
      55              : {
      56         4446 :   visit_items_as_lines (crate.inner_attrs);
      57         4446 :   visit_items_as_lines (crate.items);
      58         4446 : }
      59              : 
      60              : void
      61            3 : TokenCollector::visit (AST::Item &item)
      62              : {
      63            3 :   item.accept_vis (*this);
      64            3 : }
      65              : 
      66              : void
      67         4520 : TokenCollector::trailing_comma ()
      68              : {
      69         4520 :   if (output_trailing_commas)
      70              :     {
      71            0 :       push (Rust::Token::make (COMMA, UNDEF_LOCATION));
      72              :     }
      73         4520 : }
      74              : 
      75              : void
      76       218399 : TokenCollector::newline ()
      77              : {
      78       218399 :   tokens.emplace_back (CollectItem::Kind::Newline);
      79       218399 : }
      80              : 
      81              : void
      82       158715 : TokenCollector::indentation ()
      83              : {
      84       158715 :   tokens.emplace_back (indent_level);
      85       158715 : }
      86              : 
      87              : void
      88        38351 : TokenCollector::increment_indentation ()
      89              : {
      90        38351 :   indent_level++;
      91        38351 : }
      92              : 
      93              : void
      94        38351 : TokenCollector::decrement_indentation ()
      95              : {
      96        38351 :   rust_assert (indent_level != 0);
      97        38351 :   indent_level--;
      98        38351 : }
      99              : 
     100              : void
     101            0 : TokenCollector::comment (std::string comment)
     102              : {
     103            0 :   tokens.emplace_back (CollectItem::make_comment (comment));
     104            0 : }
     105              : 
     106              : void
     107       725136 : TokenCollector::describe_node (const std::string &node_name,
     108              :                                std::function<void ()> visitor)
     109              : {
     110       725136 :   tokens.emplace_back (CollectItem::make_begin_node_description (node_name));
     111              : 
     112       725136 :   visitor ();
     113              : 
     114       725136 :   tokens.push_back (CollectItem::make_end_node_description (node_name));
     115       725136 : }
     116              : 
     117              : void
     118            0 : TokenCollector::visit (Visitable &v)
     119              : {
     120            0 :   v.accept_vis (*this);
     121            0 : }
     122              : 
     123              : void
     124        11850 : TokenCollector::visit (FunctionParam &param)
     125              : {
     126        11850 :   describe_node (std::string ("FunctionParam"), [this, &param] () {
     127        11850 :     visit_items_as_lines (param.get_outer_attrs ());
     128        11850 :     if (!param.is_variadic ())
     129              :       {
     130        11850 :         visit (param.get_pattern ());
     131        11850 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
     132        11850 :         visit (param.get_type ());
     133              :       }
     134              :     else
     135              :       {
     136            0 :         if (param.has_name ())
     137              :           {
     138            0 :             visit (param.get_pattern ());
     139            0 :             push (Rust::Token::make (COLON, UNDEF_LOCATION));
     140              :           }
     141            0 :         push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
     142              :       }
     143        11850 :   });
     144        11850 : }
     145              : 
     146              : void
     147          883 : TokenCollector::visit (VariadicParam &param)
     148              : {
     149          883 :   describe_node (std::string ("VariadicParam"), [this, &param] () {
     150          883 :     if (param.has_pattern ())
     151              :       {
     152            9 :         visit (param.get_pattern ());
     153           18 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
     154              :       }
     155          883 :     push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
     156          883 :   });
     157          883 : }
     158              : 
     159              : void
     160        27516 : TokenCollector::visit (Attribute &attrib)
     161              : {
     162        27516 :   describe_node (std::string ("Attribute"), [this, &attrib] () {
     163        27516 :     push (Rust::Token::make (HASH, attrib.get_locus ()));
     164        27516 :     if (attrib.is_inner_attribute ())
     165        22878 :       push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
     166        27516 :     push (Rust::Token::make (LEFT_SQUARE, UNDEF_LOCATION));
     167        27516 :     visit (attrib.get_path ());
     168              : 
     169        27516 :     if (attrib.has_attr_input ())
     170              :       {
     171        21320 :         switch (attrib.get_attr_input ().get_attr_input_type ())
     172              :           {
     173        11524 :           case AST::AttrInput::AttrInputType::LITERAL:
     174        11524 :             {
     175        11524 :               visit (
     176        11524 :                 static_cast<AttrInputLiteral &> (attrib.get_attr_input ()));
     177        11524 :               break;
     178              :             }
     179            1 :           case AST::AttrInput::AttrInputType::EXPR:
     180            1 :             {
     181            1 :               visit (static_cast<AttrInputExpr &> (attrib.get_attr_input ()));
     182            1 :               break;
     183              :             }
     184          422 :           case AST::AttrInput::AttrInputType::META_ITEM:
     185          422 :             {
     186          422 :               visit (static_cast<AttrInputMetaItemContainer &> (
     187          422 :                 attrib.get_attr_input ()));
     188          422 :               break;
     189              :             }
     190         9373 :           case AST::AttrInput::AttrInputType::TOKEN_TREE:
     191         9373 :             {
     192         9373 :               visit (static_cast<DelimTokenTree &> (attrib.get_attr_input ()));
     193         9373 :               break;
     194              :             }
     195            0 :           default:
     196            0 :             rust_unreachable ();
     197              :           }
     198              :       }
     199        27516 :     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
     200        27516 :   });
     201        27516 : }
     202              : 
     203              : void
     204        29029 : TokenCollector::visit (SimplePath &path)
     205              : {
     206        29029 :   describe_node (std::string ("SimplePath"), [this, &path] () {
     207        29029 :     if (path.has_opening_scope_resolution ())
     208              :       {
     209            0 :         push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ()));
     210              :       }
     211        29029 :     visit_items_joined_by_separator (path.get_segments (), SCOPE_RESOLUTION);
     212        29029 :   });
     213        29029 : }
     214              : 
     215              : void
     216        30031 : TokenCollector::visit (SimplePathSegment &segment)
     217              : {
     218        30031 :   describe_node (std::string ("SimplePathSegment"), [this, &segment] () {
     219        30031 :     auto name = segment.get_segment_name ();
     220        30031 :     if (segment.is_crate_path_seg ())
     221              :       {
     222          268 :         push (Rust::Token::make (CRATE, segment.get_locus ()));
     223              :       }
     224        29897 :     else if (segment.is_super_path_seg ())
     225              :       {
     226          604 :         push (Rust::Token::make (SUPER, segment.get_locus ()));
     227              :       }
     228        29595 :     else if (segment.is_lower_self_seg ())
     229              :       {
     230          150 :         push (Rust::Token::make (SELF, segment.get_locus ()));
     231              :       }
     232        29520 :     else if (segment.is_big_self ())
     233              :       {
     234            0 :         push (Rust::Token::make (SELF_ALIAS, segment.get_locus ()));
     235              :       }
     236              :     else
     237              :       {
     238        59040 :         push (Rust::Token::make_identifier (segment.get_locus (),
     239              :                                             std::move (name)));
     240              :       }
     241        30031 :   });
     242        30031 : }
     243              : 
     244              : void
     245        29852 : TokenCollector::visit (Visibility &vis)
     246              : {
     247        29852 :   describe_node (std::string ("Visibility"), [this, &vis] () {
     248        29852 :     switch (vis.get_vis_type ())
     249              :       {
     250         9029 :       case Visibility::PUB:
     251         9029 :         push (Rust::Token::make (PUB, vis.get_locus ()));
     252         9029 :         break;
     253           47 :       case Visibility::PUB_CRATE:
     254           47 :         push (Rust::Token::make (PUB, vis.get_locus ()));
     255           47 :         push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
     256           47 :         push (Rust::Token::make (CRATE, UNDEF_LOCATION));
     257           47 :         push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
     258           47 :         break;
     259            0 :       case Visibility::PUB_SELF:
     260            0 :         push (Rust::Token::make (PUB, vis.get_locus ()));
     261            0 :         push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
     262            0 :         push (Rust::Token::make (SELF, UNDEF_LOCATION));
     263            0 :         push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
     264            0 :         break;
     265            1 :       case Visibility::PUB_SUPER:
     266            1 :         push (Rust::Token::make (PUB, vis.get_locus ()));
     267            1 :         push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
     268            1 :         push (Rust::Token::make (SUPER, UNDEF_LOCATION));
     269            1 :         push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
     270            1 :         break;
     271            3 :       case Visibility::PUB_IN_PATH:
     272            3 :         push (Rust::Token::make (PUB, vis.get_locus ()));
     273            3 :         push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
     274            3 :         push (Rust::Token::make (IN, UNDEF_LOCATION));
     275            3 :         visit (vis.get_path ());
     276            3 :         push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
     277            3 :         break;
     278              :       case Visibility::PRIV:
     279              :         break;
     280              :       }
     281        29852 :   });
     282        29852 : }
     283              : 
     284              : void
     285         9702 : TokenCollector::visit (std::vector<std::unique_ptr<GenericParam>> &params)
     286              : {
     287         9702 :   describe_node (std::string ("GenericParam"), [this, &params] () {
     288         9702 :     push (Rust::Token::make (LEFT_ANGLE, UNDEF_LOCATION));
     289         9702 :     visit_items_joined_by_separator (params, COMMA);
     290         9702 :     push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
     291         9702 :   });
     292         9702 : }
     293              : 
     294              : void
     295         2155 : TokenCollector::visit (TupleField &field)
     296              : {
     297         2155 :   describe_node (std::string ("TupleField"), [this, &field] () {
     298         2212 :     for (auto attr : field.get_outer_attrs ())
     299              :       {
     300           57 :         visit (attr);
     301           57 :       }
     302         2155 :     visit (field.get_visibility ());
     303         2155 :     visit (field.get_field_type ());
     304         2155 :   });
     305         2155 : }
     306              : 
     307              : void
     308         2316 : TokenCollector::visit (StructField &field)
     309              : {
     310         2316 :   describe_node (std::string ("StructField"), [this, &field] () {
     311         2317 :     for (auto attr : field.get_outer_attrs ())
     312              :       {
     313            1 :         visit (attr);
     314            1 :       }
     315         2316 :     visit (field.get_visibility ());
     316         4632 :     auto name = field.get_field_name ().as_string ();
     317         4632 :     push (Rust::Token::make_identifier (field.get_locus (), std::move (name)));
     318         2316 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
     319         2316 :     visit (field.get_field_type ());
     320         2316 :   });
     321         2316 : }
     322              : 
     323              : void
     324           14 : TokenCollector::visit (std::vector<LifetimeParam> &for_lifetimes)
     325              : {
     326           14 :   describe_node (std::string ("LifetimeParam"), [this, &for_lifetimes] () {
     327           14 :     push (Rust::Token::make (FOR, UNDEF_LOCATION));
     328           14 :     push (Rust::Token::make (LEFT_ANGLE, UNDEF_LOCATION));
     329           14 :     visit_items_joined_by_separator (for_lifetimes, COMMA);
     330           14 :     push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
     331           14 :   });
     332           14 : }
     333              : 
     334              : void
     335        19598 : TokenCollector::visit (FunctionQualifiers &qualifiers)
     336              : {
     337              :   // Syntax:
     338              :   //    `const`? `async`? `unsafe`? (`extern` Abi?)?
     339              :   //    unsafe? (extern Abi?)?
     340        19598 :   describe_node (std::string ("FunctionQualifiers"), [this, &qualifiers] () {
     341        19598 :     if (qualifiers.is_async ())
     342            2 :       push (Rust::Token::make (ASYNC, qualifiers.get_locus ()));
     343        19598 :     if (qualifiers.is_const ())
     344         1990 :       push (Rust::Token::make (CONST, qualifiers.get_locus ()));
     345        19598 :     if (qualifiers.is_unsafe ())
     346         1118 :       push (Rust::Token::make (UNSAFE, qualifiers.get_locus ()));
     347        19598 :     if (qualifiers.is_extern ())
     348              :       {
     349           75 :         push (Rust::Token::make (EXTERN_KW, qualifiers.get_locus ()));
     350           75 :         if (qualifiers.has_abi ())
     351              :           {
     352          150 :             push (Rust::Token::make_string (UNDEF_LOCATION,
     353          225 :                                             qualifiers.get_extern_abi ()));
     354              :           }
     355              :       }
     356        19598 :   });
     357        19598 : }
     358              : 
     359              : void
     360           66 : TokenCollector::visit (MaybeNamedParam &param)
     361              : {
     362              :   // Syntax:
     363              :   //     OuterAttribute* ( ( IDENTIFIER | _ ) : )? Type
     364              : 
     365           66 :   describe_node (std::string ("MaybeNamedParam"), [this, &param] () {
     366           66 :     for (auto attr : param.get_outer_attrs ())
     367              :       {
     368            0 :         visit (attr);
     369            0 :       }
     370          132 :     auto param_name = param.get_name ().as_string ();
     371           66 :     switch (param.get_param_kind ())
     372              :       {
     373              :       case MaybeNamedParam::UNNAMED:
     374              :         break;
     375            0 :       case MaybeNamedParam::IDENTIFIER:
     376            0 :         push (Rust::Token::make_identifier (UNDEF_LOCATION,
     377              :                                             std::move (param_name)));
     378            0 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
     379            0 :         break;
     380            6 :       case MaybeNamedParam::WILDCARD:
     381            6 :         push (Rust::Token::make (UNDERSCORE, UNDEF_LOCATION));
     382            6 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
     383            6 :         break;
     384              :       }
     385           66 :     visit (param.get_type ());
     386           66 :   });
     387           66 : }
     388              : 
     389              : void
     390        81246 : TokenCollector::visit (Token &tok)
     391              : {
     392        81246 :   std::string data
     393       106367 :     = tok.get_tok_ptr ()->should_have_str () ? tok.get_str () : "";
     394        81246 :   switch (tok.get_id ())
     395              :     {
     396        20478 :     case IDENTIFIER:
     397        40956 :       push (Rust::Token::make_identifier (tok.get_locus (), std::move (data)));
     398        20478 :       break;
     399          394 :     case INT_LITERAL:
     400          394 :       {
     401          394 :         auto suffix_start = data.length ();
     402          788 :         push (Rust::Token::make_int (tok.get_locus (), std::move (data),
     403              :                                      suffix_start, IntegerLiteralBase::Decimal,
     404              :                                      tok.get_type_hint ()));
     405          394 :         break;
     406              :       }
     407            0 :     case FLOAT_LITERAL:
     408            0 :       {
     409            0 :         auto suffix_start = data.length ();
     410            0 :         push (Rust::Token::make_float (tok.get_locus (), std::move (data),
     411              :                                        suffix_start, tok.get_type_hint ()));
     412            0 :         break;
     413              :       }
     414         4239 :     case STRING_LITERAL:
     415         8478 :       push (Rust::Token::make_string (tok.get_locus (), std::move (data)));
     416         4239 :       break;
     417            0 :     case CHAR_LITERAL:
     418            0 :       push (Rust::Token::make_char (
     419              :         tok.get_locus (),
     420              :         // FIXME: This need to be fixed to properly support UTF-8
     421            0 :         static_cast<uint32_t> (data[0])));
     422            0 :       break;
     423            0 :     case BYTE_CHAR_LITERAL:
     424            0 :       push (Rust::Token::make_byte_char (tok.get_locus (), data[0]));
     425            0 :       break;
     426            0 :     case BYTE_STRING_LITERAL:
     427            0 :       push (Rust::Token::make_byte_string (tok.get_locus (), std::move (data)));
     428            0 :       break;
     429            0 :     case RAW_STRING_LITERAL:
     430            0 :       push (Rust::Token::make_raw_string (tok.get_locus (), std::move (data)));
     431            0 :       break;
     432            0 :     case C_STRING_LITERAL:
     433            0 :       push (Rust::Token::make_c_string (tok.get_locus (), std::move (data)));
     434            0 :       break;
     435            0 :     case INNER_DOC_COMMENT:
     436            0 :       push (Rust::Token::make_inner_doc_comment (tok.get_locus (),
     437              :                                                  std::move (data)));
     438            0 :       break;
     439            0 :     case OUTER_DOC_COMMENT:
     440            0 :       push (Rust::Token::make_outer_doc_comment (tok.get_locus (),
     441              :                                                  std::move (data)));
     442            0 :       break;
     443           10 :     case LIFETIME:
     444           20 :       push (Rust::Token::make_lifetime (tok.get_locus (), std::move (data)));
     445           10 :       break;
     446        56125 :     default:
     447       112250 :       push (Rust::Token::make (tok.get_id (), tok.get_locus ()));
     448              :     }
     449        81246 : }
     450              : 
     451              : void
     452        10656 : TokenCollector::visit (DelimTokenTree &delim_tok_tree)
     453              : {
     454        10656 :   describe_node (std::string ("DelimTokenTree"), [this, &delim_tok_tree] () {
     455        91423 :     for (auto &token : delim_tok_tree.to_token_stream ())
     456              :       {
     457        80767 :         visit (token);
     458        10656 :       }
     459        10656 :   });
     460        10656 : }
     461              : 
     462              : void
     463          422 : TokenCollector::visit (AttrInputMetaItemContainer &container)
     464              : {
     465          422 :   describe_node (std::string ("AttrInputMetaItemContainer"),
     466          422 :                  [this, &container] () {
     467          844 :                    for (auto &item : container.get_items ())
     468              :                      {
     469          422 :                        visit (item);
     470              :                      }
     471          422 :                  });
     472          422 : }
     473              : 
     474              : void
     475        26395 : TokenCollector::visit (IdentifierExpr &ident_expr)
     476              : {
     477        26395 :   describe_node (std::string ("IdentifierExpr"), [this, &ident_expr] () {
     478        52790 :     auto ident = ident_expr.get_ident ().as_string ();
     479        52790 :     push (Rust::Token::make_identifier (ident_expr.get_locus (),
     480              :                                         std::move (ident)));
     481        26395 :   });
     482        26395 : }
     483              : 
     484              : void
     485        10217 : TokenCollector::visit (Lifetime &lifetime)
     486              : {
     487              :   // Syntax:
     488              :   // Lifetime :
     489              :   //    LIFETIME_OR_LABEL
     490              :   //    | 'static
     491              :   //    | '_
     492              : 
     493        10217 :   describe_node (std::string ("Lifetime"), [this, &lifetime] () {
     494        10217 :     auto name = lifetime.get_lifetime_name ();
     495        10217 :     switch (lifetime.get_lifetime_type ())
     496              :       {
     497          555 :       case Lifetime::LifetimeType::NAMED:
     498          555 :         push (
     499         1110 :           Rust::Token::make_lifetime (lifetime.get_locus (), std::move (name)));
     500          555 :         break;
     501          120 :       case Lifetime::LifetimeType::STATIC:
     502          240 :         push (Rust::Token::make_lifetime (lifetime.get_locus (),
     503          120 :                                           Values::Keywords::STATIC_KW));
     504          120 :         break;
     505         9542 :       case Lifetime::LifetimeType::WILDCARD:
     506        19084 :         push (Rust::Token::make_lifetime (lifetime.get_locus (),
     507         9542 :                                           Values::Keywords::UNDERSCORE));
     508         9542 :         break;
     509              :       }
     510        10217 :   });
     511        10217 : }
     512              : 
     513              : void
     514          182 : TokenCollector::visit (LifetimeParam &lifetime_param)
     515              : {
     516              :   // Syntax:
     517              :   //   LIFETIME_OR_LABEL ( : LifetimeBounds )?
     518              :   // LifetimeBounds :
     519              :   //   ( Lifetime + )* Lifetime?
     520              : 
     521              :   // TODO what to do with outer attr? They are not mentioned in the reference.
     522          182 :   describe_node (std::string ("LifetimeParam"), [this, &lifetime_param] () {
     523          182 :     visit_items_as_lines (lifetime_param.get_outer_attrs ());
     524          182 :     auto lifetime = lifetime_param.get_lifetime ();
     525          182 :     visit (lifetime);
     526              : 
     527          182 :     if (lifetime_param.has_lifetime_bounds ())
     528              :       {
     529            0 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
     530            0 :         for (auto &bound : lifetime_param.get_lifetime_bounds ())
     531              :           {
     532            0 :             visit (bound);
     533              :           }
     534              :       }
     535          182 :   });
     536          182 : }
     537              : 
     538              : void
     539           78 : TokenCollector::visit (ConstGenericParam &param)
     540              : {
     541              :   // Syntax:
     542              :   // const IDENTIFIER : Type ( = Block | IDENTIFIER | -?LITERAL )?
     543           78 :   describe_node (std::string ("ConstGenericParam"), [this, &param] () {
     544           78 :     visit_items_as_lines (param.get_outer_attrs ());
     545           78 :     push (Rust::Token::make (CONST, param.get_locus ()));
     546           78 :     auto id = param.get_name ().as_string ();
     547          156 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
     548           78 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
     549           78 :     if (param.has_type ())
     550           78 :       visit (param.get_type ());
     551           78 :     if (param.has_default_value ())
     552              :       {
     553            6 :         push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
     554            6 :         visit (param.get_default_value_unchecked ());
     555              :       }
     556           78 :   });
     557           78 : }
     558              : 
     559              : void
     560        41000 : TokenCollector::visit (PathExprSegment &segment)
     561              : {
     562        41000 :   describe_node (std::string ("PathExprSegment"), [this, &segment] () {
     563        41000 :     visit (segment.get_ident_segment ());
     564        41000 :     if (segment.has_generic_args ())
     565              :       {
     566         1000 :         auto generics = segment.get_generic_args ();
     567         1000 :         push (Rust::Token::make (SCOPE_RESOLUTION, segment.get_locus ()));
     568         1000 :         push (Rust::Token::make (LEFT_ANGLE, generics.get_locus ()));
     569              : 
     570         1000 :         auto &lifetime_args = generics.get_lifetime_args ();
     571         1000 :         auto &generic_args = generics.get_generic_args ();
     572         1000 :         auto &binding_args = generics.get_binding_args ();
     573              : 
     574         1000 :         visit_items_joined_by_separator (generic_args, COMMA);
     575              : 
     576         1000 :         if (!lifetime_args.empty ()
     577         1000 :             && (!generic_args.empty () || !binding_args.empty ()))
     578              :           {
     579            0 :             push (Rust::Token::make (COMMA, UNDEF_LOCATION));
     580              :           }
     581              : 
     582         1000 :         visit_items_joined_by_separator (binding_args, COMMA);
     583              : 
     584         1000 :         if (!generic_args.empty () && !binding_args.empty ())
     585              :           {
     586            0 :             push (Rust::Token::make (COMMA, UNDEF_LOCATION));
     587              :           }
     588              : 
     589         1000 :         visit_items_joined_by_separator (lifetime_args, COMMA);
     590              : 
     591         1000 :         push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
     592         1000 :       }
     593        41000 :   });
     594        41000 : }
     595              : 
     596              : void
     597        27573 : TokenCollector::visit (PathInExpression &path)
     598              : {
     599        27573 :   describe_node (std::string ("PathInExpression"), [this, &path] () {
     600        27573 :     if (path.is_lang_item ())
     601              :       {
     602          167 :         push (Rust::Token::make (TokenId::HASH, path.get_locus ()));
     603          167 :         push (Rust::Token::make (TokenId::LEFT_SQUARE, path.get_locus ()));
     604          334 :         push (Rust::Token::make_identifier (path.get_locus (), "lang"));
     605          167 :         push (Rust::Token::make (TokenId::EQUAL, path.get_locus ()));
     606          334 :         push (Rust::Token::make_string (
     607          167 :           path.get_locus (), LangItem::ToString (path.get_lang_item ())));
     608          167 :         push (Rust::Token::make (TokenId::RIGHT_SQUARE, path.get_locus ()));
     609              : 
     610          167 :         return;
     611              :       }
     612              : 
     613        27406 :     if (path.opening_scope_resolution ())
     614          766 :       push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ()));
     615              : 
     616        27406 :     visit_items_joined_by_separator (path.get_segments (), SCOPE_RESOLUTION);
     617              :   });
     618        27573 : }
     619              : 
     620              : void
     621        60275 : TokenCollector::visit (TypePathSegment &segment)
     622              : {
     623              :   // Syntax:
     624              :   //    PathIdentSegment
     625        60275 :   describe_node (std::string ("TypePathSegment"), [this, &segment] () {
     626        60275 :     auto locus = segment.is_lang_item ()
     627        60275 :                    ? segment.get_locus ()
     628        59937 :                    : segment.get_ident_segment ().get_locus ();
     629        60275 :     auto segment_string = segment.is_lang_item ()
     630        60275 :                             ? LangItem::PrettyString (segment.get_lang_item ())
     631        60275 :                             : segment.get_ident_segment ().as_string ();
     632       120550 :     push (Rust::Token::make_identifier (locus, std::move (segment_string)));
     633        60275 :   });
     634        60275 : }
     635              : 
     636              : void
     637         3342 : TokenCollector::visit (TypePathSegmentGeneric &segment)
     638              : {
     639              :   // Syntax:
     640              :   //    PathIdentSegment `::`? (GenericArgs)?
     641              :   // GenericArgs :
     642              :   //    `<` `>`
     643              :   //    | `<` ( GenericArg `,` )* GenericArg `,`? `>`
     644         3342 :   describe_node (std::string ("TypePathSegmentGeneric"), [this, &segment] () {
     645         3342 :     auto locus = segment.is_lang_item ()
     646         3342 :                    ? segment.get_locus ()
     647         3294 :                    : segment.get_ident_segment ().get_locus ();
     648         3342 :     auto segment_string = segment.is_lang_item ()
     649         3342 :                             ? LangItem::PrettyString (segment.get_lang_item ())
     650         3342 :                             : segment.get_ident_segment ().as_string ();
     651         6684 :     push (Rust::Token::make_identifier (locus, std::move (segment_string)));
     652              : 
     653         3342 :     push (Rust::Token::make (LEFT_ANGLE, UNDEF_LOCATION));
     654              : 
     655         3342 :     {
     656         3342 :       auto &lifetime_args = segment.get_generic_args ().get_lifetime_args ();
     657         3342 :       auto &generic_args = segment.get_generic_args ().get_generic_args ();
     658         3342 :       auto &binding_args = segment.get_generic_args ().get_binding_args ();
     659              : 
     660         3342 :       visit_items_joined_by_separator (lifetime_args, COMMA);
     661         3342 :       if (!lifetime_args.empty ()
     662         3342 :           && (!generic_args.empty () || !binding_args.empty ()))
     663           16 :         push (Rust::Token::make (COMMA, UNDEF_LOCATION));
     664         3342 :       visit_items_joined_by_separator (generic_args, COMMA);
     665         3342 :       if (!generic_args.empty () && !binding_args.empty ())
     666            2 :         push (Rust::Token::make (COMMA, UNDEF_LOCATION));
     667         3342 :       visit_items_joined_by_separator (binding_args, COMMA);
     668              :     }
     669              : 
     670         6684 :     push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
     671         3342 :   });
     672         3342 : }
     673              : 
     674              : void
     675           57 : TokenCollector::visit (GenericArgsBinding &binding)
     676              : {
     677              :   // Syntax:
     678              :   //    IDENTIFIER `=` Type
     679           57 :   describe_node (std::string ("GenericArgsBinding"), [this, &binding] () {
     680          114 :     auto identifier = binding.get_identifier ().as_string ();
     681          114 :     push (Rust::Token::make_identifier (binding.get_locus (),
     682              :                                         std::move (identifier)));
     683              : 
     684           57 :     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
     685           57 :     visit (binding.get_type ());
     686           57 :   });
     687           57 : }
     688              : 
     689              : void
     690         4566 : TokenCollector::visit (GenericArg &arg)
     691              : {
     692              :   // `GenericArg` implements `accept_vis` but it is not useful for this case
     693              :   // as it ignores unresolved cases (`Kind::Either`).
     694         4566 :   describe_node (std::string ("GenericArg"), [this, &arg] () {
     695         4566 :     switch (arg.get_kind ())
     696              :       {
     697          110 :       case GenericArg::Kind::Const:
     698          110 :         visit (arg.get_expression ());
     699          110 :         break;
     700         4449 :       case GenericArg::Kind::Type:
     701         4449 :         visit (arg.get_type ());
     702         4449 :         break;
     703            7 :       case GenericArg::Kind::Either:
     704            7 :         {
     705            7 :           auto path = arg.get_path ();
     706            7 :           push (
     707           14 :             Rust::Token::make_identifier (UNDEF_LOCATION, std::move (path)));
     708            7 :         }
     709            7 :         break;
     710              :       }
     711         4566 :   });
     712         4566 : }
     713              : 
     714              : void
     715           36 : TokenCollector::visit (TypePathSegmentFunction &segment)
     716              : {
     717              :   // Syntax:
     718              :   //   PathIdentSegment `::`? (TypePathFn)?
     719           36 :   describe_node (std::string ("TypePathSegmentFunction"), [this, &segment] () {
     720           36 :     auto ident_segment = segment.get_ident_segment ();
     721           36 :     auto id = ident_segment.as_string ();
     722           72 :     push (Rust::Token::make_identifier (ident_segment.get_locus (),
     723              :                                         std::move (id)));
     724              : 
     725           36 :     if (segment.get_separating_scope_resolution ())
     726            0 :       push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
     727              : 
     728           36 :     if (!segment.is_ident_only ())
     729           36 :       visit (segment.get_type_path_function ());
     730           36 :   });
     731           36 : }
     732              : 
     733              : void
     734           36 : TokenCollector::visit (TypePathFunction &type_path_fn)
     735              : {
     736              :   // Syntax:
     737              :   //   `(` TypePathFnInputs? `)` (`->` Type)?
     738              :   // TypePathFnInputs :
     739              :   //   Type (`,` Type)* `,`?
     740           36 :   describe_node (std::string ("TypePathFunction"), [this, &type_path_fn] () {
     741           36 :     push (Rust::Token::make (LEFT_PAREN, type_path_fn.get_locus ()));
     742           36 :     if (type_path_fn.has_inputs ())
     743           35 :       visit_items_joined_by_separator (type_path_fn.get_params (), COMMA);
     744           36 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
     745              : 
     746           36 :     if (type_path_fn.has_return_type ())
     747              :       {
     748           36 :         push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
     749           36 :         visit (type_path_fn.get_return_type ());
     750              :       }
     751           36 :   });
     752           36 : }
     753              : 
     754              : void
     755        61466 : TokenCollector::visit (TypePath &path)
     756              : {
     757              :   // Syntax:
     758              :   //    `::`? TypePathSegment (`::` TypePathSegment)*
     759        61466 :   describe_node (std::string ("TypePath"), [this, &path] () {
     760        61466 :     if (path.has_opening_scope_resolution_op ())
     761          728 :       push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ()));
     762              : 
     763        61466 :     visit_items_joined_by_separator (path.get_segments (), SCOPE_RESOLUTION);
     764        61466 :   });
     765        61466 : }
     766              : 
     767              : void
     768        41000 : TokenCollector::visit (PathIdentSegment &segment)
     769              : {
     770        41000 :   describe_node (std::string ("PathIdentSegment"), [this, &segment] () {
     771        41000 :     if (segment.is_super_path_seg ())
     772              :       {
     773            2 :         push (Rust::Token::make (SUPER, segment.get_locus ()));
     774              :       }
     775        40999 :     else if (segment.is_crate_path_seg ())
     776              :       {
     777         3102 :         push (Rust::Token::make (CRATE, segment.get_locus ()));
     778              :       }
     779        39448 :     else if (segment.is_lower_self_seg ())
     780              :       {
     781        14894 :         push (Rust::Token::make (SELF, segment.get_locus ()));
     782              :       }
     783        32001 :     else if (segment.is_big_self_seg ())
     784              :       {
     785          980 :         push (Rust::Token::make (SELF_ALIAS, segment.get_locus ()));
     786              :       }
     787              :     else
     788              :       {
     789        31511 :         auto id = segment.as_string ();
     790        31511 :         push (
     791        63022 :           Rust::Token::make_identifier (segment.get_locus (), std::move (id)));
     792        31511 :       }
     793        41000 :   });
     794        41000 : }
     795              : 
     796              : void
     797          119 : TokenCollector::visit (QualifiedPathInExpression &path)
     798              : {
     799          119 :   describe_node (std::string ("QualifiedPathInExpression"), [this, &path] () {
     800          119 :     visit (path.get_qualified_path_type ());
     801          238 :     for (auto &segment : path.get_segments ())
     802              :       {
     803          119 :         push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
     804          119 :         visit (segment);
     805              :       }
     806          119 :   });
     807          119 : }
     808              : 
     809              : void
     810          403 : TokenCollector::visit (QualifiedPathType &path)
     811              : {
     812          403 :   describe_node (std::string ("QualifiedPathType"), [this, &path] () {
     813          403 :     push (Rust::Token::make (LEFT_ANGLE, path.get_locus ()));
     814          403 :     visit (path.get_type ());
     815          403 :     if (path.has_as_clause ())
     816              :       {
     817          363 :         push (Rust::Token::make (AS, UNDEF_LOCATION));
     818          363 :         visit (path.get_as_type_path ());
     819              :       }
     820          403 :     push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
     821          403 :   });
     822          403 : }
     823              : 
     824              : void
     825          284 : TokenCollector::visit (QualifiedPathInType &path)
     826              : {
     827          284 :   describe_node (std::string ("QualifiedPathInType"), [this, &path] () {
     828          284 :     visit (path.get_qualified_path_type ());
     829              : 
     830          284 :     push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
     831          284 :     visit (path.get_associated_segment ());
     832          284 :     for (auto &segment : path.get_segments ())
     833              :       {
     834            0 :         push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
     835            0 :         visit (segment);
     836              :       }
     837          284 :   });
     838          284 : }
     839              : 
     840              : void
     841        33749 : TokenCollector::visit (Literal &lit, location_t locus)
     842              : {
     843        33749 :   auto value = lit.as_string ();
     844        33749 :   switch (lit.get_lit_type ())
     845              :     {
     846          183 :     case Literal::LitType::CHAR:
     847          183 :       push (
     848          183 :         Rust::Token::make_char (locus,
     849              :                                 // TODO: Change this to support utf-8 properly
     850          183 :                                 Codepoint (static_cast<uint32_t> (value[0]))));
     851          183 :       break;
     852        13979 :     case Literal::LitType::STRING:
     853        27958 :       push (Rust::Token::make_string (locus, std::move (value)));
     854        13979 :       break;
     855          411 :     case Literal::LitType::BYTE:
     856          411 :       push (Rust::Token::make_byte_char (locus, value[0]));
     857          411 :       break;
     858           35 :     case Literal::LitType::BYTE_STRING:
     859           70 :       push (Rust::Token::make_byte_string (locus, std::move (value)));
     860           35 :       break;
     861            1 :     case Literal::LitType::RAW_STRING:
     862            2 :       push (Rust::Token::make_raw_string (locus, std::move (value)));
     863            1 :       break;
     864           14 :     case Literal::LitType::C_STRING:
     865           28 :       push (Rust::Token::make_c_string (locus, std::move (value)));
     866           14 :       break;
     867        17426 :     case Literal::LitType::INT:
     868        17426 :       {
     869        17426 :         auto val_len = value.length ();
     870        34852 :         push (Rust::Token::make_int (locus, std::move (value), val_len,
     871              :                                      IntegerLiteralBase::Decimal,
     872              :                                      lit.get_type_hint ()));
     873        17426 :         break;
     874              :       }
     875          351 :     case Literal::LitType::FLOAT:
     876          351 :       {
     877          351 :         auto val_len = value.length ();
     878          702 :         push (Rust::Token::make_float (locus, std::move (value), val_len,
     879              :                                        lit.get_type_hint ()));
     880          351 :         break;
     881              :       }
     882         1349 :     case Literal::LitType::BOOL:
     883         1349 :       {
     884         1349 :         if (value == Values::Keywords::FALSE_LITERAL)
     885         1164 :           push (Rust::Token::make (FALSE_LITERAL, locus));
     886          767 :         else if (value == Values::Keywords::TRUE_LITERAL)
     887         1534 :           push (Rust::Token::make (TRUE_LITERAL, locus));
     888              :         else
     889            0 :           rust_unreachable (); // Not a boolean
     890              :         break;
     891              :       }
     892            0 :     case Literal::LitType::ERROR:
     893            0 :       rust_unreachable ();
     894        33749 :       break;
     895              :     }
     896        33749 : }
     897              : 
     898              : void
     899        33211 : TokenCollector::visit (LiteralExpr &expr)
     900              : {
     901        33211 :   describe_node (std::string ("LiteralExpr"), [this, &expr] () {
     902        33211 :     auto lit = expr.get_literal ();
     903        33211 :     visit (lit, expr.get_locus ());
     904        33211 :   });
     905        33211 : }
     906              : 
     907              : void
     908        11524 : TokenCollector::visit (AttrInputLiteral &literal)
     909              : {
     910        11524 :   describe_node (std::string ("AttrInputLiteral"), [this, &literal] () {
     911        11524 :     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
     912        11524 :     visit (literal.get_literal ());
     913        11524 :   });
     914        11524 : }
     915              : 
     916              : void
     917            1 : TokenCollector::visit (AttrInputExpr &attr)
     918              : {
     919            1 :   describe_node (std::string ("AttrInputExpr"),
     920            2 :                  [this, &attr] () { visit (attr.get_expr ()); });
     921            1 : }
     922              : 
     923              : void
     924            0 : TokenCollector::visit (MetaItemLitExpr &item)
     925              : {
     926            0 :   describe_node (std::string ("MetaItemLitExpr"), [this, &item] () {
     927            0 :     auto lit = item.get_literal ();
     928            0 :     visit (lit);
     929            0 :   });
     930            0 : }
     931              : 
     932              : void
     933            0 : TokenCollector::visit (MetaItemPathExpr &item)
     934              : {
     935            0 :   describe_node (std::string ("MetaItemPathLit"), [this, &item] () {
     936            0 :     auto &path = item.get_path ();
     937            0 :     auto &expr = item.get_expr ();
     938            0 :     visit (path);
     939            0 :     push (Rust::Token::make (EQUAL, item.get_locus ()));
     940            0 :     visit (expr);
     941            0 :   });
     942            0 : }
     943              : 
     944              : void
     945         2039 : TokenCollector::visit (BorrowExpr &expr)
     946              : {
     947         2039 :   describe_node (std::string ("BorrowExpr"), [this, &expr] () {
     948         2039 :     push (Rust::Token::make (AMP, expr.get_locus ()));
     949         2039 :     if (expr.get_is_double_borrow ())
     950           46 :       push (Rust::Token::make (AMP, UNDEF_LOCATION));
     951              : 
     952         2039 :     if (expr.is_raw_borrow ())
     953              :       {
     954            8 :         push (Rust::Token::make_identifier (expr.get_locus (),
     955            4 :                                             Values::WeakKeywords::RAW));
     956            4 :         if (expr.get_is_mut ())
     957            8 :           push (Rust::Token::make (MUT, UNDEF_LOCATION));
     958              :         else
     959            0 :           push (Rust::Token::make (CONST, UNDEF_LOCATION));
     960              :       }
     961              :     else
     962              :       {
     963         2035 :         if (expr.get_is_mut ())
     964          886 :           push (Rust::Token::make (MUT, UNDEF_LOCATION));
     965              :       }
     966              : 
     967         2039 :     if (expr.is_raw_borrow ())
     968              :       {
     969            8 :         push (Rust::Token::make_identifier (expr.get_locus (),
     970            4 :                                             Values::WeakKeywords::RAW));
     971            4 :         if (expr.get_is_mut ())
     972            8 :           push (Rust::Token::make (MUT, UNDEF_LOCATION));
     973              :         else
     974            0 :           push (Rust::Token::make (CONST, UNDEF_LOCATION));
     975              :       }
     976              :     else
     977              :       {
     978         2035 :         if (expr.get_is_mut ())
     979          886 :           push (Rust::Token::make (MUT, UNDEF_LOCATION));
     980              :       }
     981              : 
     982         2039 :     if (expr.has_borrow_expr ())
     983         2039 :       visit (expr.get_borrowed_expr ());
     984         2039 :   });
     985         2039 : }
     986              : 
     987              : void
     988         4130 : TokenCollector::visit (DereferenceExpr &expr)
     989              : {
     990         4130 :   describe_node (std::string ("DereferenceExpr"), [this, &expr] () {
     991         4130 :     push (Rust::Token::make (ASTERISK, expr.get_locus ()));
     992         4130 :     visit (expr.get_dereferenced_expr ());
     993         4130 :   });
     994         4130 : }
     995              : 
     996              : void
     997            0 : TokenCollector::visit (ErrorPropagationExpr &expr)
     998              : {
     999            0 :   describe_node (std::string ("ErrorPropagationExpr"), [this, &expr] () {
    1000            0 :     visit (expr.get_propagating_expr ());
    1001            0 :     push (Rust::Token::make (QUESTION_MARK, expr.get_locus ()));
    1002            0 :   });
    1003            0 : }
    1004              : 
    1005              : void
    1006          882 : TokenCollector::visit (NegationExpr &expr)
    1007              : {
    1008          882 :   describe_node (std::string ("NegationExpr"), [this, &expr] () {
    1009          882 :     switch (expr.get_expr_type ())
    1010              :       {
    1011          417 :       case NegationOperator::NEGATE:
    1012          417 :         push (Rust::Token::make (MINUS, expr.get_locus ()));
    1013          417 :         break;
    1014          465 :       case NegationOperator::NOT:
    1015          465 :         push (Rust::Token::make (EXCLAM, expr.get_locus ()));
    1016          465 :         break;
    1017              :       }
    1018          882 :     visit (expr.get_negated_expr ());
    1019          882 :   });
    1020          882 : }
    1021              : 
    1022              : void
    1023         3775 : TokenCollector::visit (ArithmeticOrLogicalExpr &expr)
    1024              : {
    1025         3775 :   describe_node (std::string ("ArithmeticOrLogicalExpr"), [this, &expr] () {
    1026         3775 :     visit (expr.get_left_expr ());
    1027         3775 :     switch (expr.get_expr_type ())
    1028              :       {
    1029         2041 :       case ArithmeticOrLogicalOperator::ADD:
    1030         2041 :         push (Rust::Token::make (PLUS, expr.get_locus ()));
    1031         2041 :         break;
    1032              : 
    1033         1148 :       case ArithmeticOrLogicalOperator::SUBTRACT:
    1034         1148 :         push (Rust::Token::make (MINUS, expr.get_locus ()));
    1035         1148 :         break;
    1036              : 
    1037          277 :       case ArithmeticOrLogicalOperator::MULTIPLY:
    1038          277 :         push (Rust::Token::make (ASTERISK, expr.get_locus ()));
    1039          277 :         break;
    1040              : 
    1041           34 :       case ArithmeticOrLogicalOperator::DIVIDE:
    1042           34 :         push (Rust::Token::make (DIV, expr.get_locus ()));
    1043           34 :         break;
    1044              : 
    1045           48 :       case ArithmeticOrLogicalOperator::MODULUS:
    1046           48 :         push (Rust::Token::make (PERCENT, expr.get_locus ()));
    1047           48 :         break;
    1048              : 
    1049           52 :       case ArithmeticOrLogicalOperator::BITWISE_AND:
    1050           52 :         push (Rust::Token::make (AMP, expr.get_locus ()));
    1051           52 :         break;
    1052              : 
    1053           39 :       case ArithmeticOrLogicalOperator::BITWISE_OR:
    1054           39 :         push (Rust::Token::make (PIPE, expr.get_locus ()));
    1055           39 :         break;
    1056              : 
    1057           63 :       case ArithmeticOrLogicalOperator::BITWISE_XOR:
    1058           63 :         push (Rust::Token::make (CARET, expr.get_locus ()));
    1059           63 :         break;
    1060              : 
    1061           51 :       case ArithmeticOrLogicalOperator::LEFT_SHIFT:
    1062           51 :         push (Rust::Token::make (LEFT_SHIFT, expr.get_locus ()));
    1063           51 :         break;
    1064              : 
    1065           22 :       case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
    1066           22 :         push (Rust::Token::make (RIGHT_SHIFT, expr.get_locus ()));
    1067           22 :         break;
    1068              :       }
    1069              : 
    1070         3775 :     visit (expr.get_right_expr ());
    1071         3775 :   });
    1072         3775 : }
    1073              : 
    1074              : void
    1075         4073 : TokenCollector::visit (ComparisonExpr &expr)
    1076              : {
    1077         4073 :   describe_node (std::string ("ComparisonExpr"), [this, &expr] () {
    1078         4073 :     visit (expr.get_left_expr ());
    1079              : 
    1080         4073 :     switch (expr.get_expr_type ())
    1081              :       {
    1082          927 :       case ComparisonOperator::EQUAL:
    1083          927 :         push (Rust::Token::make (EQUAL_EQUAL, expr.get_locus ()));
    1084          927 :         break;
    1085         1130 :       case ComparisonOperator::NOT_EQUAL:
    1086         1130 :         push (Rust::Token::make (NOT_EQUAL, expr.get_locus ()));
    1087         1130 :         break;
    1088          677 :       case ComparisonOperator::GREATER_THAN:
    1089          677 :         push (Rust::Token::make (RIGHT_ANGLE, expr.get_locus ()));
    1090          677 :         break;
    1091          810 :       case ComparisonOperator::LESS_THAN:
    1092          810 :         push (Rust::Token::make (LEFT_ANGLE, expr.get_locus ()));
    1093          810 :         break;
    1094          236 :       case ComparisonOperator::GREATER_OR_EQUAL:
    1095          236 :         push (Rust::Token::make (GREATER_OR_EQUAL, expr.get_locus ()));
    1096          236 :         break;
    1097              : 
    1098          293 :       case ComparisonOperator::LESS_OR_EQUAL:
    1099          293 :         push (Rust::Token::make (LESS_OR_EQUAL, expr.get_locus ()));
    1100          293 :         break;
    1101              :       }
    1102         4073 :     visit (expr.get_right_expr ());
    1103         4073 :   });
    1104         4073 : }
    1105              : 
    1106              : void
    1107          522 : TokenCollector::visit (LazyBooleanExpr &expr)
    1108              : {
    1109          522 :   describe_node (std::string ("LazyBooleanExpr"), [this, &expr] () {
    1110          522 :     visit (expr.get_left_expr ());
    1111              : 
    1112          522 :     switch (expr.get_expr_type ())
    1113              :       {
    1114          378 :       case LazyBooleanOperator::LOGICAL_AND:
    1115          378 :         push (Rust::Token::make (LOGICAL_AND, expr.get_locus ()));
    1116          378 :         break;
    1117          144 :       case LazyBooleanOperator::LOGICAL_OR:
    1118          144 :         push (Rust::Token::make (OR, expr.get_locus ()));
    1119          144 :         break;
    1120              :       }
    1121              : 
    1122          522 :     visit (expr.get_right_expr ());
    1123          522 :   });
    1124          522 : }
    1125              : 
    1126              : void
    1127         5624 : TokenCollector::visit (TypeCastExpr &expr)
    1128              : {
    1129         5624 :   describe_node (std::string ("TypeCastExpr"), [this, &expr] () {
    1130         5624 :     visit (expr.get_casted_expr ());
    1131         5624 :     push (Rust::Token::make (AS, expr.get_locus ()));
    1132         5624 :     visit (expr.get_type_to_cast_to ());
    1133         5624 :   });
    1134         5624 : }
    1135              : 
    1136              : void
    1137         2537 : TokenCollector::visit (AssignmentExpr &expr)
    1138              : {
    1139         2537 :   describe_node (std::string ("AssignementExpr"), [this, &expr] () {
    1140         2537 :     expr.visit_lhs (*this);
    1141         2537 :     push (Rust::Token::make (EQUAL, expr.get_locus ()));
    1142         2537 :     expr.visit_rhs (*this);
    1143         2537 :   });
    1144         2537 : }
    1145              : 
    1146              : void
    1147          718 : TokenCollector::visit (CompoundAssignmentExpr &expr)
    1148              : {
    1149          718 :   describe_node (std::string ("CompoundAssignmentExpr"), [this, &expr] () {
    1150          718 :     visit (expr.get_left_expr ());
    1151              : 
    1152          718 :     switch (expr.get_expr_type ())
    1153              :       {
    1154          191 :       case CompoundAssignmentOperator::ADD:
    1155          191 :         push (Rust::Token::make (PLUS_EQ, expr.get_locus ()));
    1156          191 :         break;
    1157          107 :       case CompoundAssignmentOperator::SUBTRACT:
    1158          107 :         push (Rust::Token::make (MINUS_EQ, expr.get_locus ()));
    1159          107 :         break;
    1160            7 :       case CompoundAssignmentOperator::MULTIPLY:
    1161            7 :         push (Rust::Token::make (ASTERISK_EQ, expr.get_locus ()));
    1162            7 :         break;
    1163            7 :       case CompoundAssignmentOperator::DIVIDE:
    1164            7 :         push (Rust::Token::make (DIV_EQ, expr.get_locus ()));
    1165            7 :         break;
    1166            7 :       case CompoundAssignmentOperator::MODULUS:
    1167            7 :         push (Rust::Token::make (PERCENT_EQ, expr.get_locus ()));
    1168            7 :         break;
    1169           21 :       case CompoundAssignmentOperator::BITWISE_AND:
    1170           21 :         push (Rust::Token::make (AMP_EQ, expr.get_locus ()));
    1171           21 :         break;
    1172           28 :       case CompoundAssignmentOperator::BITWISE_OR:
    1173           28 :         push (Rust::Token::make (PIPE_EQ, expr.get_locus ()));
    1174           28 :         break;
    1175          336 :       case CompoundAssignmentOperator::BITWISE_XOR:
    1176          336 :         push (Rust::Token::make (CARET_EQ, expr.get_locus ()));
    1177          336 :         break;
    1178            7 :       case CompoundAssignmentOperator::LEFT_SHIFT:
    1179            7 :         push (Rust::Token::make (LEFT_SHIFT_EQ, expr.get_locus ()));
    1180            7 :         break;
    1181            7 :       case CompoundAssignmentOperator::RIGHT_SHIFT:
    1182            7 :         push (Rust::Token::make (RIGHT_SHIFT_EQ, expr.get_locus ()));
    1183            7 :         break;
    1184              :       }
    1185          718 :     visit (expr.get_right_expr ());
    1186          718 :   });
    1187          718 : }
    1188              : 
    1189              : void
    1190          360 : TokenCollector::visit (GroupedExpr &expr)
    1191              : {
    1192          360 :   describe_node (std::string ("GroupedExpr"), [this, &expr] () {
    1193          360 :     push (Rust::Token::make (LEFT_PAREN, expr.get_locus ()));
    1194          360 :     visit (expr.get_expr_in_parens ());
    1195          360 :     push (Rust::Token::make (RIGHT_PAREN, expr.get_locus ()));
    1196          360 :   });
    1197          360 : }
    1198              : 
    1199              : void
    1200          295 : TokenCollector::visit (ArrayElemsValues &elems)
    1201              : {
    1202          295 :   describe_node (std::string ("ArraysElemValues"), [this, &elems] () {
    1203          295 :     visit_items_joined_by_separator (elems.get_values (), COMMA);
    1204          295 :   });
    1205          295 : }
    1206              : 
    1207              : void
    1208          116 : TokenCollector::visit (ArrayElemsCopied &elems)
    1209              : {
    1210          116 :   describe_node (std::string ("ArrayElemsCopied"), [this, &elems] () {
    1211          116 :     visit (elems.get_elem_to_copy ());
    1212          116 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    1213          116 :     visit (elems.get_num_copies ());
    1214          116 :   });
    1215          116 : }
    1216              : 
    1217              : void
    1218          411 : TokenCollector::visit (ArrayExpr &expr)
    1219              : {
    1220          411 :   describe_node (std::string ("ArrayExpr"), [this, &expr] () {
    1221          411 :     push (Rust::Token::make (LEFT_SQUARE, expr.get_locus ()));
    1222          411 :     visit (expr.get_array_elems ());
    1223          411 :     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
    1224          411 :   });
    1225          411 : }
    1226              : 
    1227              : void
    1228          302 : TokenCollector::visit (ArrayIndexExpr &expr)
    1229              : {
    1230          302 :   describe_node (std::string ("ArrayIndexExpr"), [this, &expr] () {
    1231          302 :     visit (expr.get_array_expr ());
    1232          302 :     push (Rust::Token::make (LEFT_SQUARE, expr.get_locus ()));
    1233          302 :     visit (expr.get_index_expr ());
    1234          302 :     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
    1235          302 :   });
    1236          302 : }
    1237              : 
    1238              : void
    1239          601 : TokenCollector::visit (TupleExpr &expr)
    1240              : {
    1241          601 :   describe_node (std::string ("TupleExpr"), [this, &expr] () {
    1242          601 :     visit_items_as_lines (expr.get_outer_attrs ());
    1243          601 :     push (Rust::Token::make (LEFT_PAREN, expr.get_locus ()));
    1244          601 :     visit_items_joined_by_separator (expr.get_tuple_elems (), COMMA);
    1245          601 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    1246          601 :   });
    1247          601 : }
    1248              : 
    1249              : void
    1250          914 : TokenCollector::visit (TupleIndexExpr &expr)
    1251              : {
    1252          914 :   describe_node (std::string ("TupleIndexExpr"), [this, &expr] () {
    1253          914 :     visit (expr.get_tuple_expr ());
    1254          914 :     push (Rust::Token::make (DOT, expr.get_locus ()));
    1255          914 :     auto str = std::to_string (expr.get_tuple_index ());
    1256          914 :     auto suffix_start = str.length ();
    1257         1828 :     push (Rust::Token::make_int (UNDEF_LOCATION, str, suffix_start,
    1258              :                                  IntegerLiteralBase::Decimal));
    1259          914 :   });
    1260          914 : }
    1261              : 
    1262              : void
    1263           79 : TokenCollector::visit (StructExprStruct &expr)
    1264              : {
    1265           79 :   describe_node (std::string ("StructExprStruct"),
    1266          158 :                  [this, &expr] () { visit (expr.get_struct_name ()); });
    1267           79 : }
    1268              : 
    1269              : void
    1270          229 : TokenCollector::visit (StructExprFieldIdentifier &expr)
    1271              : {
    1272          229 :   describe_node (std::string ("StructExprFieldIdentifier"), [this, &expr] () {
    1273          229 :     visit_items_as_lines (expr.get_outer_attrs ());
    1274          458 :     auto id = expr.get_field_name ().as_string ();
    1275          458 :     push (Rust::Token::make_identifier (expr.get_locus (), std::move (id)));
    1276          229 :   });
    1277          229 : }
    1278              : 
    1279              : void
    1280         2082 : TokenCollector::visit (StructExprFieldIdentifierValue &expr)
    1281              : {
    1282         2082 :   describe_node (std::string ("StructExprFieldIdentifierValue"), [this,
    1283              :                                                                   &expr] () {
    1284         2082 :     visit_items_as_lines (expr.get_outer_attrs ());
    1285         2082 :     auto id = expr.get_field_name ();
    1286         4164 :     push (Rust::Token::make_identifier (expr.get_locus (), std::move (id)));
    1287         2082 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    1288         2082 :     visit (expr.get_value ());
    1289         2082 :   });
    1290         2082 : }
    1291              : 
    1292              : void
    1293           42 : TokenCollector::visit (StructExprFieldIndexValue &expr)
    1294              : {
    1295           42 :   describe_node (std::string ("StructExprFieldIndexValue"), [this, &expr] () {
    1296           42 :     visit_items_as_lines (expr.get_outer_attrs ());
    1297           42 :     auto str = std::to_string (expr.get_index ());
    1298           42 :     auto suffix_start = str.length ();
    1299           84 :     push (Rust::Token::make_int (expr.get_locus (), str, suffix_start,
    1300              :                                  IntegerLiteralBase::Decimal));
    1301           42 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    1302           42 :     visit (expr.get_value ());
    1303           42 :   });
    1304           42 : }
    1305              : 
    1306              : void
    1307           63 : TokenCollector::visit (StructBase &base)
    1308              : {
    1309           63 :   describe_node (std::string ("StructBase"), [this, &base] () {
    1310           63 :     push (Rust::Token::make (DOT_DOT, UNDEF_LOCATION));
    1311           63 :     visit (base.get_base_struct ());
    1312           63 :   });
    1313           63 : }
    1314              : 
    1315              : void
    1316         1387 : TokenCollector::visit (StructExprStructFields &expr)
    1317              : {
    1318         1387 :   describe_node (std::string ("StructExprStructFields"), [this, &expr] () {
    1319         1387 :     visit (expr.get_struct_name ());
    1320         1387 :     push (Rust::Token::make (LEFT_CURLY, expr.get_locus ()));
    1321         1387 :     visit_items_joined_by_separator (expr.get_fields (), COMMA);
    1322         1387 :     if (expr.has_struct_base ())
    1323              :       {
    1324           63 :         push (Rust::Token::make (COMMA, UNDEF_LOCATION));
    1325           63 :         visit (expr.get_struct_base ());
    1326              :       }
    1327              :     else
    1328              :       {
    1329         1324 :         trailing_comma ();
    1330              :       }
    1331         1387 :     push (Rust::Token::make (RIGHT_CURLY, expr.get_locus ()));
    1332         1387 :   });
    1333         1387 : }
    1334              : 
    1335              : void
    1336            0 : TokenCollector::visit (StructExprStructBase &)
    1337              : {
    1338              :   // FIXME: Implement this node
    1339            0 :   rust_unreachable ();
    1340              : }
    1341              : 
    1342              : void
    1343        13485 : TokenCollector::visit (CallExpr &expr)
    1344              : {
    1345        13485 :   describe_node (std::string ("CallExpr"), [this, &expr] () {
    1346        13485 :     visit (expr.get_function_expr ());
    1347              : 
    1348        13485 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    1349              : 
    1350        13485 :     visit_items_joined_by_separator (expr.get_params (), COMMA);
    1351              : 
    1352        13485 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    1353        13485 :   });
    1354        13485 : }
    1355              : 
    1356              : void
    1357         3196 : TokenCollector::visit (MethodCallExpr &expr)
    1358              : {
    1359         3196 :   describe_node (std::string ("MethodCallExpr"), [this, &expr] () {
    1360         3196 :     visit (expr.get_receiver_expr ());
    1361         3196 :     push (Rust::Token::make (DOT, expr.get_locus ()));
    1362         3196 :     visit (expr.get_method_name ());
    1363         3196 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    1364         3196 :     visit_items_joined_by_separator (expr.get_params (), COMMA);
    1365         3196 :     trailing_comma ();
    1366         3196 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    1367         3196 :   });
    1368         3196 : }
    1369              : 
    1370              : void
    1371         5148 : TokenCollector::visit (FieldAccessExpr &expr)
    1372              : {
    1373         5148 :   describe_node (std::string ("FieldAccessExpr"), [this, &expr] () {
    1374         5148 :     visit (expr.get_receiver_expr ());
    1375         5148 :     push (Rust::Token::make (DOT, expr.get_locus ()));
    1376        10296 :     auto field_name = expr.get_field_name ().as_string ();
    1377         5148 :     push (
    1378        10296 :       Rust::Token::make_identifier (UNDEF_LOCATION, std::move (field_name)));
    1379         5148 :   });
    1380         5148 : }
    1381              : 
    1382              : void
    1383           65 : TokenCollector::visit (ClosureParam &param)
    1384              : {
    1385           65 :   describe_node (std::string ("ClosureParam"), [this, &param] () {
    1386           65 :     visit_items_as_lines (param.get_outer_attrs ());
    1387           65 :     visit (param.get_pattern ());
    1388           65 :     if (param.has_type_given ())
    1389              :       {
    1390           58 :         push (Rust::Token::make (COLON, param.get_locus ()));
    1391           58 :         visit (param.get_type ());
    1392              :       }
    1393           65 :   });
    1394           65 : }
    1395              : 
    1396              : void
    1397           66 : TokenCollector::visit_closure_common (ClosureExpr &expr)
    1398              : {
    1399           66 :   describe_node (std::string ("ClosureExpr"), [this, &expr] () {
    1400           66 :     if (expr.get_has_move ())
    1401              :       {
    1402            0 :         push (Rust::Token::make (MOVE, expr.get_locus ()));
    1403              :       }
    1404           66 :     push (Rust::Token::make (PIPE, UNDEF_LOCATION));
    1405           66 :     visit_items_joined_by_separator (expr.get_params (), COMMA);
    1406           66 :     push (Rust::Token::make (PIPE, UNDEF_LOCATION));
    1407           66 :   });
    1408           66 : }
    1409              : 
    1410              : void
    1411           36 : TokenCollector::visit (ClosureExprInner &expr)
    1412              : {
    1413           36 :   describe_node (std::string ("ClosureExprInner"), [this, &expr] () {
    1414           36 :     visit_closure_common (expr);
    1415           36 :     visit (expr.get_definition_expr ());
    1416           36 :   });
    1417           36 : }
    1418              : 
    1419              : void
    1420        24685 : TokenCollector::visit (BlockExpr &expr)
    1421              : {
    1422        24685 :   describe_node (std::string ("BlockExpr"), [this, &expr] () {
    1423        24685 :     visit_items_as_lines (expr.get_outer_attrs ());
    1424        24685 :     push (Rust::Token::make (LEFT_CURLY, expr.get_locus ()));
    1425        24685 :     newline ();
    1426        24685 :     increment_indentation ();
    1427        24685 :     visit_items_as_lines (expr.get_inner_attrs ());
    1428              : 
    1429        24685 :     visit_items_as_lines (expr.get_statements (), {});
    1430              : 
    1431        24685 :     if (expr.has_tail_expr ())
    1432              :       {
    1433        17719 :         indentation ();
    1434        17719 :         visit (expr.get_tail_expr ());
    1435        17719 :         newline ();
    1436              :       }
    1437              : 
    1438        24685 :     decrement_indentation ();
    1439        24685 :     indentation ();
    1440        24685 :     push (Rust::Token::make (RIGHT_CURLY, expr.get_locus ()));
    1441        24685 :     newline ();
    1442        24685 :   });
    1443        24685 : }
    1444              : 
    1445              : void
    1446          937 : TokenCollector::visit (AnonConst &expr)
    1447              : {
    1448          937 :   if (!expr.is_deferred ())
    1449              :     {
    1450          917 :       visit (expr.get_inner_expr ());
    1451          917 :       return;
    1452              :     }
    1453              : 
    1454           40 :   push (Rust::Token::make_string (expr.get_locus (), "_"));
    1455              : }
    1456              : 
    1457              : void
    1458           14 : TokenCollector::visit (ConstBlock &expr)
    1459              : {
    1460           14 :   push (Rust::Token::make (CONST, expr.get_locus ()));
    1461              : 
    1462              :   // The inner expression is already a block expr, so we don't need to add
    1463              :   // curlies
    1464           14 :   visit (expr.get_const_expr ());
    1465           14 : }
    1466              : 
    1467              : void
    1468           30 : TokenCollector::visit (ClosureExprInnerTyped &expr)
    1469              : {
    1470           30 :   describe_node (std::string ("ClosureExprInnerTyped"), [this, &expr] () {
    1471           30 :     visit_closure_common (expr);
    1472           30 :     push (Rust::Token::make (RETURN_TYPE, expr.get_locus ()));
    1473           30 :     visit (expr.get_return_type ());
    1474              : 
    1475           30 :     visit (expr.get_definition_expr ());
    1476           30 :   });
    1477           30 : }
    1478              : 
    1479              : void
    1480           25 : TokenCollector::visit (ContinueExpr &expr)
    1481              : {
    1482           25 :   describe_node (std::string ("ContinueExpr"), [this, &expr] () {
    1483           25 :     push (Rust::Token::make (CONTINUE, expr.get_locus ()));
    1484           25 :     if (expr.has_label ())
    1485            6 :       visit (expr.get_label_unchecked ());
    1486           25 :   });
    1487           25 : }
    1488              : 
    1489              : void
    1490          113 : TokenCollector::visit (BreakExpr &expr)
    1491              : {
    1492          113 :   describe_node (std::string ("BreakExpr"), [this, &expr] () {
    1493          113 :     push (Rust::Token::make (BREAK, expr.get_locus ()));
    1494          113 :     if (expr.has_label ())
    1495           33 :       visit (expr.get_label_unchecked ());
    1496          113 :     if (expr.has_break_expr ())
    1497           21 :       visit (expr.get_break_expr_unchecked ());
    1498          113 :   });
    1499          113 : }
    1500              : 
    1501              : void
    1502           73 : TokenCollector::visit (RangeFromToExpr &expr)
    1503              : {
    1504           73 :   describe_node (std::string ("RangeFromToExpr"), [this, &expr] () {
    1505           73 :     visit (expr.get_from_expr ());
    1506           73 :     push (Rust::Token::make (DOT_DOT, expr.get_locus ()));
    1507           73 :     visit (expr.get_to_expr ());
    1508           73 :   });
    1509           73 : }
    1510              : 
    1511              : void
    1512           13 : TokenCollector::visit (RangeFromExpr &expr)
    1513              : {
    1514           13 :   describe_node (std::string ("RangeFromExpr"), [this, &expr] () {
    1515           13 :     visit (expr.get_from_expr ());
    1516           13 :     push (Rust::Token::make (DOT_DOT, expr.get_locus ()));
    1517           13 :   });
    1518           13 : }
    1519              : 
    1520              : void
    1521            7 : TokenCollector::visit (RangeToExpr &expr)
    1522              : {
    1523            7 :   describe_node (std::string ("RangeToExpr"), [this, &expr] () {
    1524            7 :     push (Rust::Token::make (DOT_DOT, expr.get_locus ()));
    1525            7 :     visit (expr.get_to_expr ());
    1526            7 :   });
    1527            7 : }
    1528              : 
    1529              : void
    1530            0 : TokenCollector::visit (RangeFullExpr &expr)
    1531              : {
    1532            0 :   describe_node (std::string ("RangeFullExpr"), [this, &expr] () {
    1533            0 :     push (Rust::Token::make (DOT_DOT, expr.get_locus ()));
    1534            0 :   });
    1535            0 : }
    1536              : 
    1537              : void
    1538            7 : TokenCollector::visit (RangeFromToInclExpr &expr)
    1539              : {
    1540            7 :   describe_node (std::string ("RangeFromToInclExpr"), [this, &expr] () {
    1541            7 :     visit (expr.get_from_expr ());
    1542            7 :     push (Rust::Token::make (DOT_DOT_EQ, expr.get_locus ()));
    1543            7 :     visit (expr.get_to_expr ());
    1544            7 :   });
    1545            7 : }
    1546              : 
    1547              : void
    1548            0 : TokenCollector::visit (RangeToInclExpr &expr)
    1549              : {
    1550            0 :   describe_node (std::string ("RangeToInclExpr"), [this, &expr] () {
    1551            0 :     push (Rust::Token::make (DOT_DOT_EQ, expr.get_locus ()));
    1552            0 :     visit (expr.get_to_expr ());
    1553            0 :   });
    1554            0 : }
    1555              : 
    1556              : void
    1557            4 : TokenCollector::visit (BoxExpr &expr)
    1558              : {
    1559            4 :   describe_node (std::string ("BoxExpr"), [this, &expr] () {
    1560            4 :     push (Rust::Token::make (BOX, expr.get_locus ()));
    1561            4 :     visit (expr.get_boxed_expr ());
    1562            4 :   });
    1563            4 : }
    1564              : 
    1565              : void
    1566          631 : TokenCollector::visit (ReturnExpr &expr)
    1567              : {
    1568          631 :   describe_node (std::string ("ReturnExpr"), [this, &expr] () {
    1569          631 :     push (Rust::Token::make (RETURN_KW, expr.get_locus ()));
    1570          631 :     if (expr.has_returned_expr ())
    1571          594 :       visit (expr.get_returned_expr ());
    1572          631 :   });
    1573          631 : }
    1574              : 
    1575              : void
    1576            0 : TokenCollector::visit (TryExpr &expr)
    1577              : {
    1578            0 :   push (Rust::Token::make (TRY, expr.get_locus ()));
    1579            0 :   visit (expr.get_block_expr ());
    1580            0 : }
    1581              : 
    1582              : void
    1583         3951 : TokenCollector::visit (UnsafeBlockExpr &expr)
    1584              : {
    1585         3951 :   describe_node (std::string ("UnsafeBlockExpr"), [this, &expr] () {
    1586         3951 :     push (Rust::Token::make (UNSAFE, expr.get_locus ()));
    1587         3951 :     visit (expr.get_block_expr ());
    1588         3951 :   });
    1589         3951 : }
    1590              : 
    1591              : void
    1592           84 : TokenCollector::visit (LoopLabel &label)
    1593              : {
    1594           84 :   describe_node (std::string ("LoopLabel"), [this, &label] () {
    1595           84 :     visit (label.get_lifetime ());
    1596           84 :     push (Rust::Token::make (COLON, label.get_locus ()));
    1597           84 :   });
    1598           84 : }
    1599              : 
    1600              : void
    1601          236 : TokenCollector::visit_loop_common (BaseLoopExpr &expr)
    1602              : {
    1603          236 :   describe_node (std::string ("BaseLoopExpr"), [this, &expr] () {
    1604          236 :     if (expr.has_loop_label ())
    1605           51 :       visit (expr.get_loop_label ());
    1606          236 :   });
    1607          236 : }
    1608              : 
    1609              : void
    1610          147 : TokenCollector::visit (LoopExpr &expr)
    1611              : {
    1612          147 :   describe_node (std::string ("LoopExpr"), [this, &expr] () {
    1613          147 :     visit_loop_common (expr);
    1614          147 :     push (Rust::Token::make (LOOP, expr.get_locus ()));
    1615          147 :     visit (expr.get_loop_block ());
    1616          147 :   });
    1617          147 : }
    1618              : 
    1619              : void
    1620           89 : TokenCollector::visit (WhileLoopExpr &expr)
    1621              : {
    1622           89 :   describe_node (std::string ("WhileLoopExpr"), [this, &expr] () {
    1623           89 :     visit_loop_common (expr);
    1624           89 :     push (Rust::Token::make (WHILE, expr.get_locus ()));
    1625           89 :     visit (expr.get_predicate_expr ());
    1626           89 :     visit (expr.get_loop_block ());
    1627           89 :   });
    1628           89 : }
    1629              : 
    1630              : void
    1631            0 : TokenCollector::visit (WhileLetLoopExpr &expr)
    1632              : {
    1633            0 :   describe_node (std::string ("WhileLetLoopExpr"), [this, &expr] () {
    1634            0 :     visit_loop_common (expr);
    1635            0 :     push (Rust::Token::make (WHILE, expr.get_locus ()));
    1636            0 :     push (Rust::Token::make (LET, UNDEF_LOCATION));
    1637            0 :     visit (expr.get_pattern ());
    1638            0 :     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    1639            0 :     visit (expr.get_scrutinee_expr ());
    1640            0 :     visit (expr.get_loop_block ());
    1641            0 :   });
    1642            0 : }
    1643              : 
    1644              : void
    1645            0 : TokenCollector::visit (ForLoopExpr &expr)
    1646              : {
    1647            0 :   describe_node (std::string ("ForLoopExpr"), [this, &expr] () {
    1648            0 :     visit_loop_common (expr);
    1649            0 :     push (Rust::Token::make (FOR, expr.get_locus ()));
    1650            0 :     visit (expr.get_pattern ());
    1651            0 :     push (Rust::Token::make (IN, UNDEF_LOCATION));
    1652            0 :     visit (expr.get_iterator_expr ());
    1653            0 :     visit (expr.get_loop_block ());
    1654            0 :   });
    1655            0 : }
    1656              : 
    1657              : void
    1658         2831 : TokenCollector::visit (IfExpr &expr)
    1659              : {
    1660         2831 :   describe_node (std::string ("IfExpr"), [this, &expr] () {
    1661         2831 :     push (Rust::Token::make (IF, expr.get_locus ()));
    1662              : 
    1663         2831 :     visit (expr.get_condition_expr ());
    1664         2831 :     visit (expr.get_if_block ());
    1665         2831 :   });
    1666         2831 : }
    1667              : 
    1668              : void
    1669         1323 : TokenCollector::visit (IfExprConseqElse &expr)
    1670              : {
    1671         1323 :   describe_node (std::string ("IfExprConseqElse"), [this, &expr] () {
    1672         1323 :     visit (static_cast<IfExpr &> (expr));
    1673         1323 :     indentation ();
    1674         1323 :     push (Rust::Token::make (ELSE, expr.get_locus ()));
    1675         1323 :     visit (expr.get_else_block ());
    1676         1323 :   });
    1677         1323 : }
    1678              : 
    1679              : void
    1680           29 : TokenCollector::visit (IfLetExpr &expr)
    1681              : {
    1682           29 :   describe_node (std::string ("IfLetExpr"), [this, &expr] () {
    1683           29 :     push (Rust::Token::make (IF, expr.get_locus ()));
    1684           29 :     push (Rust::Token::make (LET, UNDEF_LOCATION));
    1685           29 :     visit (expr.get_pattern ());
    1686           29 :     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    1687           29 :     visit (expr.get_value_expr ());
    1688           29 :     visit (expr.get_if_block ());
    1689           29 :   });
    1690           29 : }
    1691              : 
    1692              : void
    1693           12 : TokenCollector::visit (IfLetExprConseqElse &expr)
    1694              : {
    1695           12 :   describe_node (std::string ("IfLetExprConseqElse"), [this, &expr] () {
    1696           12 :     visit (static_cast<IfLetExpr &> (expr));
    1697           12 :     indentation ();
    1698           12 :     push (Rust::Token::make (ELSE, expr.get_locus ()));
    1699           12 :     visit (expr.get_else_block ());
    1700           12 :   });
    1701           12 : }
    1702              : 
    1703              : void
    1704         2597 : TokenCollector::visit (MatchArm &arm)
    1705              : {
    1706         2597 :   describe_node (std::string ("MatchArm"), [this, &arm] () {
    1707         2597 :     visit_items_as_lines (arm.get_outer_attrs ());
    1708         2597 :     visit (arm.get_pattern ());
    1709         2597 :     if (arm.has_match_arm_guard ())
    1710              :       {
    1711           59 :         push (Rust::Token::make (IF, UNDEF_LOCATION));
    1712           59 :         visit (arm.get_guard_expr ());
    1713              :       }
    1714         2597 :   });
    1715         2597 : }
    1716              : 
    1717              : void
    1718         2597 : TokenCollector::visit (MatchCase &match_case)
    1719              : {
    1720         2597 :   describe_node (std::string ("MatchCase"), [this, &match_case] () {
    1721         2597 :     indentation ();
    1722         2597 :     visit (match_case.get_arm ());
    1723         2597 :     push (Rust::Token::make (MATCH_ARROW, UNDEF_LOCATION));
    1724         2597 :     visit (match_case.get_expr ());
    1725         2597 :     indentation ();
    1726         2597 :     push (Rust::Token::make (COMMA, UNDEF_LOCATION));
    1727         2597 :     newline ();
    1728         2597 :   });
    1729         2597 : }
    1730              : 
    1731              : void
    1732         1113 : TokenCollector::visit (MatchExpr &expr)
    1733              : {
    1734         1113 :   describe_node (std::string ("MatchExpr"), [this, &expr] () {
    1735         1113 :     push (Rust::Token::make (MATCH_KW, expr.get_locus ()));
    1736         1113 :     visit (expr.get_scrutinee_expr ());
    1737         1113 :     push (Rust::Token::make (LEFT_CURLY, UNDEF_LOCATION));
    1738         1113 :     newline ();
    1739         1113 :     increment_indentation ();
    1740         1113 :     visit_items_as_lines (expr.get_inner_attrs ());
    1741         3710 :     for (auto &arm : expr.get_match_cases ())
    1742              :       {
    1743         2597 :         visit (arm);
    1744              :       }
    1745         1113 :     decrement_indentation ();
    1746         1113 :     indentation ();
    1747         1113 :     push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
    1748         1113 :   });
    1749         1113 : }
    1750              : 
    1751              : void
    1752            0 : TokenCollector::visit (AwaitExpr &expr)
    1753              : {
    1754            0 :   describe_node (std::string ("AwaitExpr"), [this, &expr] () {
    1755            0 :     visit (expr.get_awaited_expr ());
    1756            0 :     push (Rust::Token::make (DOT, expr.get_locus ()));
    1757              :     // TODO: Check status of await keyword (Context dependant ?)
    1758            0 :     push (
    1759            0 :       Rust::Token::make_identifier (UNDEF_LOCATION, Values::Keywords::AWAIT));
    1760            0 :   });
    1761            0 : }
    1762              : 
    1763              : void
    1764            0 : TokenCollector::visit (AsyncBlockExpr &expr)
    1765              : {
    1766            0 :   describe_node (std::string ("AsyncBlockExpr"), [this, &expr] () {
    1767            0 :     push (Rust::Token::make (ASYNC, expr.get_locus ()));
    1768            0 :     if (expr.get_has_move ())
    1769            0 :       push (Rust::Token::make (MOVE, UNDEF_LOCATION));
    1770            0 :     visit (expr.get_block_expr ());
    1771            0 :   });
    1772            0 : }
    1773              : 
    1774              : void
    1775           26 : TokenCollector::visit (InlineAsm &expr)
    1776              : {
    1777           52 :   push (Rust::Token::make_identifier (expr.get_locus (), "asm"));
    1778           26 :   push (Rust::Token::make (EXCLAM, expr.get_locus ()));
    1779           26 :   push (Rust::Token::make (LEFT_PAREN, expr.get_locus ()));
    1780              : 
    1781           52 :   for (auto &template_str : expr.get_template_strs ())
    1782           52 :     push (Rust::Token::make_string (template_str.get_locus (),
    1783           52 :                                     std::move (template_str.symbol)));
    1784              : 
    1785           26 :   push (Rust::Token::make (COLON, expr.get_locus ()));
    1786              : 
    1787           55 :   for (auto &operand : expr.get_operands ())
    1788              :     {
    1789           29 :       using RegisterType = AST::InlineAsmOperand::RegisterType;
    1790           29 :       switch (operand.get_register_type ())
    1791              :         {
    1792           10 :         case RegisterType::In:
    1793           10 :           {
    1794           10 :             visit (operand.get_in ().expr);
    1795           10 :             break;
    1796              :           }
    1797           17 :         case RegisterType::Out:
    1798           17 :           {
    1799           17 :             visit (operand.get_out ().expr);
    1800           17 :             break;
    1801              :           }
    1802            0 :         case RegisterType::InOut:
    1803            0 :           {
    1804            0 :             visit (operand.get_in_out ().expr);
    1805            0 :             break;
    1806              :           }
    1807            2 :         case RegisterType::SplitInOut:
    1808            2 :           {
    1809            2 :             auto split = operand.get_split_in_out ();
    1810            2 :             visit (split.in_expr);
    1811            2 :             visit (split.out_expr);
    1812            2 :             break;
    1813            2 :           }
    1814            0 :         case RegisterType::Const:
    1815            0 :           {
    1816            0 :             visit (operand.get_const ().anon_const.get_inner_expr ());
    1817            0 :             break;
    1818              :           }
    1819            0 :         case RegisterType::Sym:
    1820            0 :           {
    1821            0 :             visit (operand.get_sym ().expr);
    1822            0 :             break;
    1823              :           }
    1824            0 :         case RegisterType::Label:
    1825            0 :           {
    1826            0 :             visit (operand.get_label ().expr);
    1827            0 :             break;
    1828              :           }
    1829              :         }
    1830           58 :       push (Rust::Token::make (COMMA, expr.get_locus ()));
    1831           26 :     }
    1832           26 :   push (Rust::Token::make (COLON, expr.get_locus ()));
    1833              : 
    1834           26 :   for (auto &clobber : expr.get_clobber_abi ())
    1835              :     {
    1836            0 :       push (Rust::Token::make_string (expr.get_locus (),
    1837            0 :                                       std::move (clobber.symbol)));
    1838            0 :       push (Rust::Token::make (COMMA, expr.get_locus ()));
    1839           26 :     }
    1840           26 :   push (Rust::Token::make (COLON, expr.get_locus ()));
    1841              : 
    1842           26 :   for (auto it = expr.named_args.begin (); it != expr.named_args.end (); ++it)
    1843              :     {
    1844            0 :       auto &arg = *it;
    1845            0 :       push (
    1846            0 :         Rust::Token::make_identifier (expr.get_locus (), arg.first.c_str ()));
    1847            0 :       push (Rust::Token::make (EQUAL, expr.get_locus ()));
    1848            0 :       push (Rust::Token::make_identifier (expr.get_locus (),
    1849            0 :                                           std::to_string (arg.second)));
    1850              : 
    1851            0 :       push (Rust::Token::make (COMMA, expr.get_locus ()));
    1852              :     }
    1853              : 
    1854           26 :   push (Rust::Token::make (COLON, expr.get_locus ()));
    1855              : 
    1856           31 :   for (auto &option : expr.get_options ())
    1857              :     {
    1858           10 :       push (Rust::Token::make_identifier (
    1859           10 :         expr.get_locus (), InlineAsm::option_to_string (option).c_str ()));
    1860           10 :       push (Rust::Token::make (COMMA, expr.get_locus ()));
    1861           26 :     }
    1862              : 
    1863           26 :   push (Rust::Token::make (RIGHT_PAREN, expr.get_locus ()));
    1864           26 : }
    1865              : 
    1866              : void
    1867            2 : TokenCollector::visit (LlvmInlineAsm &expr)
    1868              : {
    1869            4 :   push (Rust::Token::make_identifier (expr.get_locus (), "llvm_asm"));
    1870            2 :   push (Rust::Token::make (EXCLAM, expr.get_locus ()));
    1871            2 :   push (Rust::Token::make (LEFT_PAREN, expr.get_locus ()));
    1872            4 :   push (Rust::Token::make_string (expr.get_template ().get_locus (),
    1873            2 :                                   std::move (expr.get_template ().symbol)));
    1874              : 
    1875            2 :   push (Rust::Token::make (COLON, expr.get_locus ()));
    1876              : 
    1877            2 :   bool needs_comma = false;
    1878              : 
    1879            2 :   for (auto output : expr.get_outputs ())
    1880              :     {
    1881            0 :       if (needs_comma)
    1882            0 :         push (Rust::Token::make (COMMA, expr.get_locus ()));
    1883            0 :       needs_comma = true;
    1884            0 :       push (Rust::Token::make_string (expr.get_locus (),
    1885              :                                       std::move (output.constraint)));
    1886            0 :       push (Rust::Token::make (LEFT_PAREN, expr.get_locus ()));
    1887            0 :       visit (output.expr);
    1888            0 :       push (Rust::Token::make (RIGHT_PAREN, expr.get_locus ()));
    1889            0 :     }
    1890              : 
    1891            2 :   push (Rust::Token::make (COLON, expr.get_locus ()));
    1892            2 :   needs_comma = false;
    1893            4 :   for (auto input : expr.get_inputs ())
    1894              :     {
    1895            2 :       if (needs_comma)
    1896            0 :         push (Rust::Token::make (COMMA, expr.get_locus ()));
    1897            2 :       needs_comma = true;
    1898            4 :       push (Rust::Token::make_string (expr.get_locus (),
    1899              :                                       std::move (input.constraint)));
    1900            2 :       push (Rust::Token::make (LEFT_PAREN, expr.get_locus ()));
    1901            2 :       visit (input.expr);
    1902            4 :       push (Rust::Token::make (RIGHT_PAREN, expr.get_locus ()));
    1903            2 :     }
    1904              : 
    1905            2 :   push (Rust::Token::make (COLON, expr.get_locus ()));
    1906            2 :   needs_comma = false;
    1907            4 :   for (auto &clobber : expr.get_clobbers ())
    1908              :     {
    1909            2 :       if (needs_comma)
    1910            0 :         push (Rust::Token::make (COMMA, expr.get_locus ()));
    1911            2 :       needs_comma = true;
    1912            4 :       push (Rust::Token::make_string (expr.get_locus (),
    1913            2 :                                       std::move (clobber.symbol)));
    1914              :     }
    1915            2 :   push (Rust::Token::make (COLON, expr.get_locus ()));
    1916              : 
    1917              : #define X(code, s)                                                             \
    1918              :   if (expr.code)                                                               \
    1919              :     {                                                                          \
    1920              :       if (needs_comma)                                                         \
    1921              :         push (Rust::Token::make (COMMA, expr.get_locus ()));                   \
    1922              :       needs_comma = true;                                                      \
    1923              :       push (Rust::Token::make_string (expr.get_locus (), s));                  \
    1924              :     }
    1925              : 
    1926            2 :   needs_comma = false;
    1927            4 :   X (is_volatile (), "volatile")
    1928            2 :   X (is_stack_aligned (), "alignstack")
    1929            2 :   X (get_dialect () == LlvmInlineAsm::Dialect::Intel, "intel")
    1930              : 
    1931              : #undef X
    1932              : 
    1933            2 :   push (Rust::Token::make (RIGHT_PAREN, expr.get_locus ()));
    1934            2 : }
    1935              : 
    1936              : // rust-item.h
    1937              : 
    1938              : void
    1939         4904 : TokenCollector::visit (TypeParam &param)
    1940              : {
    1941              :   // Syntax:
    1942              :   //    IDENTIFIER( : TypeParamBounds? )? ( = Type )?
    1943              :   // TypeParamBounds :
    1944              :   //    TypeParamBound ( + TypeParamBound )* +?
    1945         4904 :   describe_node (std::string ("TypeParam"), [this, &param] () {
    1946         4904 :     visit_items_as_lines (param.get_outer_attrs ());
    1947         9808 :     auto id = param.get_type_representation ().as_string ();
    1948         9808 :     push (Rust::Token::make_identifier (param.get_locus (), std::move (id)));
    1949         4904 :     if (param.has_type_param_bounds ())
    1950              :       {
    1951          877 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
    1952          877 :         visit_items_joined_by_separator (param.get_type_param_bounds (), PLUS);
    1953              :       }
    1954         4904 :     if (param.has_type ())
    1955              :       {
    1956          393 :         push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    1957          393 :         visit (param.get_type ());
    1958              :       }
    1959         4904 :   });
    1960         4904 : }
    1961              : 
    1962              : void
    1963          320 : TokenCollector::visit (WhereClause &rule)
    1964              : {
    1965              :   // Syntax:
    1966              :   //    where ( WhereClauseItem , )* WhereClauseItem ?
    1967              :   // WhereClauseItem :
    1968              :   //    LifetimeWhereClauseItem
    1969              :   //    | TypeBoundWhereClauseItem
    1970          320 :   describe_node (std::string ("WhereClause"), [this, &rule] () {
    1971          320 :     push (Rust::Token::make (WHERE, UNDEF_LOCATION));
    1972          320 :     newline ();
    1973          320 :     increment_indentation ();
    1974          320 :     visit_items_joined_by_separator (rule.get_items (), COMMA);
    1975          320 :     decrement_indentation ();
    1976          320 :   });
    1977          320 : }
    1978              : 
    1979              : void
    1980            0 : TokenCollector::visit (LifetimeWhereClauseItem &item)
    1981              : {
    1982              :   // Syntax:
    1983              :   //    Lifetime : LifetimeBounds
    1984              :   // LifetimeBounds :
    1985              :   //   ( Lifetime + )* Lifetime?
    1986              : 
    1987            0 :   describe_node (std::string ("LifetimeWhereClauseItem"), [this, &item] () {
    1988            0 :     visit (item.get_lifetime ());
    1989            0 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    1990            0 :     visit_items_joined_by_separator (item.get_lifetime_bounds (), PLUS);
    1991            0 :   });
    1992            0 : }
    1993              : 
    1994              : void
    1995          345 : TokenCollector::visit (TypeBoundWhereClauseItem &item)
    1996              : {
    1997              :   // Syntax:
    1998              :   //    ForLifetimes? Type : TypeParamBounds?
    1999              :   // TypeParamBounds :
    2000              :   //    TypeParamBound ( + TypeParamBound )* +?
    2001              :   // TypeParamBound :
    2002              :   //    Lifetime | TraitBound
    2003              : 
    2004          345 :   describe_node (std::string ("TypeBoundWhereClauseItem"), [this, &item] () {
    2005          345 :     if (item.has_for_lifetimes ())
    2006            7 :       visit (item.get_for_lifetimes ());
    2007              : 
    2008          345 :     visit (item.get_type ());
    2009              : 
    2010          345 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    2011          345 :     visit_items_joined_by_separator (item.get_type_param_bounds (), PLUS);
    2012          345 :   });
    2013          345 : }
    2014              : 
    2015              : void
    2016         1201 : TokenCollector::visit (Module &module)
    2017              : {
    2018              :   //  Syntax:
    2019              :   //    mod IDENTIFIER ;
    2020              :   //     | mod IDENTIFIER {
    2021              :   //      InnerAttribute*
    2022              :   //      Item*
    2023              :   //    }
    2024         1201 :   describe_node (std::string ("Module"), [this, &module] () {
    2025         1201 :     visit_items_as_lines (module.get_outer_attrs ());
    2026         1201 :     visit (module.get_visibility ());
    2027         2402 :     auto name = module.get_name ().as_string ();
    2028         1201 :     push (Rust::Token::make (MOD, module.get_locus ()));
    2029         2402 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (name)));
    2030              : 
    2031         1201 :     if (module.get_kind () == Module::UNLOADED)
    2032              :       {
    2033            0 :         push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2034            0 :         newline ();
    2035              :       }
    2036              :     else /* Module::LOADED */
    2037              :       {
    2038         1201 :         push (Rust::Token::make (LEFT_CURLY, UNDEF_LOCATION));
    2039         1201 :         newline ();
    2040         1201 :         increment_indentation ();
    2041              : 
    2042         1201 :         visit_items_as_lines (module.get_inner_attrs ());
    2043         1201 :         visit_items_as_lines (module.get_items ());
    2044              : 
    2045         1201 :         decrement_indentation ();
    2046              : 
    2047         1201 :         push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
    2048         1201 :         newline ();
    2049              :       }
    2050         1201 :   });
    2051         1201 : }
    2052              : 
    2053              : void
    2054           25 : TokenCollector::visit (ExternCrate &crate)
    2055              : {
    2056           25 :   describe_node (std::string ("ExternCrate"), [this, &crate] () {
    2057           25 :     visit_items_as_lines (crate.get_outer_attrs ());
    2058           25 :     push (Rust::Token::make (EXTERN_KW, crate.get_locus ()));
    2059           25 :     push (Rust::Token::make (CRATE, UNDEF_LOCATION));
    2060           25 :     auto ref = crate.get_referenced_crate ();
    2061           50 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (ref)));
    2062           25 :     if (crate.has_as_clause ())
    2063              :       {
    2064            1 :         auto as_clause = crate.get_as_clause ();
    2065            1 :         push (Rust::Token::make (AS, UNDEF_LOCATION));
    2066            1 :         push (
    2067            2 :           Rust::Token::make_identifier (UNDEF_LOCATION, std::move (as_clause)));
    2068            1 :       }
    2069           25 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2070           25 :     newline ();
    2071           25 :   });
    2072           25 : }
    2073              : 
    2074              : void
    2075           18 : TokenCollector::visit (UseTreeGlob &use_tree)
    2076              : {
    2077           18 :   describe_node (std::string ("UseTreeGlob"), [this, &use_tree] () {
    2078           18 :     switch (use_tree.get_glob_type ())
    2079              :       {
    2080           15 :       case UseTreeGlob::PathType::PATH_PREFIXED:
    2081           15 :         {
    2082           15 :           auto path = use_tree.get_path ();
    2083           15 :           visit (path);
    2084           30 :           push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
    2085           15 :         }
    2086           15 :         break;
    2087            2 :       case UseTreeGlob::PathType::NO_PATH:
    2088            2 :         push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
    2089            2 :         break;
    2090              :       case UseTreeGlob::PathType::GLOBAL:
    2091              :         break;
    2092              :       }
    2093           18 :     push (Rust::Token::make (ASTERISK, UNDEF_LOCATION));
    2094           18 :   });
    2095           18 : }
    2096              : 
    2097              : void
    2098          171 : TokenCollector::visit (UseTreeList &use_tree)
    2099              : {
    2100          171 :   describe_node (std::string ("UseTreeList"), [this, &use_tree] () {
    2101          171 :     switch (use_tree.get_path_type ())
    2102              :       {
    2103          171 :       case UseTreeList::PathType::PATH_PREFIXED:
    2104          171 :         {
    2105          171 :           auto path = use_tree.get_path ();
    2106          171 :           visit (path);
    2107              : 
    2108          342 :           push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
    2109          171 :         }
    2110          171 :         break;
    2111            0 :       case UseTreeList::PathType::NO_PATH:
    2112            0 :         push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
    2113            0 :         break;
    2114              :       case UseTreeList::PathType::GLOBAL:
    2115              :         break;
    2116              :       }
    2117              : 
    2118          171 :     push (Rust::Token::make (LEFT_CURLY, UNDEF_LOCATION));
    2119          171 :     if (use_tree.has_trees ())
    2120              :       {
    2121          171 :         visit_items_joined_by_separator (use_tree.get_trees (), COMMA);
    2122              :       }
    2123          171 :     push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
    2124          171 :   });
    2125          171 : }
    2126              : 
    2127              : void
    2128         1135 : TokenCollector::visit (UseTreeRebind &use_tree)
    2129              : {
    2130         1135 :   describe_node (std::string ("UseTreeRebind"), [this, &use_tree] () {
    2131         1135 :     auto path = use_tree.get_path ();
    2132         1135 :     visit (path);
    2133         1135 :     switch (use_tree.get_new_bind_type ())
    2134              :       {
    2135            2 :       case UseTreeRebind::NewBindType::IDENTIFIER:
    2136            2 :         {
    2137            2 :           push (Rust::Token::make (AS, UNDEF_LOCATION));
    2138            2 :           auto id = use_tree.get_identifier ().as_string ();
    2139            4 :           push (Rust::Token::make_identifier (use_tree.get_locus (),
    2140              :                                               std::move (id)));
    2141            2 :         }
    2142            2 :         break;
    2143            2 :       case UseTreeRebind::NewBindType::WILDCARD:
    2144            2 :         push (Rust::Token::make (AS, UNDEF_LOCATION));
    2145            2 :         push (Rust::Token::make (UNDERSCORE, use_tree.get_locus ()));
    2146            2 :         break;
    2147              :       case UseTreeRebind::NewBindType::NONE:
    2148              :         break;
    2149              :       }
    2150         1135 :   });
    2151         1135 : }
    2152              : 
    2153              : void
    2154          691 : TokenCollector::visit (UseDeclaration &decl)
    2155              : {
    2156          691 :   describe_node (std::string ("UseDeclaration"), [this, &decl] () {
    2157          691 :     visit_items_as_lines (decl.get_outer_attrs ());
    2158          691 :     push (Rust::Token::make (USE, decl.get_locus ()));
    2159          691 :     visit (*decl.get_tree ());
    2160          691 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2161          691 :     newline ();
    2162          691 :   });
    2163          691 : }
    2164              : 
    2165              : void
    2166        19516 : TokenCollector::visit (Function &function)
    2167              : {
    2168              :   // Syntax:
    2169              :   //   FunctionQualifiers fn IDENTIFIER GenericParams?
    2170              :   //      ( FunctionParameters? )
    2171              :   //      FunctionReturnType? WhereClause?
    2172              :   //      ( BlockExpression | ; )
    2173        19516 :   describe_node (std::string ("Function"), [this, &function] () {
    2174        19516 :     visit_items_as_lines (function.get_outer_attrs ());
    2175              : 
    2176        19516 :     visit (function.get_visibility ());
    2177        19516 :     auto qualifiers = function.get_qualifiers ();
    2178        19516 :     visit (qualifiers);
    2179              : 
    2180        19516 :     push (Rust::Token::make (FN_KW, function.get_locus ()));
    2181        39032 :     auto name = function.get_function_name ().as_string ();
    2182        39032 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (name)));
    2183        19516 :     if (function.has_generics ())
    2184         1808 :       visit (function.get_generic_params ());
    2185              : 
    2186        19516 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2187              : 
    2188        19516 :     visit_items_joined_by_separator (function.get_function_params ());
    2189        19516 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2190              : 
    2191        19516 :     if (function.has_return_type ())
    2192              :       {
    2193        14244 :         push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
    2194        14244 :         visit (function.get_return_type ());
    2195              :       }
    2196              : 
    2197        19516 :     if (function.has_where_clause ())
    2198          212 :       visit (function.get_where_clause ());
    2199              : 
    2200        19516 :     if (function.has_body ())
    2201        15071 :       visit (*function.get_definition ());
    2202              :     else
    2203         8890 :       push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2204        19516 :     newline ();
    2205        19516 :   });
    2206        19516 : }
    2207              : 
    2208              : void
    2209         1465 : TokenCollector::visit (TypeAlias &type_alias)
    2210              : {
    2211              :   // Syntax:
    2212              :   // Visibility? type IDENTIFIER GenericParams? WhereClause? = Type;
    2213              : 
    2214              :   // Note: Associated types are handled by `AST::TraitItemType`.
    2215         1465 :   describe_node (std::string ("TypeAlias"), [this, &type_alias] () {
    2216         1465 :     visit_items_as_lines (type_alias.get_outer_attrs ());
    2217         1465 :     if (type_alias.has_visibility ())
    2218           16 :       visit (type_alias.get_visibility ());
    2219         2930 :     auto alias_name = type_alias.get_new_type_name ().as_string ();
    2220         1465 :     push (Rust::Token::make (TYPE, type_alias.get_locus ()));
    2221         1465 :     push (
    2222         2930 :       Rust::Token::make_identifier (UNDEF_LOCATION, std::move (alias_name)));
    2223              : 
    2224         1465 :     if (type_alias.has_generics ())
    2225           23 :       visit (type_alias.get_generic_params ());
    2226              : 
    2227         1465 :     if (type_alias.has_where_clause ())
    2228            0 :       visit (type_alias.get_where_clause ());
    2229              : 
    2230         1465 :     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    2231         1465 :     visit (type_alias.get_type_aliased ());
    2232         2930 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2233         1465 :   });
    2234         1465 : }
    2235              : 
    2236              : void
    2237            0 : TokenCollector::visit (TraitAlias &trait_alias)
    2238              : {
    2239              :   // Syntax:
    2240              :   // Visibility? trait IDENTIFIER GenericParams? = TypeBounds? WhereClause?;
    2241              :   // https://github.com/rust-lang/rfcs/blob/main/text/1733-trait-alias.md
    2242            0 :   describe_node (std::string ("TraitAlias"), [this, &trait_alias] () {
    2243            0 :     visit_items_as_lines (trait_alias.get_outer_attrs ());
    2244            0 :     if (trait_alias.has_visibility ())
    2245            0 :       visit (trait_alias.get_visibility ());
    2246            0 :     auto alias_name = trait_alias.get_alias_name ().as_string ();
    2247            0 :     push (Rust::Token::make (TRAIT, trait_alias.get_locus ()));
    2248            0 :     push (
    2249            0 :       Rust::Token::make_identifier (UNDEF_LOCATION, std::move (alias_name)));
    2250              : 
    2251            0 :     if (trait_alias.has_generics ())
    2252            0 :       visit (trait_alias.get_generic_params ());
    2253              : 
    2254            0 :     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    2255              : 
    2256            0 :     visit_items_joined_by_separator (trait_alias.get_alias_bounds (), PLUS);
    2257              : 
    2258            0 :     if (trait_alias.has_where_clause ())
    2259            0 :       visit (trait_alias.get_where_clause ());
    2260              : 
    2261            0 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2262            0 :   });
    2263            0 : }
    2264              : 
    2265              : void
    2266         1592 : TokenCollector::visit (StructStruct &struct_item)
    2267              : {
    2268         1592 :   describe_node (std::string ("StructStruct"), [this, &struct_item] () {
    2269         1592 :     visit_items_as_lines (struct_item.get_outer_attrs ());
    2270         1592 :     if (struct_item.has_visibility ())
    2271          377 :       visit (struct_item.get_visibility ());
    2272         3184 :     auto struct_name = struct_item.get_identifier ().as_string ();
    2273         1592 :     push (Rust::Token::make (STRUCT_KW, struct_item.get_locus ()));
    2274         1592 :     push (
    2275         3184 :       Rust::Token::make_identifier (UNDEF_LOCATION, std::move (struct_name)));
    2276              : 
    2277         1592 :     if (struct_item.has_generics ())
    2278          513 :       visit (struct_item.get_generic_params ());
    2279         1592 :     if (struct_item.has_where_clause ())
    2280            5 :       visit (struct_item.get_where_clause ());
    2281         1592 :     if (struct_item.is_unit_struct ())
    2282              :       {
    2283          556 :         push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2284          556 :         newline ();
    2285              :       }
    2286              :     else
    2287         2072 :       visit_items_as_block (struct_item.get_fields (),
    2288              :                             {Rust::Token::make (COMMA, UNDEF_LOCATION)});
    2289         1592 :   });
    2290         1592 : }
    2291              : 
    2292              : void
    2293          982 : TokenCollector::visit (TupleStruct &tuple_struct)
    2294              : {
    2295          982 :   describe_node (std::string ("TupleStruct"), [this, &tuple_struct] () {
    2296          982 :     visit_items_as_lines (tuple_struct.get_outer_attrs ());
    2297         1964 :     auto struct_name = tuple_struct.get_identifier ().as_string ();
    2298          982 :     push (Rust::Token::make (STRUCT_KW, tuple_struct.get_locus ()));
    2299          982 :     push (
    2300         1964 :       Rust::Token::make_identifier (UNDEF_LOCATION, std::move (struct_name)));
    2301          982 :     if (tuple_struct.has_generics ())
    2302          296 :       visit (tuple_struct.get_generic_params ());
    2303          982 :     if (tuple_struct.has_where_clause ())
    2304            0 :       visit (tuple_struct.get_where_clause ());
    2305              : 
    2306          982 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2307          982 :     visit_items_joined_by_separator (tuple_struct.get_fields (), COMMA);
    2308          982 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2309          982 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2310          982 :     newline ();
    2311          982 :   });
    2312          982 : }
    2313              : 
    2314              : void
    2315          449 : TokenCollector::visit (EnumItem &item)
    2316              : {
    2317          449 :   describe_node (std::string ("EnumItem"), [this, &item] () {
    2318          449 :     visit_items_as_lines (item.get_outer_attrs ());
    2319          898 :     auto id = item.get_identifier ().as_string ();
    2320          898 :     push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
    2321          449 :   });
    2322          449 : }
    2323              : 
    2324              : void
    2325          432 : TokenCollector::visit (EnumItemTuple &item)
    2326              : {
    2327          432 :   describe_node (std::string ("EnumItemTuple"), [this, &item] () {
    2328          864 :     auto id = item.get_identifier ().as_string ();
    2329          864 :     push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
    2330          432 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2331          432 :     visit_items_joined_by_separator (item.get_tuple_fields (), COMMA);
    2332          864 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2333          432 :   });
    2334          432 : }
    2335              : 
    2336              : void
    2337           79 : TokenCollector::visit (EnumItemStruct &item)
    2338              : {
    2339           79 :   describe_node (std::string ("EnumItemStruct"), [this, &item] () {
    2340          158 :     auto id = item.get_identifier ().as_string ();
    2341          158 :     push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
    2342          158 :     visit_items_as_block (item.get_struct_fields (),
    2343              :                           {Rust::Token::make (COMMA, UNDEF_LOCATION)});
    2344           79 :   });
    2345           79 : }
    2346              : 
    2347              : void
    2348          279 : TokenCollector::visit (EnumItemDiscriminant &item)
    2349              : {
    2350          279 :   describe_node (std::string ("EnumItemDiscriminant"), [this, &item] () {
    2351          558 :     auto id = item.get_identifier ().as_string ();
    2352          558 :     push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
    2353          279 :     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    2354          279 :     visit (item.get_expr ());
    2355          279 :   });
    2356          279 : }
    2357              : 
    2358              : void
    2359          528 : TokenCollector::visit (Enum &enumeration)
    2360              : {
    2361          528 :   describe_node (std::string ("Enum"), [this, &enumeration] () {
    2362          528 :     visit_items_as_lines (enumeration.get_outer_attrs ());
    2363          528 :     if (enumeration.has_visibility ())
    2364          279 :       visit (enumeration.get_visibility ());
    2365          528 :     push (Rust::Token::make (ENUM_KW, enumeration.get_locus ()));
    2366         1056 :     auto id = enumeration.get_identifier ().as_string ();
    2367          528 :     push (
    2368         1056 :       Rust::Token::make_identifier (enumeration.get_locus (), std::move (id)));
    2369          528 :     if (enumeration.has_generics ())
    2370          243 :       visit (enumeration.get_generic_params ());
    2371          528 :     if (enumeration.has_where_clause ())
    2372            0 :       visit (enumeration.get_where_clause ());
    2373              : 
    2374         1056 :     visit_items_as_block (enumeration.get_variants (),
    2375              :                           {Rust::Token::make (COMMA, UNDEF_LOCATION)});
    2376          528 :   });
    2377          528 : }
    2378              : 
    2379              : void
    2380          101 : TokenCollector::visit (Union &union_item)
    2381              : {
    2382          101 :   describe_node (std::string ("Union"), [this, &union_item] () {
    2383          101 :     visit_items_as_lines (union_item.get_outer_attrs ());
    2384          202 :     auto id = union_item.get_identifier ().as_string ();
    2385          202 :     push (Rust::Token::make_identifier (union_item.get_locus (),
    2386          101 :                                         Values::WeakKeywords::UNION));
    2387          202 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2388              : 
    2389          101 :     if (union_item.has_generics ())
    2390           74 :       visit (union_item.get_generic_params ());
    2391              : 
    2392          101 :     if (union_item.has_where_clause ())
    2393            0 :       visit (union_item.get_where_clause ());
    2394              : 
    2395          202 :     visit_items_as_block (union_item.get_variants (),
    2396              :                           {Rust::Token::make (COMMA, UNDEF_LOCATION)});
    2397          101 :   });
    2398          101 : }
    2399              : 
    2400              : void
    2401          552 : TokenCollector::visit (ConstantItem &item)
    2402              : {
    2403          552 :   describe_node (std::string ("ConstantItem"), [this, &item] () {
    2404          552 :     visit_items_as_lines (item.get_outer_attrs ());
    2405          552 :     push (Rust::Token::make (CONST, item.get_locus ()));
    2406          552 :     if (item.is_unnamed ())
    2407              :       {
    2408           12 :         push (Rust::Token::make (UNDERSCORE, UNDEF_LOCATION));
    2409              :       }
    2410              :     else
    2411              :       {
    2412         1092 :         push (Rust::Token::make_identifier (item.get_identifier ()));
    2413              :       }
    2414          552 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    2415          552 :     visit (item.get_type ());
    2416          552 :     if (item.has_expr ())
    2417              :       {
    2418          528 :         push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    2419          528 :         visit (item.get_expr ());
    2420              :       }
    2421          552 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2422          552 :   });
    2423          552 : }
    2424              : 
    2425              : void
    2426           70 : TokenCollector::visit (StaticItem &item)
    2427              : {
    2428           70 :   describe_node (std::string ("StaticItem"), [this, &item] () {
    2429           70 :     visit_items_as_lines (item.get_outer_attrs ());
    2430           70 :     push (Rust::Token::make (STATIC_KW, item.get_locus ()));
    2431           70 :     if (item.is_mutable ())
    2432           34 :       push (Rust::Token::make (MUT, UNDEF_LOCATION));
    2433              : 
    2434          140 :     auto id = item.get_identifier ().as_string ();
    2435          140 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2436           70 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    2437              : 
    2438           70 :     visit (item.get_type ());
    2439              : 
    2440           70 :     if (item.has_expr ())
    2441              :       {
    2442           70 :         push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    2443           70 :         visit (item.get_expr ());
    2444              :       }
    2445          140 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2446           70 :   });
    2447           70 : }
    2448              : 
    2449              : void
    2450            0 : TokenCollector::visit_function_common (std::unique_ptr<Type> &return_type,
    2451              :                                        std::unique_ptr<BlockExpr> &block)
    2452              : {
    2453              :   // FIXME: This should format the `<vis> fn <name> ( [args] )` as well
    2454            0 :   if (return_type)
    2455              :     {
    2456            0 :       push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
    2457            0 :       visit (return_type);
    2458              :     }
    2459              : 
    2460            0 :   if (block)
    2461              :     {
    2462            0 :       visit (block);
    2463              :     }
    2464              :   else
    2465              :     {
    2466            0 :       push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2467            0 :       newline ();
    2468              :     }
    2469            0 : }
    2470              : 
    2471              : void
    2472         8761 : TokenCollector::visit (SelfParam &param)
    2473              : {
    2474         8761 :   describe_node (std::string ("SelfParam"), [this, &param] () {
    2475         8761 :     if (param.get_has_ref ())
    2476              :       {
    2477         5190 :         push (Rust::Token::make (AMP, UNDEF_LOCATION));
    2478         5190 :         if (param.has_lifetime ())
    2479              :           {
    2480         4931 :             auto lifetime = param.get_lifetime ();
    2481         4931 :             visit (lifetime);
    2482         4931 :           }
    2483         5190 :         if (param.get_is_mut ())
    2484          906 :           push (Rust::Token::make (MUT, UNDEF_LOCATION));
    2485              :       }
    2486         8761 :     push (Rust::Token::make (SELF, UNDEF_LOCATION));
    2487         8761 :     if (param.has_type ())
    2488              :       {
    2489            3 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
    2490            3 :         visit (param.get_type ());
    2491              :       }
    2492         8761 :   });
    2493         8761 : }
    2494              : 
    2495              : void
    2496          797 : TokenCollector::visit (TraitItemType &item)
    2497              : {
    2498          797 :   describe_node (std::string ("TraitItemType"), [this, &item] () {
    2499          797 :     visit_items_as_lines (item.get_outer_attrs ());
    2500         1594 :     auto id = item.get_identifier ().as_string ();
    2501          797 :     indentation ();
    2502              : 
    2503          797 :     push (Rust::Token::make (TYPE, item.get_locus ()));
    2504         1594 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2505          797 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2506          797 :     newline ();
    2507          797 :   });
    2508          797 : }
    2509              : 
    2510              : void
    2511         3990 : TokenCollector::visit (Trait &trait)
    2512              : {
    2513         3990 :   describe_node (std::string ("Trait"), [this, &trait] () {
    2514         7958 :     for (auto &attr : trait.get_outer_attrs ())
    2515              :       {
    2516         3968 :         visit (attr);
    2517         3968 :         newline ();
    2518         3968 :         indentation ();
    2519              :       }
    2520              : 
    2521         3990 :     visit (trait.get_visibility ());
    2522              : 
    2523         7980 :     auto id = trait.get_identifier ().as_string ();
    2524         3990 :     push (Rust::Token::make (TRAIT, trait.get_locus ()));
    2525         7980 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2526              : 
    2527         3990 :     if (trait.has_generics ())
    2528          686 :       visit (trait.get_generic_params ());
    2529         3990 :     if (!trait.get_type_param_bounds ().empty ())
    2530         1092 :       push (Rust::Token::make ((COLON), trait.get_locus ()));
    2531         3990 :     visit_items_joined_by_separator (trait.get_type_param_bounds (), PLUS);
    2532              : 
    2533         3990 :     visit_items_as_block (trait.get_trait_items (), {});
    2534         3990 :   });
    2535         3990 : }
    2536              : 
    2537              : void
    2538         1011 : TokenCollector::visit (InherentImpl &impl)
    2539              : {
    2540         1011 :   describe_node (std::string ("InherentImpl"), [this, &impl] () {
    2541         1011 :     visit_items_as_lines (impl.get_outer_attrs ());
    2542         1011 :     push (Rust::Token::make (IMPL, impl.get_locus ()));
    2543         1011 :     visit (impl.get_generic_params ());
    2544              : 
    2545         1011 :     visit (impl.get_type ());
    2546              : 
    2547         1011 :     if (impl.has_where_clause ())
    2548            0 :       visit (impl.get_where_clause ());
    2549              : 
    2550              :     // FIXME: Handle inner attributes
    2551              : 
    2552         1011 :     visit_items_as_block (impl.get_impl_items (), {});
    2553         1011 :   });
    2554         1011 : }
    2555              : 
    2556              : void
    2557         5048 : TokenCollector::visit (TraitImpl &impl)
    2558              : {
    2559         5048 :   describe_node (std::string ("TraitImpl"), [this, &impl] () {
    2560         5048 :     visit_items_as_lines (impl.get_outer_attrs ());
    2561         5048 :     push (Rust::Token::make (IMPL, impl.get_locus ()));
    2562         5048 :     visit (impl.get_generic_params ());
    2563         5048 :     if (impl.is_exclam ())
    2564           12 :       push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
    2565         5048 :     visit (impl.get_trait_path ());
    2566         5048 :     push (Rust::Token::make (FOR, UNDEF_LOCATION));
    2567         5048 :     visit (impl.get_type ());
    2568              : 
    2569         5048 :     if (impl.has_where_clause ())
    2570          103 :       visit (impl.get_where_clause ());
    2571         5048 :   });
    2572         5048 :   visit_items_as_block (impl.get_impl_items ());
    2573         5048 : }
    2574              : 
    2575              : void
    2576            2 : TokenCollector::visit (ExternalTypeItem &type)
    2577              : {
    2578            2 :   describe_node (std::string ("ExternalTypeItem"), [this, &type] () {
    2579            2 :     visit (type.get_visibility ());
    2580              : 
    2581            4 :     auto id = type.get_identifier ().as_string ();
    2582              : 
    2583            2 :     push (Rust::Token::make (TYPE, UNDEF_LOCATION));
    2584            4 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2585            4 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2586            2 :   });
    2587            2 : }
    2588              : 
    2589              : void
    2590            0 : TokenCollector::visit (ExternalStaticItem &item)
    2591              : {
    2592            0 :   describe_node (std::string ("ExternalStaticItem"), [this, &item] () {
    2593            0 :     auto id = item.get_identifier ().as_string ();
    2594            0 :     visit_items_as_lines (item.get_outer_attrs ());
    2595            0 :     if (item.has_visibility ())
    2596            0 :       visit (item.get_visibility ());
    2597            0 :     push (Rust::Token::make (STATIC_KW, item.get_locus ()));
    2598            0 :     if (item.is_mut ())
    2599            0 :       push (Rust::Token::make (MUT, UNDEF_LOCATION));
    2600            0 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2601            0 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    2602            0 :     visit (item.get_type ());
    2603              :     // TODO: No expr ? The "(= Expression)?" part from the reference seems
    2604              :     // missing in the ast.
    2605            0 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2606            0 :   });
    2607            0 : }
    2608              : 
    2609              : void
    2610         1676 : TokenCollector::visit (ExternBlock &block)
    2611              : {
    2612         1676 :   describe_node (std::string ("ExternBlock"), [this, &block] () {
    2613         1676 :     visit_items_as_lines (block.get_outer_attrs ());
    2614         1676 :     push (Rust::Token::make (EXTERN_KW, block.get_locus ()));
    2615              : 
    2616         1676 :     if (block.has_abi ())
    2617              :       {
    2618         1675 :         auto abi = block.get_abi ();
    2619         3350 :         push (Rust::Token::make_string (UNDEF_LOCATION, std::move (abi)));
    2620         1675 :       }
    2621              : 
    2622         1676 :     visit_items_as_block (block.get_extern_items (), {});
    2623         1676 :   });
    2624         1676 : }
    2625              : 
    2626              : static std::pair<TokenId, TokenId>
    2627         1175 : get_delimiters (DelimType delim)
    2628              : {
    2629         1175 :   switch (delim)
    2630              :     {
    2631         1118 :     case PARENS:
    2632         1118 :       return {LEFT_PAREN, RIGHT_PAREN};
    2633           43 :     case SQUARE:
    2634           43 :       return {LEFT_SQUARE, RIGHT_SQUARE};
    2635           14 :     case CURLY:
    2636           14 :       return {LEFT_CURLY, RIGHT_CURLY};
    2637            0 :     default:
    2638            0 :       rust_unreachable ();
    2639              :     }
    2640              : }
    2641              : 
    2642              : void
    2643          974 : TokenCollector::visit (MacroMatchFragment &match)
    2644              : {
    2645          974 :   describe_node (std::string ("MacroMatchFragment"), [this, &match] () {
    2646         1948 :     auto id = match.get_ident ().as_string ();
    2647          974 :     auto frag_spec = match.get_frag_spec ().as_string ();
    2648          974 :     push (Rust::Token::make (DOLLAR_SIGN, UNDEF_LOCATION));
    2649         1948 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2650          974 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    2651         1948 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (frag_spec)));
    2652          974 :   });
    2653          974 : }
    2654              : 
    2655              : void
    2656          542 : TokenCollector::visit (MacroMatchRepetition &repetition)
    2657              : {
    2658          542 :   describe_node (std::string ("MacroMatchRepetition"), [this, &repetition] () {
    2659          542 :     push (Rust::Token::make (DOLLAR_SIGN, UNDEF_LOCATION));
    2660          542 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2661              : 
    2662         1196 :     for (auto &match : repetition.get_matches ())
    2663              :       {
    2664          654 :         visit (match);
    2665              :       }
    2666              : 
    2667          542 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2668              : 
    2669          542 :     if (repetition.has_sep ())
    2670              :       {
    2671          262 :         push (Rust::Token::make (repetition.get_sep ()->get_id (),
    2672          131 :                                  repetition.get_sep ()->get_locus ()));
    2673              :       }
    2674          542 :     switch (repetition.get_op ())
    2675              :       {
    2676          476 :       case MacroMatchRepetition::ANY:
    2677          476 :         push (Rust::Token::make (ASTERISK, UNDEF_LOCATION));
    2678          476 :         break;
    2679           33 :       case MacroMatchRepetition::ONE_OR_MORE:
    2680           33 :         push (Rust::Token::make (PLUS, UNDEF_LOCATION));
    2681           33 :         break;
    2682           33 :       case MacroMatchRepetition::ZERO_OR_ONE:
    2683           33 :         push (Rust::Token::make (QUESTION_MARK, UNDEF_LOCATION));
    2684           33 :         break;
    2685              :       case MacroMatchRepetition::NONE:
    2686              :         break;
    2687              :       }
    2688          542 :   });
    2689          542 : }
    2690              : 
    2691              : void
    2692         1175 : TokenCollector::visit (MacroMatcher &matcher)
    2693              : {
    2694         1175 :   describe_node (std::string ("MacroMatcher"), [this, &matcher] () {
    2695         1175 :     auto delimiters = get_delimiters (matcher.get_delim_type ());
    2696              : 
    2697         1175 :     push (Rust::Token::make (delimiters.first, UNDEF_LOCATION));
    2698              : 
    2699         2583 :     for (auto &item : matcher.get_matches ())
    2700              :       {
    2701         1408 :         visit (item);
    2702              :       }
    2703              : 
    2704         1175 :     push (Rust::Token::make (delimiters.second, UNDEF_LOCATION));
    2705         1175 :   });
    2706         1175 : }
    2707              : 
    2708              : void
    2709         1108 : TokenCollector::visit (MacroRule &rule)
    2710              : {
    2711         1108 :   describe_node (std::string ("MacroRule"), [this, &rule] () {
    2712         1108 :     visit (rule.get_matcher ());
    2713         1108 :     push (Rust::Token::make (MATCH_ARROW, rule.get_locus ()));
    2714         1108 :     visit (rule.get_transcriber ().get_token_tree ());
    2715         1108 :   });
    2716         1108 : }
    2717              : 
    2718              : void
    2719          970 : TokenCollector::visit (MacroRulesDefinition &rules_def)
    2720              : {
    2721          970 :   describe_node (std::string ("MacroRulesDefinition"), [this, &rules_def] () {
    2722         1113 :     for (auto &outer_attr : rules_def.get_outer_attrs ())
    2723          143 :       visit (outer_attr);
    2724              : 
    2725         1940 :     auto rule_name = rules_def.get_rule_name ().as_string ();
    2726              : 
    2727         1940 :     push (Rust::Token::make_identifier (rules_def.get_locus (),
    2728          970 :                                         Values::WeakKeywords::MACRO_RULES));
    2729          970 :     push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
    2730              : 
    2731         1940 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (rule_name)));
    2732              : 
    2733         1940 :     visit_items_as_block (rules_def.get_rules (),
    2734              :                           {Rust::Token::make (SEMICOLON, UNDEF_LOCATION)});
    2735          970 :   });
    2736          970 : }
    2737              : 
    2738              : void
    2739          175 : TokenCollector::visit (MacroInvocation &invocation)
    2740              : {
    2741          175 :   describe_node (std::string ("MacroInvocation"), [this, &invocation] () {
    2742          175 :     auto data = invocation.get_invoc_data ();
    2743          175 :     visit (data.get_path ());
    2744          175 :     push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
    2745          175 :     visit (data.get_delim_tok_tree ());
    2746          175 :     if (invocation.has_semicolon ())
    2747          348 :       push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2748          175 :   });
    2749          175 : }
    2750              : 
    2751              : void
    2752            0 : TokenCollector::visit (MetaItemPath &item)
    2753              : {
    2754            0 :   describe_node (std::string ("MetaItemPath"), [this, &item] () {
    2755            0 :     auto path = item.to_path_item ();
    2756            0 :     visit (path);
    2757            0 :   });
    2758            0 : }
    2759              : 
    2760              : void
    2761           14 : TokenCollector::visit (MetaItemSeq &item)
    2762              : {
    2763           14 :   describe_node (std::string ("MetaItemSeq"), [this, &item] () {
    2764           14 :     visit (item.get_path ());
    2765              :     // TODO: Double check this, there is probably a mistake.
    2766           14 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2767           14 :     visit_items_joined_by_separator (item.get_seq (), COMMA);
    2768           14 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2769           14 :   });
    2770           14 : }
    2771              : 
    2772              : void
    2773           42 : TokenCollector::visit (MetaWord &word)
    2774              : {
    2775           42 :   describe_node (std::string ("MetaWord"), [this, &word] () {
    2776           42 :     auto id = word.get_ident ().as_string ();
    2777              : 
    2778           84 :     push (Rust::Token::make_identifier (word.get_locus (), std::move (id)));
    2779           42 :   });
    2780           42 : }
    2781              : 
    2782              : void
    2783          388 : TokenCollector::visit (MetaNameValueStr &name)
    2784              : {
    2785          388 :   describe_node (std::string ("MetaNameValueStr"), [this, &name] () {
    2786          388 :     auto pair = name.get_name_value_pair ();
    2787          388 :     auto id = std::get<0> (pair).as_string ();
    2788          388 :     auto value = std::get<1> (pair);
    2789              : 
    2790          776 :     push (Rust::Token::make_identifier (name.get_locus (), std::move (id)));
    2791          388 :     push (Rust::Token::make (EQUAL, name.get_locus ()));
    2792          388 :     push (Rust::Token::make (DOUBLE_QUOTE, UNDEF_LOCATION));
    2793          776 :     push (Rust::Token::make_identifier (name.get_locus (), std::move (value)));
    2794          776 :     push (Rust::Token::make (DOUBLE_QUOTE, UNDEF_LOCATION));
    2795          388 :   });
    2796          388 : }
    2797              : 
    2798              : void
    2799            0 : TokenCollector::visit (MetaListPaths &list)
    2800              : {
    2801            0 :   describe_node (std::string ("MetaListPath"), [this, &list] () {
    2802            0 :     auto id = list.get_ident ().as_string ();
    2803              : 
    2804            0 :     push (Rust::Token::make_identifier (list.get_locus (), std::move (id)));
    2805            0 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2806              : 
    2807            0 :     visit_items_joined_by_separator (list.get_paths (), COMMA);
    2808              : 
    2809            0 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2810            0 :   });
    2811            0 : }
    2812              : 
    2813              : void
    2814            0 : TokenCollector::visit (MetaListNameValueStr &list)
    2815              : {
    2816            0 :   describe_node (std::string ("MetaListNameValueStr"), [this, &list] () {
    2817            0 :     auto id = list.get_ident ().as_string ();
    2818              : 
    2819            0 :     push (Rust::Token::make_identifier (list.get_locus (), std::move (id)));
    2820            0 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2821              : 
    2822            0 :     visit_items_joined_by_separator (list.get_values (), COMMA);
    2823              : 
    2824            0 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2825            0 :   });
    2826            0 : }
    2827              : 
    2828              : // rust-pattern.h
    2829              : void
    2830          477 : TokenCollector::visit (LiteralPattern &pattern)
    2831              : {
    2832          477 :   describe_node (std::string ("LiteralPattern"), [this, &pattern] () {
    2833          477 :     visit (pattern.get_literal (), pattern.get_locus ());
    2834          477 :   });
    2835          477 : }
    2836              : 
    2837              : void
    2838        25784 : TokenCollector::visit (IdentifierPattern &pattern)
    2839              : {
    2840        25784 :   describe_node (std::string ("IdentifierPattern"), [this, &pattern] () {
    2841        25784 :     if (pattern.get_is_ref ())
    2842              :       {
    2843            4 :         push (Rust::Token::make (REF, pattern.get_locus ()));
    2844              :       }
    2845        25784 :     if (pattern.get_is_mut ())
    2846              :       {
    2847         2044 :         push (Rust::Token::make (MUT, UNDEF_LOCATION));
    2848              :       }
    2849              : 
    2850        51568 :     auto id = pattern.get_ident ().as_string ();
    2851        51568 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2852              : 
    2853        25784 :     if (pattern.has_subpattern ())
    2854              :       {
    2855           27 :         push (Rust::Token::make (PATTERN_BIND, UNDEF_LOCATION));
    2856           27 :         visit (pattern.get_subpattern ());
    2857              :       }
    2858        25784 :   });
    2859        25784 : }
    2860              : 
    2861              : void
    2862         1187 : TokenCollector::visit (WildcardPattern &pattern)
    2863              : {
    2864         1187 :   describe_node (std::string ("WildcardPattern"), [this, &pattern] () {
    2865         1187 :     push (Rust::Token::make (UNDERSCORE, pattern.get_locus ()));
    2866         1187 :   });
    2867         1187 : }
    2868              : 
    2869              : void
    2870           44 : TokenCollector::visit (RestPattern &pattern)
    2871              : {
    2872           44 :   describe_node (std::string ("RestPattern"), [this, &pattern] () {
    2873           44 :     push (Rust::Token::make (DOT_DOT, pattern.get_locus ()));
    2874           44 :   });
    2875           44 : }
    2876              : 
    2877              : // void TokenCollector::visit(RangePatternBound& ){}
    2878              : 
    2879              : void
    2880           61 : TokenCollector::visit (RangePatternBoundLiteral &pattern)
    2881              : {
    2882           61 :   describe_node (std::string ("RangePatternBoundLiteral"), [this, &pattern] () {
    2883           61 :     if (pattern.get_has_minus ())
    2884              :       {
    2885           48 :         push (Rust::Token::make (MINUS, pattern.get_locus ()));
    2886              :       }
    2887           61 :     auto literal = pattern.get_literal ();
    2888           61 :     visit (literal);
    2889           61 :   });
    2890           61 : }
    2891              : 
    2892              : void
    2893           21 : TokenCollector::visit (RangePatternBoundPath &pattern)
    2894              : {
    2895           21 :   describe_node (std::string ("RangePatternBoundPath"),
    2896           42 :                  [this, &pattern] () { visit (pattern.get_path ()); });
    2897           21 : }
    2898              : 
    2899              : void
    2900            0 : TokenCollector::visit (RangePatternBoundQualPath &pattern)
    2901              : {
    2902            0 :   describe_node (std::string ("RangePatternBoundQualPath"),
    2903            0 :                  [this, &pattern] () {
    2904            0 :                    visit (pattern.get_qualified_path ());
    2905              :                  });
    2906            0 : }
    2907              : 
    2908              : void
    2909           41 : TokenCollector::visit (RangePattern &pattern)
    2910              : {
    2911           41 :   describe_node (std::string ("RangePattern"), [this, &pattern] () {
    2912           41 :     if (pattern.get_has_lower_bound () && pattern.get_has_upper_bound ())
    2913              :       {
    2914           41 :         visit (pattern.get_lower_bound ());
    2915           41 :         if (pattern.get_has_ellipsis_syntax ())
    2916            0 :           push (Rust::Token::make (ELLIPSIS, pattern.get_locus ()));
    2917              :         else
    2918           82 :           push (Rust::Token::make (DOT_DOT_EQ, pattern.get_locus ()));
    2919           41 :         visit (pattern.get_upper_bound ());
    2920              :       }
    2921            0 :     else if (pattern.get_has_lower_bound ())
    2922              :       {
    2923            0 :         visit (pattern.get_lower_bound ());
    2924            0 :         push (Rust::Token::make (DOT_DOT, pattern.get_locus ()));
    2925              :       }
    2926              :     else
    2927              :       {
    2928            0 :         push (Rust::Token::make (DOT_DOT_EQ, pattern.get_locus ()));
    2929            0 :         visit (pattern.get_upper_bound ());
    2930              :       }
    2931           41 :   });
    2932           41 : }
    2933              : 
    2934              : void
    2935          198 : TokenCollector::visit (ReferencePattern &pattern)
    2936              : 
    2937              : {
    2938          198 :   describe_node (std::string ("ReferencePattern"), [this, &pattern] () {
    2939          198 :     if (pattern.is_double_reference ())
    2940              :       {
    2941           20 :         push (Rust::Token::make (LOGICAL_AND, pattern.get_locus ()));
    2942              :       }
    2943              :     else
    2944              :       {
    2945          376 :         push (Rust::Token::make (AMP, pattern.get_locus ()));
    2946              :       }
    2947              : 
    2948          198 :     if (pattern.get_is_mut ())
    2949              :       {
    2950            0 :         push (Rust::Token::make (MUT, UNDEF_LOCATION));
    2951              :       }
    2952              : 
    2953          198 :     visit (pattern.get_referenced_pattern ());
    2954          198 :   });
    2955          198 : }
    2956              : 
    2957              : // void TokenCollector::visit(StructPatternField& ){}
    2958              : 
    2959              : void
    2960           26 : TokenCollector::visit (StructPatternFieldTuplePat &pattern)
    2961              : {
    2962           26 :   describe_node (std::string ("StructPatternFieldTuplePat"), [this,
    2963              :                                                               &pattern] () {
    2964           26 :     visit_items_as_lines (pattern.get_outer_attrs ());
    2965           26 :     auto str = std::to_string (pattern.get_index ());
    2966           26 :     auto suffix_start = str.length ();
    2967           52 :     push (Rust::Token::make_int (pattern.get_locus (), str, suffix_start,
    2968              :                                  IntegerLiteralBase::Decimal));
    2969           26 :     push (Rust::Token::make (COLON, pattern.get_locus ()));
    2970           26 :     visit (pattern.get_index_pattern ());
    2971           26 :   });
    2972           26 : }
    2973              : 
    2974              : void
    2975          148 : TokenCollector::visit (StructPatternFieldIdentPat &pattern)
    2976              : {
    2977          148 :   describe_node (std::string ("StructPatternFieldIdentPat"), [this,
    2978              :                                                               &pattern] () {
    2979          148 :     visit_items_as_lines (pattern.get_outer_attrs ());
    2980              : 
    2981          148 :     auto id = pattern.get_identifier ().as_string ();
    2982          296 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2983              : 
    2984          148 :     push (Rust::Token::make (COLON, pattern.get_locus ()));
    2985              : 
    2986          148 :     visit (pattern.get_ident_pattern ());
    2987          148 :   });
    2988          148 : }
    2989              : 
    2990              : void
    2991           99 : TokenCollector::visit (StructPatternFieldIdent &pattern)
    2992              : {
    2993           99 :   describe_node (std::string ("StructPatternFieldIdent"), [this, &pattern] () {
    2994           99 :     visit_items_as_lines (pattern.get_outer_attrs ());
    2995           99 :     if (pattern.is_ref ())
    2996            0 :       push (Rust::Token::make (REF, UNDEF_LOCATION));
    2997           99 :     if (pattern.is_mut ())
    2998            4 :       push (Rust::Token::make (MUT, UNDEF_LOCATION));
    2999              : 
    3000           99 :     auto id = pattern.get_identifier ().as_string ();
    3001          198 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    3002           99 :   });
    3003           99 : }
    3004              : 
    3005              : void
    3006          173 : TokenCollector::visit (StructPattern &pattern)
    3007              : {
    3008          173 :   describe_node (std::string ("StructPattern"), [this, &pattern] () {
    3009          173 :     visit (pattern.get_path ());
    3010          173 :     push (Rust::Token::make (LEFT_CURLY, pattern.get_locus ()));
    3011          173 :     auto elems = pattern.get_struct_pattern_elems ();
    3012          173 :     if (elems.has_struct_pattern_fields ())
    3013              :       {
    3014          172 :         visit_items_joined_by_separator (elems.get_struct_pattern_fields ());
    3015          172 :         if (elems.has_rest ())
    3016              :           {
    3017           13 :             push (Rust::Token::make (COMMA, UNDEF_LOCATION));
    3018           13 :             visit_items_as_lines (elems.get_etc_outer_attrs ());
    3019              :           }
    3020              :       }
    3021              :     else
    3022              :       {
    3023            1 :         visit_items_as_lines (elems.get_etc_outer_attrs ());
    3024              :       }
    3025              : 
    3026          346 :     push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
    3027          173 :   });
    3028          173 : }
    3029              : 
    3030              : // void TokenCollector::visit(TupleStructItems& ){}
    3031              : 
    3032              : void
    3033         1004 : TokenCollector::visit (TupleStructItemsNoRest &pattern)
    3034              : {
    3035         1004 :   describe_node (std::string ("TupleStructItemsNoRange"), [this, &pattern] () {
    3036         1004 :     visit_items_joined_by_separator (pattern.get_patterns ());
    3037         1004 :   });
    3038         1004 : }
    3039              : 
    3040              : void
    3041           36 : TokenCollector::visit (TupleStructItemsHasRest &pattern)
    3042              : {
    3043           36 :   describe_node (std::string ("TupleStructItemsRange"), [this, &pattern] () {
    3044           65 :     for (auto &lower : pattern.get_lower_patterns ())
    3045              :       {
    3046           29 :         visit (lower);
    3047              :       }
    3048           36 :     push (Rust::Token::make (DOT_DOT, UNDEF_LOCATION));
    3049           65 :     for (auto &upper : pattern.get_lower_patterns ())
    3050              :       {
    3051           29 :         visit (upper);
    3052              :       }
    3053           36 :   });
    3054           36 : }
    3055              : 
    3056              : void
    3057         1040 : TokenCollector::visit (TupleStructPattern &pattern)
    3058              : {
    3059         1040 :   describe_node (std::string ("TupleStructPattern"), [this, &pattern] () {
    3060         1040 :     visit (pattern.get_path ());
    3061         1040 :     push (Rust::Token::make (LEFT_PAREN, pattern.get_locus ()));
    3062         1040 :     visit (pattern.get_items ());
    3063         1040 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    3064         1040 :   });
    3065         1040 : }
    3066              : 
    3067              : // void
    3068              : // TokenCollector::visit (TuplePatternItems &)
    3069              : // {}
    3070              : 
    3071              : void
    3072          519 : TokenCollector::visit (TuplePatternItemsNoRest &pattern)
    3073              : {
    3074          519 :   describe_node (std::string ("TuplePatternItemsMultiple"), [this,
    3075              :                                                              &pattern] () {
    3076          519 :     visit_items_joined_by_separator (pattern.get_patterns (), COMMA);
    3077          519 :   });
    3078          519 : }
    3079              : 
    3080              : void
    3081           31 : TokenCollector::visit (TuplePatternItemsHasRest &pattern)
    3082              : {
    3083           31 :   describe_node (std::string ("TuplePatternItemsRanged"), [this, &pattern] () {
    3084           58 :     for (auto &lower : pattern.get_lower_patterns ())
    3085              :       {
    3086           27 :         visit (lower);
    3087              :       }
    3088           31 :     push (Rust::Token::make (DOT_DOT, UNDEF_LOCATION));
    3089           58 :     for (auto &upper : pattern.get_lower_patterns ())
    3090              :       {
    3091           27 :         visit (upper);
    3092              :       }
    3093           31 :   });
    3094           31 : }
    3095              : 
    3096              : void
    3097          550 : TokenCollector::visit (TuplePattern &pattern)
    3098              : {
    3099          550 :   describe_node (std::string ("TuplePattern"), [this, &pattern] () {
    3100          550 :     push (Rust::Token::make (LEFT_PAREN, pattern.get_locus ()));
    3101          550 :     visit (pattern.get_items ());
    3102          550 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    3103          550 :   });
    3104          550 : }
    3105              : 
    3106              : void
    3107            1 : TokenCollector::visit (GroupedPattern &pattern)
    3108              : {
    3109            1 :   describe_node (std::string ("GroupedPattern"), [this, &pattern] () {
    3110            1 :     push (Rust::Token::make (LEFT_PAREN, pattern.get_locus ()));
    3111            1 :     visit (pattern.get_pattern_in_parens ());
    3112            1 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    3113            1 :   });
    3114            1 : }
    3115              : 
    3116              : void
    3117           75 : TokenCollector::visit (SlicePattern &pattern)
    3118              : {
    3119           75 :   describe_node (std::string ("SlicePattern"), [this, &pattern] () {
    3120           75 :     push (Rust::Token::make (LEFT_SQUARE, pattern.get_locus ()));
    3121           75 :     visit_items_joined_by_separator (pattern.get_patterns (), COMMA);
    3122           75 :     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
    3123           75 :   });
    3124           75 : }
    3125              : 
    3126              : void
    3127          152 : TokenCollector::visit (AltPattern &pattern)
    3128              : {
    3129          152 :   describe_node (std::string ("AltPattern"), [this, &pattern] () {
    3130          152 :     visit_items_joined_by_separator (pattern.get_alts (), PIPE);
    3131          152 :   });
    3132          152 : }
    3133              : 
    3134              : // rust-stmt.h
    3135              : void
    3136           45 : TokenCollector::visit (EmptyStmt &)
    3137           45 : {}
    3138              : 
    3139              : void
    3140        13117 : TokenCollector::visit (LetStmt &stmt)
    3141              : {
    3142        13117 :   describe_node (std::string ("LetStmt"), [this, &stmt] () {
    3143        13117 :     push (Rust::Token::make (LET, stmt.get_locus ()));
    3144        13117 :     auto &pattern = stmt.get_pattern ();
    3145        13117 :     visit (pattern);
    3146              : 
    3147        13117 :     if (stmt.has_type ())
    3148              :       {
    3149         2170 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
    3150         2170 :         visit (stmt.get_type ());
    3151              :       }
    3152              : 
    3153        13117 :     if (stmt.has_type ())
    3154              :       {
    3155         2170 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
    3156         2170 :         visit (stmt.get_type ());
    3157              :       }
    3158              : 
    3159        13117 :     if (stmt.has_init_expr ())
    3160              :       {
    3161        11985 :         push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    3162        11985 :         visit (stmt.get_init_expr ());
    3163              :       }
    3164              : 
    3165        13117 :     if (stmt.has_else_expr ())
    3166              :       {
    3167            5 :         push (Rust::Token::make (ELSE, UNDEF_LOCATION));
    3168            5 :         visit (stmt.get_else_expr ());
    3169              :       }
    3170              : 
    3171        13117 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    3172        13117 :   });
    3173        13117 : }
    3174              : 
    3175              : void
    3176        11486 : TokenCollector::visit (ExprStmt &stmt)
    3177              : {
    3178        11486 :   describe_node (std::string ("ExprStmt"), [this, &stmt] () {
    3179        11486 :     visit (stmt.get_expr ());
    3180              : 
    3181        11486 :     if (stmt.is_semicolon_followed ())
    3182        18228 :       push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    3183        11486 :   });
    3184        11486 : }
    3185              : 
    3186              : // rust-type.h
    3187              : void
    3188         2271 : TokenCollector::visit (TraitBound &bound)
    3189              : {
    3190              :   // Syntax:
    3191              :   //      ?? ForLifetimes? TypePath
    3192              :   //   | ( ?? ForLifetimes? TypePath )
    3193         2271 :   describe_node (std::string ("TraitBound"), [this, &bound] () {
    3194         2271 :     if (bound.has_opening_question_mark ())
    3195          860 :       push (Rust::Token::make (QUESTION_MARK, bound.get_locus ()));
    3196              : 
    3197         2271 :     if (bound.has_for_lifetimes ())
    3198            7 :       visit (bound.get_for_lifetimes ());
    3199              : 
    3200         2271 :     visit (bound.get_type_path ());
    3201         2271 :   });
    3202         2271 : }
    3203              : 
    3204              : void
    3205           10 : TokenCollector::visit (ImplTraitType &type)
    3206              : {
    3207              :   // Syntax:
    3208              :   //    impl TypeParamBounds
    3209              :   // TypeParamBounds :
    3210              :   //    TypeParamBound ( + TypeParamBound )* +?
    3211           10 :   describe_node (std::string ("ImplTraitType"), [this, &type] () {
    3212           10 :     push (Rust::Token::make (IMPL, type.get_locus ()));
    3213           10 :     visit_items_joined_by_separator (type.get_type_param_bounds (), PLUS);
    3214           10 :   });
    3215           10 : }
    3216              : 
    3217              : void
    3218           11 : TokenCollector::visit (TraitObjectType &type)
    3219              : {
    3220              :   // Syntax:
    3221              :   //   dyn? TypeParamBounds
    3222              :   // TypeParamBounds :
    3223              :   //   TypeParamBound ( + TypeParamBound )* +?
    3224           11 :   describe_node (std::string ("TraiObjectType"), [this, &type] () {
    3225           11 :     if (type.is_dyn ())
    3226           22 :       push (Rust::Token::make (DYN, type.get_locus ()));
    3227           11 :     visit_items_joined_by_separator (type.get_type_param_bounds (), PLUS);
    3228           11 :   });
    3229           11 : }
    3230              : 
    3231              : void
    3232            5 : TokenCollector::visit (ParenthesisedType &type)
    3233              : {
    3234              :   // Syntax:
    3235              :   //    ( Type )
    3236            5 :   describe_node (std::string ("ParenthesisedType"), [this, &type] () {
    3237            5 :     push (Rust::Token::make (LEFT_PAREN, type.get_locus ()));
    3238            5 :     visit (type.get_type_in_parens ());
    3239            5 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    3240            5 :   });
    3241            5 : }
    3242              : 
    3243              : void
    3244           28 : TokenCollector::visit (ImplTraitTypeOneBound &type)
    3245              : {
    3246              :   // Syntax:
    3247              :   //    impl TraitBound
    3248              : 
    3249           28 :   describe_node (std::string ("ImplTraitTypeOneBound"), [this, &type] () {
    3250           28 :     push (Rust::Token::make (IMPL, type.get_locus ()));
    3251           28 :     visit (type.get_trait_bound ());
    3252           28 :   });
    3253           28 : }
    3254              : 
    3255              : void
    3256          326 : TokenCollector::visit (TraitObjectTypeOneBound &type)
    3257              : {
    3258              :   // Syntax:
    3259              :   //    dyn? TraitBound
    3260          326 :   describe_node (std::string ("TraitObjectTypeOneBound"), [this, &type] () {
    3261          326 :     if (type.is_dyn ())
    3262          652 :       push (Rust::Token::make (DYN, type.get_locus ()));
    3263          326 :     visit (type.get_trait_bound ());
    3264          326 :   });
    3265          326 : }
    3266              : 
    3267              : void
    3268          474 : TokenCollector::visit (TupleType &type)
    3269              : {
    3270              :   // Syntax:
    3271              :   //   ( )
    3272              :   //   | ( ( Type , )+ Type? )
    3273              : 
    3274          474 :   describe_node (std::string ("TupleType"), [this, &type] () {
    3275          474 :     push (Rust::Token::make (LEFT_PAREN, type.get_locus ()));
    3276          474 :     visit_items_joined_by_separator (type.get_elems (), COMMA);
    3277          474 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    3278          474 :   });
    3279          474 : }
    3280              : 
    3281              : void
    3282          194 : TokenCollector::visit (NeverType &type)
    3283              : {
    3284              :   // Syntax:
    3285              :   //  !
    3286              : 
    3287          194 :   describe_node (std::string ("NeverType"), [this, &type] () {
    3288          194 :     push (Rust::Token::make (EXCLAM, type.get_locus ()));
    3289          194 :   });
    3290          194 : }
    3291              : 
    3292              : void
    3293         7201 : TokenCollector::visit (RawPointerType &type)
    3294              : {
    3295              :   // Syntax:
    3296              :   //    * ( mut | const ) TypeNoBounds
    3297         7201 :   describe_node (std::string ("RawPointerType"), [this, &type] () {
    3298         7201 :     push (Rust::Token::make (ASTERISK, type.get_locus ()));
    3299         7201 :     if (type.get_pointer_type () == RawPointerType::MUT)
    3300         1778 :       push (Rust::Token::make (MUT, UNDEF_LOCATION));
    3301              :     else /* RawPointerType::CONST */
    3302        12624 :       push (Rust::Token::make (CONST, UNDEF_LOCATION));
    3303              : 
    3304         7201 :     visit (type.get_type_pointed_to ());
    3305         7201 :   });
    3306         7201 : }
    3307              : 
    3308              : void
    3309         4969 : TokenCollector::visit (ReferenceType &type)
    3310              : {
    3311              :   // Syntax:
    3312              :   //    & Lifetime? mut? TypeNoBounds
    3313         4969 :   describe_node (std::string ("ReferenceType"), [this, &type] () {
    3314         4969 :     push (Rust::Token::make (AMP, type.get_locus ()));
    3315              : 
    3316         4969 :     if (type.has_lifetime ())
    3317              :       {
    3318         4969 :         visit (type.get_lifetime ());
    3319              :       }
    3320              : 
    3321         4969 :     if (type.get_has_mut ())
    3322          686 :       push (Rust::Token::make (MUT, UNDEF_LOCATION));
    3323              : 
    3324         4969 :     visit (type.get_type_referenced ());
    3325         4969 :   });
    3326         4969 : }
    3327              : 
    3328              : void
    3329          923 : TokenCollector::visit (ArrayType &type)
    3330              : {
    3331              :   // Syntax:
    3332              :   //    [type Type ; Expression ]
    3333          923 :   describe_node (std::string ("ArrayType"), [this, &type] () {
    3334          923 :     push (Rust::Token::make (LEFT_SQUARE, type.get_locus ()));
    3335          923 :     visit (type.get_elem_type ());
    3336          923 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    3337          923 :     visit (type.get_size_expr ());
    3338          923 :     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
    3339          923 :   });
    3340          923 : }
    3341              : 
    3342              : void
    3343          940 : TokenCollector::visit (SliceType &type)
    3344              : {
    3345              :   // Syntax:
    3346              :   //    [type Type ]
    3347              : 
    3348          940 :   describe_node (std::string ("SliceType"), [this, &type] () {
    3349          940 :     push (Rust::Token::make (LEFT_SQUARE, type.get_locus ()));
    3350          940 :     visit (type.get_elem_type ());
    3351          940 :     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
    3352          940 :   });
    3353          940 : }
    3354              : 
    3355              : void
    3356          275 : TokenCollector::visit (InferredType &type)
    3357              : {
    3358              :   // Syntax:
    3359              :   //    _
    3360          275 :   describe_node (std::string ("InferredType"), [this, &type] () {
    3361          275 :     push (Rust::Token::make (UNDERSCORE, type.get_locus ()));
    3362          275 :   });
    3363          275 : }
    3364              : 
    3365              : void
    3366           82 : TokenCollector::visit (BareFunctionType &type)
    3367              : {
    3368              :   // Syntax:
    3369              :   //    ForLifetimes? FunctionTypeQualifiers fn
    3370              :   //      ( FunctionParametersMaybeNamedVariadic? )
    3371              :   //      BareFunctionReturnType?
    3372              :   //
    3373              :   //    BareFunctionReturnType:
    3374              :   //      -> TypeNoBounds
    3375              :   //
    3376              :   //    FunctionParametersMaybeNamedVariadic :
    3377              :   //      MaybeNamedFunctionParameters |
    3378              :   //      MaybeNamedFunctionParametersVariadic
    3379              :   //
    3380              :   //    MaybeNamedFunctionParameters :
    3381              :   //      MaybeNamedParam ( , MaybeNamedParam )* ,?
    3382              :   //
    3383              :   //    MaybeNamedFunctionParametersVariadic :
    3384              :   //      ( MaybeNamedParam , )* MaybeNamedParam , OuterAttribute* ...
    3385           82 :   describe_node (std::string ("BareFunctionType"), [this, &type] () {
    3386           82 :     if (type.has_for_lifetimes ())
    3387            0 :       visit (type.get_for_lifetimes ());
    3388              : 
    3389           82 :     visit (type.get_function_qualifiers ());
    3390              : 
    3391           82 :     push (Rust::Token::make (FN_KW, type.get_locus ()));
    3392           82 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    3393              : 
    3394           82 :     visit_items_joined_by_separator (type.get_function_params (), COMMA);
    3395              : 
    3396           82 :     if (type.is_variadic ())
    3397              :       {
    3398            0 :         push (Rust::Token::make (COMMA, UNDEF_LOCATION));
    3399            0 :         for (auto &item : type.get_variadic_attr ())
    3400              :           {
    3401            0 :             visit (item);
    3402              :           }
    3403            0 :         push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
    3404              :       }
    3405              : 
    3406           82 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    3407              : 
    3408           82 :     if (type.has_return_type ())
    3409              :       {
    3410           66 :         push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
    3411           66 :         visit (type.get_return_type ());
    3412              :       }
    3413           82 :   });
    3414           82 : }
    3415              : 
    3416              : void
    3417            0 : TokenCollector::visit (AST::FormatArgs &fmt)
    3418              : {
    3419            0 :   push (Rust::Token::make_identifier (fmt.get_locus (), "format_args"));
    3420            0 :   push (Rust::Token::make (EXCLAM, fmt.get_locus ()));
    3421            0 :   push (Rust::Token::make (LEFT_PAREN, fmt.get_locus ()));
    3422              : 
    3423            0 :   std::string reconstructed_template = "\"";
    3424            0 :   const auto &template_pieces = fmt.get_template ();
    3425              : 
    3426            0 :   for (const auto &piece : template_pieces.get_pieces ())
    3427              :     {
    3428            0 :       if (piece.tag == Fmt::ffi::Piece::Tag::String)
    3429              :         {
    3430            0 :           std::string literal = piece.string._0.to_string ();
    3431            0 :           for (char c : literal)
    3432              :             {
    3433            0 :               if (c == '"' || c == '\\')
    3434              :                 {
    3435            0 :                   reconstructed_template += '\\';
    3436              :                 }
    3437            0 :               else if (c == '\n')
    3438              :                 {
    3439            0 :                   reconstructed_template += "\\n";
    3440            0 :                   continue;
    3441              :                 }
    3442            0 :               else if (c == '\r')
    3443              :                 {
    3444            0 :                   reconstructed_template += "\\r";
    3445            0 :                   continue;
    3446              :                 }
    3447            0 :               else if (c == '\t')
    3448              :                 {
    3449            0 :                   reconstructed_template += "\\t";
    3450            0 :                   continue;
    3451              :                 }
    3452            0 :               reconstructed_template += c;
    3453              :             }
    3454            0 :         }
    3455            0 :       else if (piece.tag == Fmt::ffi::Piece::Tag::NextArgument)
    3456              :         {
    3457            0 :           reconstructed_template += "{";
    3458              : 
    3459            0 :           const auto &argument = piece.next_argument._0;
    3460            0 :           const auto &position = argument.position;
    3461              : 
    3462            0 :           switch (position.tag)
    3463              :             {
    3464              :             case Fmt::ffi::Position::Tag::ArgumentImplicitlyIs:
    3465              :               break;
    3466            0 :             case Fmt::ffi::Position::Tag::ArgumentIs:
    3467            0 :               reconstructed_template
    3468            0 :                 += std::to_string (position.argument_is._0);
    3469            0 :               break;
    3470            0 :             case Fmt::ffi::Position::Tag::ArgumentNamed:
    3471            0 :               reconstructed_template += position.argument_named._0.to_string ();
    3472            0 :               break;
    3473              :             }
    3474              : 
    3475              :           // Add format specifiers if any (like :?, :x, etc.)
    3476            0 :           const auto &format_spec = argument.format;
    3477              : 
    3478            0 :           bool has_format_spec = false;
    3479            0 :           std::string format_part;
    3480              : 
    3481              :           // For now, skipping the complex format specifications that
    3482              :           // use FFIOpt since FFIOpt::get_opt() has a bug.
    3483              : 
    3484              :           // Alignment
    3485            0 :           if (format_spec.align != Fmt::ffi::Alignment::AlignUnknown)
    3486              :             {
    3487            0 :               has_format_spec = true;
    3488            0 :               switch (format_spec.align)
    3489              :                 {
    3490            0 :                 case Fmt::ffi::Alignment::AlignLeft:
    3491            0 :                   format_part += "<";
    3492            0 :                   break;
    3493            0 :                 case Fmt::ffi::Alignment::AlignRight:
    3494            0 :                   format_part += ">";
    3495            0 :                   break;
    3496            0 :                 case Fmt::ffi::Alignment::AlignCenter:
    3497            0 :                   format_part += "^";
    3498            0 :                   break;
    3499              :                 case Fmt::ffi::Alignment::AlignUnknown:
    3500              :                   break;
    3501              :                 }
    3502              :             }
    3503              : 
    3504              :           // Alternate flag
    3505            0 :           if (format_spec.alternate)
    3506              :             {
    3507            0 :               has_format_spec = true;
    3508            0 :               format_part += "#";
    3509              :             }
    3510              : 
    3511              :           // Zero pad flag
    3512            0 :           if (format_spec.zero_pad)
    3513              :             {
    3514            0 :               has_format_spec = true;
    3515            0 :               format_part += "0";
    3516              :             }
    3517              : 
    3518              :           // Width
    3519            0 :           if (format_spec.width.tag != Fmt::ffi::Count::Tag::CountImplied)
    3520              :             {
    3521            0 :               has_format_spec = true;
    3522            0 :               switch (format_spec.width.tag)
    3523              :                 {
    3524            0 :                 case Fmt::ffi::Count::Tag::CountIs:
    3525            0 :                   format_part += std::to_string (format_spec.width.count_is._0);
    3526            0 :                   break;
    3527            0 :                 case Fmt::ffi::Count::Tag::CountIsParam:
    3528            0 :                   format_part
    3529            0 :                     += std::to_string (format_spec.width.count_is_param._0)
    3530            0 :                        + "$";
    3531            0 :                   break;
    3532            0 :                 case Fmt::ffi::Count::Tag::CountIsName:
    3533            0 :                   format_part
    3534            0 :                     += format_spec.width.count_is_name._0.to_string () + "$";
    3535            0 :                   break;
    3536            0 :                 case Fmt::ffi::Count::Tag::CountIsStar:
    3537            0 :                   format_part += "*";
    3538            0 :                   break;
    3539              :                 case Fmt::ffi::Count::Tag::CountImplied:
    3540              :                   break;
    3541              :                 }
    3542              :             }
    3543              : 
    3544              :           // Precision
    3545            0 :           if (format_spec.precision.tag != Fmt::ffi::Count::Tag::CountImplied)
    3546              :             {
    3547            0 :               has_format_spec = true;
    3548            0 :               format_part += ".";
    3549            0 :               switch (format_spec.precision.tag)
    3550              :                 {
    3551            0 :                 case Fmt::ffi::Count::Tag::CountIs:
    3552            0 :                   format_part
    3553            0 :                     += std::to_string (format_spec.precision.count_is._0);
    3554            0 :                   break;
    3555            0 :                 case Fmt::ffi::Count::Tag::CountIsParam:
    3556            0 :                   format_part
    3557            0 :                     += std::to_string (format_spec.precision.count_is_param._0)
    3558            0 :                        + "$";
    3559            0 :                   break;
    3560            0 :                 case Fmt::ffi::Count::Tag::CountIsName:
    3561            0 :                   format_part
    3562            0 :                     += format_spec.precision.count_is_name._0.to_string ()
    3563            0 :                        + "$";
    3564            0 :                   break;
    3565            0 :                 case Fmt::ffi::Count::Tag::CountIsStar:
    3566            0 :                   format_part += "*";
    3567            0 :                   break;
    3568              :                 case Fmt::ffi::Count::Tag::CountImplied:
    3569              :                   break;
    3570              :                 }
    3571              :             }
    3572              : 
    3573              :           // Type/trait (like ?, x, X, etc.)
    3574            0 :           std::string type_str = format_spec.ty.to_string ();
    3575            0 :           if (!type_str.empty ())
    3576              :             {
    3577            0 :               has_format_spec = true;
    3578            0 :               format_part += type_str;
    3579              :             }
    3580              : 
    3581              :           // Add the format specification if any
    3582            0 :           if (has_format_spec)
    3583              :             {
    3584            0 :               reconstructed_template += ":";
    3585            0 :               reconstructed_template += format_part;
    3586              :             }
    3587              : 
    3588            0 :           reconstructed_template += "}";
    3589              :         }
    3590              :     }
    3591            0 :   reconstructed_template += "\"";
    3592              : 
    3593            0 :   push (Rust::Token::make_string (fmt.get_locus (), reconstructed_template));
    3594              : 
    3595              :   // Visit format arguments if any exist
    3596            0 :   auto &arguments = fmt.get_arguments ();
    3597            0 :   if (!arguments.empty ())
    3598              :     {
    3599            0 :       push (Rust::Token::make (COMMA, fmt.get_locus ()));
    3600              : 
    3601            0 :       auto &args = arguments.get_args ();
    3602            0 :       for (size_t i = 0; i < args.size (); ++i)
    3603              :         {
    3604            0 :           if (i > 0)
    3605              :             {
    3606            0 :               push (Rust::Token::make (COMMA, fmt.get_locus ()));
    3607              :             }
    3608              : 
    3609            0 :           auto kind = args[i].get_kind ();
    3610              : 
    3611              :           // Handle named arguments: name = expr
    3612            0 :           if (kind.kind == FormatArgumentKind::Kind::Named)
    3613              :             {
    3614            0 :               auto ident = kind.get_ident ().as_string ();
    3615            0 :               push (Rust::Token::make_identifier (fmt.get_locus (),
    3616              :                                                   std::move (ident)));
    3617            0 :               push (Rust::Token::make (EQUAL, fmt.get_locus ()));
    3618            0 :             }
    3619              :           // Note: Captured arguments are handled implicitly in the
    3620              :           // template reconstruction They don't need explicit "name ="
    3621              :           // syntax in the reconstructed macro call
    3622              : 
    3623            0 :           auto &expr = args[i].get_expr ();
    3624            0 :           expr.accept_vis (*this);
    3625            0 :         }
    3626              :     }
    3627              : 
    3628            0 :   push (Rust::Token::make (RIGHT_PAREN, fmt.get_locus ()));
    3629            0 : }
    3630              : 
    3631              : void
    3632           14 : TokenCollector::visit (AST::OffsetOf &offset_of)
    3633              : {
    3634           14 :   auto loc = offset_of.get_locus ();
    3635              : 
    3636           28 :   push (Rust::Token::make_identifier (loc, "offset_of"));
    3637           14 :   push (Rust::Token::make (EXCLAM, loc));
    3638           14 :   push (Rust::Token::make (LEFT_PAREN, loc));
    3639              : 
    3640           14 :   visit (offset_of.get_type ());
    3641              : 
    3642           14 :   push (Rust::Token::make (COMMA, loc));
    3643              : 
    3644           14 :   push (Rust::Token::make_identifier (offset_of.get_field ()));
    3645              : 
    3646           14 :   push (Rust::Token::make (RIGHT_PAREN, loc));
    3647           14 : }
    3648              : 
    3649              : } // namespace AST
    3650              : } // namespace Rust
        

Generated by: LCOV version 2.5.0-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.