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.2 % 2264 1861
Test Date: 2026-09-12 16:25:28 Functions: 89.4 % 368 329
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         4340 : TokenCollector::collect () const
      49              : {
      50         4340 :   return tokens;
      51              : }
      52              : 
      53              : void
      54         4337 : TokenCollector::visit (AST::Crate &crate)
      55              : {
      56         4337 :   visit_items_as_lines (crate.inner_attrs);
      57         4337 :   visit_items_as_lines (crate.items);
      58         4337 : }
      59              : 
      60              : void
      61            3 : TokenCollector::visit (AST::Item &item)
      62              : {
      63            3 :   item.accept_vis (*this);
      64            3 : }
      65              : 
      66              : void
      67         4397 : TokenCollector::trailing_comma ()
      68              : {
      69         4397 :   if (output_trailing_commas)
      70              :     {
      71            0 :       push (Rust::Token::make (COMMA, UNDEF_LOCATION));
      72              :     }
      73         4397 : }
      74              : 
      75              : void
      76       205120 : TokenCollector::newline ()
      77              : {
      78       205120 :   tokens.emplace_back (CollectItem::Kind::Newline);
      79       205120 : }
      80              : 
      81              : void
      82       149482 : TokenCollector::indentation ()
      83              : {
      84       149482 :   tokens.emplace_back (indent_level);
      85       149482 : }
      86              : 
      87              : void
      88        35681 : TokenCollector::increment_indentation ()
      89              : {
      90        35681 :   indent_level++;
      91        35681 : }
      92              : 
      93              : void
      94        35681 : TokenCollector::decrement_indentation ()
      95              : {
      96        35681 :   rust_assert (indent_level != 0);
      97        35681 :   indent_level--;
      98        35681 : }
      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       679763 : TokenCollector::describe_node (const std::string &node_name,
     108              :                                std::function<void ()> visitor)
     109              : {
     110       679763 :   tokens.emplace_back (CollectItem::make_begin_node_description (node_name));
     111              : 
     112       679763 :   visitor ();
     113              : 
     114       679763 :   tokens.push_back (CollectItem::make_end_node_description (node_name));
     115       679763 : }
     116              : 
     117              : void
     118            0 : TokenCollector::visit (Visitable &v)
     119              : {
     120            0 :   v.accept_vis (*this);
     121            0 : }
     122              : 
     123              : void
     124        10729 : TokenCollector::visit (FunctionParam &param)
     125              : {
     126        10729 :   describe_node (std::string ("FunctionParam"), [this, &param] () {
     127        10729 :     visit_items_as_lines (param.get_outer_attrs ());
     128        10729 :     if (!param.is_variadic ())
     129              :       {
     130        10729 :         visit (param.get_pattern ());
     131        10729 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
     132        10729 :         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        10729 :   });
     144        10729 : }
     145              : 
     146              : void
     147          875 : TokenCollector::visit (VariadicParam &param)
     148              : {
     149          875 :   describe_node (std::string ("VariadicParam"), [this, &param] () {
     150          875 :     if (param.has_pattern ())
     151              :       {
     152            9 :         visit (param.get_pattern ());
     153           18 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
     154              :       }
     155          875 :     push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
     156          875 :   });
     157          875 : }
     158              : 
     159              : void
     160        26685 : TokenCollector::visit (Attribute &attrib)
     161              : {
     162        26685 :   describe_node (std::string ("Attribute"), [this, &attrib] () {
     163        26685 :     push (Rust::Token::make (HASH, attrib.get_locus ()));
     164        26685 :     if (attrib.is_inner_attribute ())
     165        22344 :       push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
     166        26685 :     push (Rust::Token::make (LEFT_SQUARE, UNDEF_LOCATION));
     167        26685 :     visit (attrib.get_path ());
     168              : 
     169        26685 :     if (attrib.has_attr_input ())
     170              :       {
     171        20786 :         switch (attrib.get_attr_input ().get_attr_input_type ())
     172              :           {
     173        11240 :           case AST::AttrInput::AttrInputType::LITERAL:
     174        11240 :             {
     175        11240 :               visit (
     176        11240 :                 static_cast<AttrInputLiteral &> (attrib.get_attr_input ()));
     177        11240 :               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          352 :           case AST::AttrInput::AttrInputType::META_ITEM:
     185          352 :             {
     186          352 :               visit (static_cast<AttrInputMetaItemContainer &> (
     187          352 :                 attrib.get_attr_input ()));
     188          352 :               break;
     189              :             }
     190         9193 :           case AST::AttrInput::AttrInputType::TOKEN_TREE:
     191         9193 :             {
     192         9193 :               visit (static_cast<DelimTokenTree &> (attrib.get_attr_input ()));
     193         9193 :               break;
     194              :             }
     195            0 :           default:
     196            0 :             rust_unreachable ();
     197              :           }
     198              :       }
     199        26685 :     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
     200        26685 :   });
     201        26685 : }
     202              : 
     203              : void
     204        28120 : TokenCollector::visit (SimplePath &path)
     205              : {
     206        28120 :   describe_node (std::string ("SimplePath"), [this, &path] () {
     207        28120 :     if (path.has_opening_scope_resolution ())
     208              :       {
     209            0 :         push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ()));
     210              :       }
     211        28120 :     visit_items_joined_by_separator (path.get_segments (), SCOPE_RESOLUTION);
     212        28120 :   });
     213        28120 : }
     214              : 
     215              : void
     216        29092 : TokenCollector::visit (SimplePathSegment &segment)
     217              : {
     218        29092 :   describe_node (std::string ("SimplePathSegment"), [this, &segment] () {
     219        29092 :     auto name = segment.get_segment_name ();
     220        29092 :     if (segment.is_crate_path_seg ())
     221              :       {
     222          266 :         push (Rust::Token::make (CRATE, segment.get_locus ()));
     223              :       }
     224        28959 :     else if (segment.is_super_path_seg ())
     225              :       {
     226          576 :         push (Rust::Token::make (SUPER, segment.get_locus ()));
     227              :       }
     228        28671 :     else if (segment.is_lower_self_seg ())
     229              :       {
     230          122 :         push (Rust::Token::make (SELF, segment.get_locus ()));
     231              :       }
     232        28610 :     else if (segment.is_big_self ())
     233              :       {
     234            0 :         push (Rust::Token::make (SELF_ALIAS, segment.get_locus ()));
     235              :       }
     236              :     else
     237              :       {
     238        57220 :         push (Rust::Token::make_identifier (segment.get_locus (),
     239              :                                             std::move (name)));
     240              :       }
     241        29092 :   });
     242        29092 : }
     243              : 
     244              : void
     245        27981 : TokenCollector::visit (Visibility &vis)
     246              : {
     247        27981 :   describe_node (std::string ("Visibility"), [this, &vis] () {
     248        27981 :     switch (vis.get_vis_type ())
     249              :       {
     250         8311 :       case Visibility::PUB:
     251         8311 :         push (Rust::Token::make (PUB, vis.get_locus ()));
     252         8311 :         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        27981 :   });
     282        27981 : }
     283              : 
     284              : void
     285         8811 : TokenCollector::visit (std::vector<std::unique_ptr<GenericParam>> &params)
     286              : {
     287         8811 :   describe_node (std::string ("GenericParam"), [this, &params] () {
     288         8811 :     push (Rust::Token::make (LEFT_ANGLE, UNDEF_LOCATION));
     289         8811 :     visit_items_joined_by_separator (params, COMMA);
     290         8811 :     push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
     291         8811 :   });
     292         8811 : }
     293              : 
     294              : void
     295         2009 : TokenCollector::visit (TupleField &field)
     296              : {
     297         2009 :   describe_node (std::string ("TupleField"), [this, &field] () {
     298         2066 :     for (auto attr : field.get_outer_attrs ())
     299              :       {
     300           57 :         visit (attr);
     301           57 :       }
     302         2009 :     visit (field.get_visibility ());
     303         2009 :     visit (field.get_field_type ());
     304         2009 :   });
     305         2009 : }
     306              : 
     307              : void
     308         2248 : TokenCollector::visit (StructField &field)
     309              : {
     310         2248 :   describe_node (std::string ("StructField"), [this, &field] () {
     311         2249 :     for (auto attr : field.get_outer_attrs ())
     312              :       {
     313            1 :         visit (attr);
     314            1 :       }
     315         2248 :     visit (field.get_visibility ());
     316         4496 :     auto name = field.get_field_name ().as_string ();
     317         4496 :     push (Rust::Token::make_identifier (field.get_locus (), std::move (name)));
     318         2248 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
     319         2248 :     visit (field.get_field_type ());
     320         2248 :   });
     321         2248 : }
     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        18256 : TokenCollector::visit (FunctionQualifiers &qualifiers)
     336              : {
     337              :   // Syntax:
     338              :   //    `const`? `async`? `unsafe`? (`extern` Abi?)?
     339              :   //    unsafe? (extern Abi?)?
     340        18256 :   describe_node (std::string ("FunctionQualifiers"), [this, &qualifiers] () {
     341        18256 :     if (qualifiers.is_async ())
     342            2 :       push (Rust::Token::make (ASYNC, qualifiers.get_locus ()));
     343        18256 :     if (qualifiers.is_const ())
     344         1760 :       push (Rust::Token::make (CONST, qualifiers.get_locus ()));
     345        18256 :     if (qualifiers.is_unsafe ())
     346          998 :       push (Rust::Token::make (UNSAFE, qualifiers.get_locus ()));
     347        18256 :     if (qualifiers.is_extern ())
     348              :       {
     349           70 :         push (Rust::Token::make (EXTERN_KW, qualifiers.get_locus ()));
     350           70 :         if (qualifiers.has_abi ())
     351              :           {
     352          140 :             push (Rust::Token::make_string (UNDEF_LOCATION,
     353          210 :                                             qualifiers.get_extern_abi ()));
     354              :           }
     355              :       }
     356        18256 :   });
     357        18256 : }
     358              : 
     359              : void
     360           63 : TokenCollector::visit (MaybeNamedParam &param)
     361              : {
     362              :   // Syntax:
     363              :   //     OuterAttribute* ( ( IDENTIFIER | _ ) : )? Type
     364              : 
     365           63 :   describe_node (std::string ("MaybeNamedParam"), [this, &param] () {
     366           63 :     for (auto attr : param.get_outer_attrs ())
     367              :       {
     368            0 :         visit (attr);
     369            0 :       }
     370          126 :     auto param_name = param.get_name ().as_string ();
     371           63 :     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           63 :     visit (param.get_type ());
     386           63 :   });
     387           63 : }
     388              : 
     389              : void
     390        73297 : TokenCollector::visit (Token &tok)
     391              : {
     392        73297 :   std::string data
     393        96406 :     = tok.get_tok_ptr ()->should_have_str () ? tok.get_str () : "";
     394        73297 :   switch (tok.get_id ())
     395              :     {
     396        18557 :     case IDENTIFIER:
     397        37114 :       push (Rust::Token::make_identifier (tok.get_locus (), std::move (data)));
     398        18557 :       break;
     399          351 :     case INT_LITERAL:
     400          351 :       {
     401          351 :         auto suffix_start = data.length ();
     402          702 :         push (Rust::Token::make_int (tok.get_locus (), std::move (data),
     403              :                                      suffix_start, IntegerLiteralBase::Decimal,
     404              :                                      tok.get_type_hint ()));
     405          351 :         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         4191 :     case STRING_LITERAL:
     415         8382 :       push (Rust::Token::make_string (tok.get_locus (), std::move (data)));
     416         4191 :       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        50188 :     default:
     447       100376 :       push (Rust::Token::make (tok.get_id (), tok.get_locus ()));
     448              :     }
     449        73297 : }
     450              : 
     451              : void
     452        10399 : TokenCollector::visit (DelimTokenTree &delim_tok_tree)
     453              : {
     454        10399 :   describe_node (std::string ("DelimTokenTree"), [this, &delim_tok_tree] () {
     455        83231 :     for (auto &token : delim_tok_tree.to_token_stream ())
     456              :       {
     457        72832 :         visit (token);
     458        10399 :       }
     459        10399 :   });
     460        10399 : }
     461              : 
     462              : void
     463          352 : TokenCollector::visit (AttrInputMetaItemContainer &container)
     464              : {
     465          352 :   describe_node (std::string ("AttrInputMetaItemContainer"),
     466          352 :                  [this, &container] () {
     467          704 :                    for (auto &item : container.get_items ())
     468              :                      {
     469          352 :                        visit (item);
     470              :                      }
     471          352 :                  });
     472          352 : }
     473              : 
     474              : void
     475        24767 : TokenCollector::visit (IdentifierExpr &ident_expr)
     476              : {
     477        24767 :   describe_node (std::string ("IdentifierExpr"), [this, &ident_expr] () {
     478        49534 :     auto ident = ident_expr.get_ident ().as_string ();
     479        49534 :     push (Rust::Token::make_identifier (ident_expr.get_locus (),
     480              :                                         std::move (ident)));
     481        24767 :   });
     482        24767 : }
     483              : 
     484              : void
     485         9590 : TokenCollector::visit (Lifetime &lifetime)
     486              : {
     487              :   // Syntax:
     488              :   // Lifetime :
     489              :   //    LIFETIME_OR_LABEL
     490              :   //    | 'static
     491              :   //    | '_
     492              : 
     493         9590 :   describe_node (std::string ("Lifetime"), [this, &lifetime] () {
     494         9590 :     auto name = lifetime.get_lifetime_name ();
     495         9590 :     switch (lifetime.get_lifetime_type ())
     496              :       {
     497          496 :       case Lifetime::LifetimeType::NAMED:
     498          496 :         push (
     499          992 :           Rust::Token::make_lifetime (lifetime.get_locus (), std::move (name)));
     500          496 :         break;
     501          111 :       case Lifetime::LifetimeType::STATIC:
     502          222 :         push (Rust::Token::make_lifetime (lifetime.get_locus (),
     503          111 :                                           Values::Keywords::STATIC_KW));
     504          111 :         break;
     505         8983 :       case Lifetime::LifetimeType::WILDCARD:
     506        17966 :         push (Rust::Token::make_lifetime (lifetime.get_locus (),
     507         8983 :                                           Values::Keywords::UNDERSCORE));
     508         8983 :         break;
     509              :       }
     510         9590 :   });
     511         9590 : }
     512              : 
     513              : void
     514          159 : 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          159 :   describe_node (std::string ("LifetimeParam"), [this, &lifetime_param] () {
     523          159 :     visit_items_as_lines (lifetime_param.get_outer_attrs ());
     524          159 :     auto lifetime = lifetime_param.get_lifetime ();
     525          159 :     visit (lifetime);
     526              : 
     527          159 :     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          159 :   });
     536          159 : }
     537              : 
     538              : void
     539           73 : TokenCollector::visit (ConstGenericParam &param)
     540              : {
     541              :   // Syntax:
     542              :   // const IDENTIFIER : Type ( = Block | IDENTIFIER | -?LITERAL )?
     543           73 :   describe_node (std::string ("ConstGenericParam"), [this, &param] () {
     544           73 :     visit_items_as_lines (param.get_outer_attrs ());
     545           73 :     push (Rust::Token::make (CONST, param.get_locus ()));
     546           73 :     auto id = param.get_name ().as_string ();
     547          146 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
     548           73 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
     549           73 :     if (param.has_type ())
     550           73 :       visit (param.get_type ());
     551           73 :     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           73 :   });
     557           73 : }
     558              : 
     559              : void
     560        37685 : TokenCollector::visit (PathExprSegment &segment)
     561              : {
     562        37685 :   describe_node (std::string ("PathExprSegment"), [this, &segment] () {
     563        37685 :     visit (segment.get_ident_segment ());
     564        37685 :     if (segment.has_generic_args ())
     565              :       {
     566          899 :         auto generics = segment.get_generic_args ();
     567          899 :         push (Rust::Token::make (SCOPE_RESOLUTION, segment.get_locus ()));
     568          899 :         push (Rust::Token::make (LEFT_ANGLE, generics.get_locus ()));
     569              : 
     570          899 :         auto &lifetime_args = generics.get_lifetime_args ();
     571          899 :         auto &generic_args = generics.get_generic_args ();
     572          899 :         auto &binding_args = generics.get_binding_args ();
     573              : 
     574          899 :         visit_items_joined_by_separator (generic_args, COMMA);
     575              : 
     576          899 :         if (!lifetime_args.empty ()
     577          899 :             && (!generic_args.empty () || !binding_args.empty ()))
     578              :           {
     579            0 :             push (Rust::Token::make (COMMA, UNDEF_LOCATION));
     580              :           }
     581              : 
     582          899 :         visit_items_joined_by_separator (binding_args, COMMA);
     583              : 
     584          899 :         if (!generic_args.empty () && !binding_args.empty ())
     585              :           {
     586            0 :             push (Rust::Token::make (COMMA, UNDEF_LOCATION));
     587              :           }
     588              : 
     589          899 :         visit_items_joined_by_separator (lifetime_args, COMMA);
     590              : 
     591          899 :         push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
     592          899 :       }
     593        37685 :   });
     594        37685 : }
     595              : 
     596              : void
     597        25576 : TokenCollector::visit (PathInExpression &path)
     598              : {
     599        25576 :   describe_node (std::string ("PathInExpression"), [this, &path] () {
     600        25576 :     if (path.is_lang_item ())
     601              :       {
     602          139 :         push (Rust::Token::make (TokenId::HASH, path.get_locus ()));
     603          139 :         push (Rust::Token::make (TokenId::LEFT_SQUARE, path.get_locus ()));
     604          278 :         push (Rust::Token::make_identifier (path.get_locus (), "lang"));
     605          139 :         push (Rust::Token::make (TokenId::EQUAL, path.get_locus ()));
     606          278 :         push (Rust::Token::make_string (
     607          139 :           path.get_locus (), LangItem::ToString (path.get_lang_item ())));
     608          139 :         push (Rust::Token::make (TokenId::RIGHT_SQUARE, path.get_locus ()));
     609              : 
     610          139 :         return;
     611              :       }
     612              : 
     613        25437 :     if (path.opening_scope_resolution ())
     614          762 :       push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ()));
     615              : 
     616        25437 :     visit_items_joined_by_separator (path.get_segments (), SCOPE_RESOLUTION);
     617              :   });
     618        25576 : }
     619              : 
     620              : void
     621        55374 : TokenCollector::visit (TypePathSegment &segment)
     622              : {
     623              :   // Syntax:
     624              :   //    PathIdentSegment
     625        55374 :   describe_node (std::string ("TypePathSegment"), [this, &segment] () {
     626        55374 :     auto locus = segment.is_lang_item ()
     627        55374 :                    ? segment.get_locus ()
     628        55044 :                    : segment.get_ident_segment ().get_locus ();
     629        55374 :     auto segment_string = segment.is_lang_item ()
     630        55374 :                             ? LangItem::PrettyString (segment.get_lang_item ())
     631        55374 :                             : segment.get_ident_segment ().as_string ();
     632       110748 :     push (Rust::Token::make_identifier (locus, std::move (segment_string)));
     633        55374 :   });
     634        55374 : }
     635              : 
     636              : void
     637         3132 : TokenCollector::visit (TypePathSegmentGeneric &segment)
     638              : {
     639              :   // Syntax:
     640              :   //    PathIdentSegment `::`? (GenericArgs)?
     641              :   // GenericArgs :
     642              :   //    `<` `>`
     643              :   //    | `<` ( GenericArg `,` )* GenericArg `,`? `>`
     644         3132 :   describe_node (std::string ("TypePathSegmentGeneric"), [this, &segment] () {
     645         3132 :     auto locus = segment.is_lang_item ()
     646         3132 :                    ? segment.get_locus ()
     647         3085 :                    : segment.get_ident_segment ().get_locus ();
     648         3132 :     auto segment_string = segment.is_lang_item ()
     649         3132 :                             ? LangItem::PrettyString (segment.get_lang_item ())
     650         3132 :                             : segment.get_ident_segment ().as_string ();
     651         6264 :     push (Rust::Token::make_identifier (locus, std::move (segment_string)));
     652              : 
     653         3132 :     push (Rust::Token::make (LEFT_ANGLE, UNDEF_LOCATION));
     654              : 
     655         3132 :     {
     656         3132 :       auto &lifetime_args = segment.get_generic_args ().get_lifetime_args ();
     657         3132 :       auto &generic_args = segment.get_generic_args ().get_generic_args ();
     658         3132 :       auto &binding_args = segment.get_generic_args ().get_binding_args ();
     659              : 
     660         3132 :       visit_items_joined_by_separator (lifetime_args, COMMA);
     661         3132 :       if (!lifetime_args.empty ()
     662         3132 :           && (!generic_args.empty () || !binding_args.empty ()))
     663            4 :         push (Rust::Token::make (COMMA, UNDEF_LOCATION));
     664         3132 :       visit_items_joined_by_separator (generic_args, COMMA);
     665         3132 :       if (!generic_args.empty () && !binding_args.empty ())
     666            0 :         push (Rust::Token::make (COMMA, UNDEF_LOCATION));
     667         3132 :       visit_items_joined_by_separator (binding_args, COMMA);
     668              :     }
     669              : 
     670         6264 :     push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
     671         3132 :   });
     672         3132 : }
     673              : 
     674              : void
     675           40 : TokenCollector::visit (GenericArgsBinding &binding)
     676              : {
     677              :   // Syntax:
     678              :   //    IDENTIFIER `=` Type
     679           40 :   describe_node (std::string ("GenericArgsBinding"), [this, &binding] () {
     680           80 :     auto identifier = binding.get_identifier ().as_string ();
     681           80 :     push (Rust::Token::make_identifier (binding.get_locus (),
     682              :                                         std::move (identifier)));
     683              : 
     684           40 :     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
     685           40 :     visit (binding.get_type ());
     686           40 :   });
     687           40 : }
     688              : 
     689              : void
     690         4251 : 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         4251 :   describe_node (std::string ("GenericArg"), [this, &arg] () {
     695         4251 :     switch (arg.get_kind ())
     696              :       {
     697          110 :       case GenericArg::Kind::Const:
     698          110 :         visit (arg.get_expression ());
     699          110 :         break;
     700         4134 :       case GenericArg::Kind::Type:
     701         4134 :         visit (arg.get_type ());
     702         4134 :         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         4251 :   });
     712         4251 : }
     713              : 
     714              : void
     715           27 : TokenCollector::visit (TypePathSegmentFunction &segment)
     716              : {
     717              :   // Syntax:
     718              :   //   PathIdentSegment `::`? (TypePathFn)?
     719           27 :   describe_node (std::string ("TypePathSegmentFunction"), [this, &segment] () {
     720           27 :     auto ident_segment = segment.get_ident_segment ();
     721           27 :     auto id = ident_segment.as_string ();
     722           54 :     push (Rust::Token::make_identifier (ident_segment.get_locus (),
     723              :                                         std::move (id)));
     724              : 
     725           27 :     if (segment.get_separating_scope_resolution ())
     726            0 :       push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
     727              : 
     728           27 :     if (!segment.is_ident_only ())
     729           27 :       visit (segment.get_type_path_function ());
     730           27 :   });
     731           27 : }
     732              : 
     733              : void
     734           27 : TokenCollector::visit (TypePathFunction &type_path_fn)
     735              : {
     736              :   // Syntax:
     737              :   //   `(` TypePathFnInputs? `)` (`->` Type)?
     738              :   // TypePathFnInputs :
     739              :   //   Type (`,` Type)* `,`?
     740           27 :   describe_node (std::string ("TypePathFunction"), [this, &type_path_fn] () {
     741           27 :     push (Rust::Token::make (LEFT_PAREN, type_path_fn.get_locus ()));
     742           27 :     if (type_path_fn.has_inputs ())
     743           27 :       visit_items_joined_by_separator (type_path_fn.get_params (), COMMA);
     744           27 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
     745              : 
     746           27 :     if (type_path_fn.has_return_type ())
     747              :       {
     748           27 :         push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
     749           27 :         visit (type_path_fn.get_return_type ());
     750              :       }
     751           27 :   });
     752           27 : }
     753              : 
     754              : void
     755        56476 : TokenCollector::visit (TypePath &path)
     756              : {
     757              :   // Syntax:
     758              :   //    `::`? TypePathSegment (`::` TypePathSegment)*
     759        56476 :   describe_node (std::string ("TypePath"), [this, &path] () {
     760        56476 :     if (path.has_opening_scope_resolution_op ())
     761          708 :       push (Rust::Token::make (SCOPE_RESOLUTION, path.get_locus ()));
     762              : 
     763        56476 :     visit_items_joined_by_separator (path.get_segments (), SCOPE_RESOLUTION);
     764        56476 :   });
     765        56476 : }
     766              : 
     767              : void
     768        37685 : TokenCollector::visit (PathIdentSegment &segment)
     769              : {
     770        37685 :   describe_node (std::string ("PathIdentSegment"), [this, &segment] () {
     771        37685 :     if (segment.is_super_path_seg ())
     772              :       {
     773            2 :         push (Rust::Token::make (SUPER, segment.get_locus ()));
     774              :       }
     775        37684 :     else if (segment.is_crate_path_seg ())
     776              :       {
     777         2192 :         push (Rust::Token::make (CRATE, segment.get_locus ()));
     778              :       }
     779        36588 :     else if (segment.is_lower_self_seg ())
     780              :       {
     781        13452 :         push (Rust::Token::make (SELF, segment.get_locus ()));
     782              :       }
     783        29862 :     else if (segment.is_big_self_seg ())
     784              :       {
     785          840 :         push (Rust::Token::make (SELF_ALIAS, segment.get_locus ()));
     786              :       }
     787              :     else
     788              :       {
     789        29442 :         auto id = segment.as_string ();
     790        29442 :         push (
     791        58884 :           Rust::Token::make_identifier (segment.get_locus (), std::move (id)));
     792        29442 :       }
     793        37685 :   });
     794        37685 : }
     795              : 
     796              : void
     797          112 : TokenCollector::visit (QualifiedPathInExpression &path)
     798              : {
     799          112 :   describe_node (std::string ("QualifiedPathInExpression"), [this, &path] () {
     800          112 :     visit (path.get_qualified_path_type ());
     801          224 :     for (auto &segment : path.get_segments ())
     802              :       {
     803          112 :         push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
     804          112 :         visit (segment);
     805              :       }
     806          112 :   });
     807          112 : }
     808              : 
     809              : void
     810          386 : TokenCollector::visit (QualifiedPathType &path)
     811              : {
     812          386 :   describe_node (std::string ("QualifiedPathType"), [this, &path] () {
     813          386 :     push (Rust::Token::make (LEFT_ANGLE, path.get_locus ()));
     814          386 :     visit (path.get_type ());
     815          386 :     if (path.has_as_clause ())
     816              :       {
     817          353 :         push (Rust::Token::make (AS, UNDEF_LOCATION));
     818          353 :         visit (path.get_as_type_path ());
     819              :       }
     820          386 :     push (Rust::Token::make (RIGHT_ANGLE, UNDEF_LOCATION));
     821          386 :   });
     822          386 : }
     823              : 
     824              : void
     825          274 : TokenCollector::visit (QualifiedPathInType &path)
     826              : {
     827          274 :   describe_node (std::string ("QualifiedPathInType"), [this, &path] () {
     828          274 :     visit (path.get_qualified_path_type ());
     829              : 
     830          274 :     push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
     831          274 :     visit (path.get_associated_segment ());
     832          274 :     for (auto &segment : path.get_segments ())
     833              :       {
     834            0 :         push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
     835            0 :         visit (segment);
     836              :       }
     837          274 :   });
     838          274 : }
     839              : 
     840              : void
     841        32519 : TokenCollector::visit (Literal &lit, location_t locus)
     842              : {
     843        32519 :   auto value = lit.as_string ();
     844        32519 :   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        13685 :     case Literal::LitType::STRING:
     853        27370 :       push (Rust::Token::make_string (locus, std::move (value)));
     854        13685 :       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        16576 :     case Literal::LitType::INT:
     868        16576 :       {
     869        16576 :         auto val_len = value.length ();
     870        33152 :         push (Rust::Token::make_int (locus, std::move (value), val_len,
     871              :                                      IntegerLiteralBase::Decimal,
     872              :                                      lit.get_type_hint ()));
     873        16576 :         break;
     874              :       }
     875          329 :     case Literal::LitType::FLOAT:
     876          329 :       {
     877          329 :         auto val_len = value.length ();
     878          658 :         push (Rust::Token::make_float (locus, std::move (value), val_len,
     879              :                                        lit.get_type_hint ()));
     880          329 :         break;
     881              :       }
     882         1285 :     case Literal::LitType::BOOL:
     883         1285 :       {
     884         1285 :         if (value == Values::Keywords::FALSE_LITERAL)
     885         1098 :           push (Rust::Token::make (FALSE_LITERAL, locus));
     886          736 :         else if (value == Values::Keywords::TRUE_LITERAL)
     887         1472 :           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        32519 :       break;
     895              :     }
     896        32519 : }
     897              : 
     898              : void
     899        32043 : TokenCollector::visit (LiteralExpr &expr)
     900              : {
     901        32043 :   describe_node (std::string ("LiteralExpr"), [this, &expr] () {
     902        32043 :     auto lit = expr.get_literal ();
     903        32043 :     visit (lit, expr.get_locus ());
     904        32043 :   });
     905        32043 : }
     906              : 
     907              : void
     908        11240 : TokenCollector::visit (AttrInputLiteral &literal)
     909              : {
     910        11240 :   describe_node (std::string ("AttrInputLiteral"), [this, &literal] () {
     911        11240 :     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
     912        11240 :     visit (literal.get_literal ());
     913        11240 :   });
     914        11240 : }
     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         1940 : TokenCollector::visit (BorrowExpr &expr)
     946              : {
     947         1940 :   describe_node (std::string ("BorrowExpr"), [this, &expr] () {
     948         1940 :     push (Rust::Token::make (AMP, expr.get_locus ()));
     949         1940 :     if (expr.get_is_double_borrow ())
     950           46 :       push (Rust::Token::make (AMP, UNDEF_LOCATION));
     951              : 
     952         1940 :     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         1936 :         if (expr.get_is_mut ())
     964          774 :           push (Rust::Token::make (MUT, UNDEF_LOCATION));
     965              :       }
     966              : 
     967         1940 :     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         1936 :         if (expr.get_is_mut ())
     979          774 :           push (Rust::Token::make (MUT, UNDEF_LOCATION));
     980              :       }
     981              : 
     982         1940 :     if (expr.has_borrow_expr ())
     983         1940 :       visit (expr.get_borrowed_expr ());
     984         1940 :   });
     985         1940 : }
     986              : 
     987              : void
     988         3791 : TokenCollector::visit (DereferenceExpr &expr)
     989              : {
     990         3791 :   describe_node (std::string ("DereferenceExpr"), [this, &expr] () {
     991         3791 :     push (Rust::Token::make (ASTERISK, expr.get_locus ()));
     992         3791 :     visit (expr.get_dereferenced_expr ());
     993         3791 :   });
     994         3791 : }
     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          857 : TokenCollector::visit (NegationExpr &expr)
    1007              : {
    1008          857 :   describe_node (std::string ("NegationExpr"), [this, &expr] () {
    1009          857 :     switch (expr.get_expr_type ())
    1010              :       {
    1011          409 :       case NegationOperator::NEGATE:
    1012          409 :         push (Rust::Token::make (MINUS, expr.get_locus ()));
    1013          409 :         break;
    1014          448 :       case NegationOperator::NOT:
    1015          448 :         push (Rust::Token::make (EXCLAM, expr.get_locus ()));
    1016          448 :         break;
    1017              :       }
    1018          857 :     visit (expr.get_negated_expr ());
    1019          857 :   });
    1020          857 : }
    1021              : 
    1022              : void
    1023         3426 : TokenCollector::visit (ArithmeticOrLogicalExpr &expr)
    1024              : {
    1025         3426 :   describe_node (std::string ("ArithmeticOrLogicalExpr"), [this, &expr] () {
    1026         3426 :     visit (expr.get_left_expr ());
    1027         3426 :     switch (expr.get_expr_type ())
    1028              :       {
    1029         1858 :       case ArithmeticOrLogicalOperator::ADD:
    1030         1858 :         push (Rust::Token::make (PLUS, expr.get_locus ()));
    1031         1858 :         break;
    1032              : 
    1033         1043 :       case ArithmeticOrLogicalOperator::SUBTRACT:
    1034         1043 :         push (Rust::Token::make (MINUS, expr.get_locus ()));
    1035         1043 :         break;
    1036              : 
    1037          242 :       case ArithmeticOrLogicalOperator::MULTIPLY:
    1038          242 :         push (Rust::Token::make (ASTERISK, expr.get_locus ()));
    1039          242 :         break;
    1040              : 
    1041           34 :       case ArithmeticOrLogicalOperator::DIVIDE:
    1042           34 :         push (Rust::Token::make (DIV, expr.get_locus ()));
    1043           34 :         break;
    1044              : 
    1045           40 :       case ArithmeticOrLogicalOperator::MODULUS:
    1046           40 :         push (Rust::Token::make (PERCENT, expr.get_locus ()));
    1047           40 :         break;
    1048              : 
    1049           48 :       case ArithmeticOrLogicalOperator::BITWISE_AND:
    1050           48 :         push (Rust::Token::make (AMP, expr.get_locus ()));
    1051           48 :         break;
    1052              : 
    1053           25 :       case ArithmeticOrLogicalOperator::BITWISE_OR:
    1054           25 :         push (Rust::Token::make (PIPE, expr.get_locus ()));
    1055           25 :         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         3426 :     visit (expr.get_right_expr ());
    1071         3426 :   });
    1072         3426 : }
    1073              : 
    1074              : void
    1075         3756 : TokenCollector::visit (ComparisonExpr &expr)
    1076              : {
    1077         3756 :   describe_node (std::string ("ComparisonExpr"), [this, &expr] () {
    1078         3756 :     visit (expr.get_left_expr ());
    1079              : 
    1080         3756 :     switch (expr.get_expr_type ())
    1081              :       {
    1082          904 :       case ComparisonOperator::EQUAL:
    1083          904 :         push (Rust::Token::make (EQUAL_EQUAL, expr.get_locus ()));
    1084          904 :         break;
    1085         1011 :       case ComparisonOperator::NOT_EQUAL:
    1086         1011 :         push (Rust::Token::make (NOT_EQUAL, expr.get_locus ()));
    1087         1011 :         break;
    1088          663 :       case ComparisonOperator::GREATER_THAN:
    1089          663 :         push (Rust::Token::make (RIGHT_ANGLE, expr.get_locus ()));
    1090          663 :         break;
    1091          656 :       case ComparisonOperator::LESS_THAN:
    1092          656 :         push (Rust::Token::make (LEFT_ANGLE, expr.get_locus ()));
    1093          656 :         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          286 :       case ComparisonOperator::LESS_OR_EQUAL:
    1099          286 :         push (Rust::Token::make (LESS_OR_EQUAL, expr.get_locus ()));
    1100          286 :         break;
    1101              :       }
    1102         3756 :     visit (expr.get_right_expr ());
    1103         3756 :   });
    1104         3756 : }
    1105              : 
    1106              : void
    1107          452 : TokenCollector::visit (LazyBooleanExpr &expr)
    1108              : {
    1109          452 :   describe_node (std::string ("LazyBooleanExpr"), [this, &expr] () {
    1110          452 :     visit (expr.get_left_expr ());
    1111              : 
    1112          452 :     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           74 :       case LazyBooleanOperator::LOGICAL_OR:
    1118           74 :         push (Rust::Token::make (OR, expr.get_locus ()));
    1119           74 :         break;
    1120              :       }
    1121              : 
    1122          452 :     visit (expr.get_right_expr ());
    1123          452 :   });
    1124          452 : }
    1125              : 
    1126              : void
    1127         5317 : TokenCollector::visit (TypeCastExpr &expr)
    1128              : {
    1129         5317 :   describe_node (std::string ("TypeCastExpr"), [this, &expr] () {
    1130         5317 :     visit (expr.get_casted_expr ());
    1131         5317 :     push (Rust::Token::make (AS, expr.get_locus ()));
    1132         5317 :     visit (expr.get_type_to_cast_to ());
    1133         5317 :   });
    1134         5317 : }
    1135              : 
    1136              : void
    1137         2470 : TokenCollector::visit (AssignmentExpr &expr)
    1138              : {
    1139         2470 :   describe_node (std::string ("AssignementExpr"), [this, &expr] () {
    1140         2470 :     expr.visit_lhs (*this);
    1141         2470 :     push (Rust::Token::make (EQUAL, expr.get_locus ()));
    1142         2470 :     expr.visit_rhs (*this);
    1143         2470 :   });
    1144         2470 : }
    1145              : 
    1146              : void
    1147          696 : TokenCollector::visit (CompoundAssignmentExpr &expr)
    1148              : {
    1149          696 :   describe_node (std::string ("CompoundAssignmentExpr"), [this, &expr] () {
    1150          696 :     visit (expr.get_left_expr ());
    1151              : 
    1152          696 :     switch (expr.get_expr_type ())
    1153              :       {
    1154          170 :       case CompoundAssignmentOperator::ADD:
    1155          170 :         push (Rust::Token::make (PLUS_EQ, expr.get_locus ()));
    1156          170 :         break;
    1157          106 :       case CompoundAssignmentOperator::SUBTRACT:
    1158          106 :         push (Rust::Token::make (MINUS_EQ, expr.get_locus ()));
    1159          106 :         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          696 :     visit (expr.get_right_expr ());
    1186          696 :   });
    1187          696 : }
    1188              : 
    1189              : void
    1190          316 : TokenCollector::visit (GroupedExpr &expr)
    1191              : {
    1192          316 :   describe_node (std::string ("GroupedExpr"), [this, &expr] () {
    1193          316 :     push (Rust::Token::make (LEFT_PAREN, expr.get_locus ()));
    1194          316 :     visit (expr.get_expr_in_parens ());
    1195          316 :     push (Rust::Token::make (RIGHT_PAREN, expr.get_locus ()));
    1196          316 :   });
    1197          316 : }
    1198              : 
    1199              : void
    1200          294 : TokenCollector::visit (ArrayElemsValues &elems)
    1201              : {
    1202          294 :   describe_node (std::string ("ArraysElemValues"), [this, &elems] () {
    1203          294 :     visit_items_joined_by_separator (elems.get_values (), COMMA);
    1204          294 :   });
    1205          294 : }
    1206              : 
    1207              : void
    1208          114 : TokenCollector::visit (ArrayElemsCopied &elems)
    1209              : {
    1210          114 :   describe_node (std::string ("ArrayElemsCopied"), [this, &elems] () {
    1211          114 :     visit (elems.get_elem_to_copy ());
    1212          114 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    1213          114 :     visit (elems.get_num_copies ());
    1214          114 :   });
    1215          114 : }
    1216              : 
    1217              : void
    1218          408 : TokenCollector::visit (ArrayExpr &expr)
    1219              : {
    1220          408 :   describe_node (std::string ("ArrayExpr"), [this, &expr] () {
    1221          408 :     push (Rust::Token::make (LEFT_SQUARE, expr.get_locus ()));
    1222          408 :     visit (expr.get_array_elems ());
    1223          408 :     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
    1224          408 :   });
    1225          408 : }
    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          544 : TokenCollector::visit (TupleExpr &expr)
    1240              : {
    1241          544 :   describe_node (std::string ("TupleExpr"), [this, &expr] () {
    1242          544 :     visit_items_as_lines (expr.get_outer_attrs ());
    1243          544 :     push (Rust::Token::make (LEFT_PAREN, expr.get_locus ()));
    1244          544 :     visit_items_joined_by_separator (expr.get_tuple_elems (), COMMA);
    1245          544 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    1246          544 :   });
    1247          544 : }
    1248              : 
    1249              : void
    1250          894 : TokenCollector::visit (TupleIndexExpr &expr)
    1251              : {
    1252          894 :   describe_node (std::string ("TupleIndexExpr"), [this, &expr] () {
    1253          894 :     visit (expr.get_tuple_expr ());
    1254          894 :     push (Rust::Token::make (DOT, expr.get_locus ()));
    1255          894 :     auto str = std::to_string (expr.get_tuple_index ());
    1256          894 :     auto suffix_start = str.length ();
    1257         1788 :     push (Rust::Token::make_int (UNDEF_LOCATION, str, suffix_start,
    1258              :                                  IntegerLiteralBase::Decimal));
    1259          894 :   });
    1260          894 : }
    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          228 : TokenCollector::visit (StructExprFieldIdentifier &expr)
    1271              : {
    1272          228 :   describe_node (std::string ("StructExprFieldIdentifier"), [this, &expr] () {
    1273          228 :     visit_items_as_lines (expr.get_outer_attrs ());
    1274          456 :     auto id = expr.get_field_name ().as_string ();
    1275          456 :     push (Rust::Token::make_identifier (expr.get_locus (), std::move (id)));
    1276          228 :   });
    1277          228 : }
    1278              : 
    1279              : void
    1280         2055 : TokenCollector::visit (StructExprFieldIdentifierValue &expr)
    1281              : {
    1282         2055 :   describe_node (std::string ("StructExprFieldIdentifierValue"), [this,
    1283              :                                                                   &expr] () {
    1284         2055 :     visit_items_as_lines (expr.get_outer_attrs ());
    1285         2055 :     auto id = expr.get_field_name ();
    1286         4110 :     push (Rust::Token::make_identifier (expr.get_locus (), std::move (id)));
    1287         2055 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    1288         2055 :     visit (expr.get_value ());
    1289         2055 :   });
    1290         2055 : }
    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         1366 : TokenCollector::visit (StructExprStructFields &expr)
    1317              : {
    1318         1366 :   describe_node (std::string ("StructExprStructFields"), [this, &expr] () {
    1319         1366 :     visit (expr.get_struct_name ());
    1320         1366 :     push (Rust::Token::make (LEFT_CURLY, expr.get_locus ()));
    1321         1366 :     visit_items_joined_by_separator (expr.get_fields (), COMMA);
    1322         1366 :     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         1303 :         trailing_comma ();
    1330              :       }
    1331         1366 :     push (Rust::Token::make (RIGHT_CURLY, expr.get_locus ()));
    1332         1366 :   });
    1333         1366 : }
    1334              : 
    1335              : void
    1336            0 : TokenCollector::visit (StructExprStructBase &)
    1337              : {
    1338              :   // FIXME: Implement this node
    1339            0 :   rust_unreachable ();
    1340              : }
    1341              : 
    1342              : void
    1343        12541 : TokenCollector::visit (CallExpr &expr)
    1344              : {
    1345        12541 :   describe_node (std::string ("CallExpr"), [this, &expr] () {
    1346        12541 :     visit (expr.get_function_expr ());
    1347              : 
    1348        12541 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    1349              : 
    1350        12541 :     visit_items_joined_by_separator (expr.get_params (), COMMA);
    1351              : 
    1352        12541 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    1353        12541 :   });
    1354        12541 : }
    1355              : 
    1356              : void
    1357         3094 : TokenCollector::visit (MethodCallExpr &expr)
    1358              : {
    1359         3094 :   describe_node (std::string ("MethodCallExpr"), [this, &expr] () {
    1360         3094 :     visit (expr.get_receiver_expr ());
    1361         3094 :     push (Rust::Token::make (DOT, expr.get_locus ()));
    1362         3094 :     visit (expr.get_method_name ());
    1363         3094 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    1364         3094 :     visit_items_joined_by_separator (expr.get_params (), COMMA);
    1365         3094 :     trailing_comma ();
    1366         3094 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    1367         3094 :   });
    1368         3094 : }
    1369              : 
    1370              : void
    1371         5097 : TokenCollector::visit (FieldAccessExpr &expr)
    1372              : {
    1373         5097 :   describe_node (std::string ("FieldAccessExpr"), [this, &expr] () {
    1374         5097 :     visit (expr.get_receiver_expr ());
    1375         5097 :     push (Rust::Token::make (DOT, expr.get_locus ()));
    1376        10194 :     auto field_name = expr.get_field_name ().as_string ();
    1377         5097 :     push (
    1378        10194 :       Rust::Token::make_identifier (UNDEF_LOCATION, std::move (field_name)));
    1379         5097 :   });
    1380         5097 : }
    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        22988 : TokenCollector::visit (BlockExpr &expr)
    1421              : {
    1422        22988 :   describe_node (std::string ("BlockExpr"), [this, &expr] () {
    1423        22988 :     visit_items_as_lines (expr.get_outer_attrs ());
    1424        22988 :     push (Rust::Token::make (LEFT_CURLY, expr.get_locus ()));
    1425        22988 :     newline ();
    1426        22988 :     increment_indentation ();
    1427        22988 :     visit_items_as_lines (expr.get_inner_attrs ());
    1428              : 
    1429        22988 :     visit_items_as_lines (expr.get_statements (), {});
    1430              : 
    1431        22988 :     if (expr.has_tail_expr ())
    1432              :       {
    1433        16222 :         indentation ();
    1434        16222 :         visit (expr.get_tail_expr ());
    1435        16222 :         newline ();
    1436              :       }
    1437              : 
    1438        22988 :     decrement_indentation ();
    1439        22988 :     indentation ();
    1440        22988 :     push (Rust::Token::make (RIGHT_CURLY, expr.get_locus ()));
    1441        22988 :     newline ();
    1442        22988 :   });
    1443        22988 : }
    1444              : 
    1445              : void
    1446          857 : TokenCollector::visit (AnonConst &expr)
    1447              : {
    1448          857 :   if (!expr.is_deferred ())
    1449              :     {
    1450          837 :       visit (expr.get_inner_expr ());
    1451          837 :       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          106 : TokenCollector::visit (BreakExpr &expr)
    1491              : {
    1492          106 :   describe_node (std::string ("BreakExpr"), [this, &expr] () {
    1493          106 :     push (Rust::Token::make (BREAK, expr.get_locus ()));
    1494          106 :     if (expr.has_label ())
    1495           33 :       visit (expr.get_label_unchecked ());
    1496          106 :     if (expr.has_break_expr ())
    1497           21 :       visit (expr.get_break_expr_unchecked ());
    1498          106 :   });
    1499          106 : }
    1500              : 
    1501              : void
    1502           66 : TokenCollector::visit (RangeFromToExpr &expr)
    1503              : {
    1504           66 :   describe_node (std::string ("RangeFromToExpr"), [this, &expr] () {
    1505           66 :     visit (expr.get_from_expr ());
    1506           66 :     push (Rust::Token::make (DOT_DOT, expr.get_locus ()));
    1507           66 :     visit (expr.get_to_expr ());
    1508           66 :   });
    1509           66 : }
    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          546 : TokenCollector::visit (ReturnExpr &expr)
    1567              : {
    1568          546 :   describe_node (std::string ("ReturnExpr"), [this, &expr] () {
    1569          546 :     push (Rust::Token::make (RETURN_KW, expr.get_locus ()));
    1570          546 :     if (expr.has_returned_expr ())
    1571          509 :       visit (expr.get_returned_expr ());
    1572          546 :   });
    1573          546 : }
    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         3671 : TokenCollector::visit (UnsafeBlockExpr &expr)
    1584              : {
    1585         3671 :   describe_node (std::string ("UnsafeBlockExpr"), [this, &expr] () {
    1586         3671 :     push (Rust::Token::make (UNSAFE, expr.get_locus ()));
    1587         3671 :     visit (expr.get_block_expr ());
    1588         3671 :   });
    1589         3671 : }
    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          222 : TokenCollector::visit_loop_common (BaseLoopExpr &expr)
    1602              : {
    1603          222 :   describe_node (std::string ("BaseLoopExpr"), [this, &expr] () {
    1604          222 :     if (expr.has_loop_label ())
    1605           51 :       visit (expr.get_loop_label ());
    1606          222 :   });
    1607          222 : }
    1608              : 
    1609              : void
    1610          140 : TokenCollector::visit (LoopExpr &expr)
    1611              : {
    1612          140 :   describe_node (std::string ("LoopExpr"), [this, &expr] () {
    1613          140 :     visit_loop_common (expr);
    1614          140 :     push (Rust::Token::make (LOOP, expr.get_locus ()));
    1615          140 :     visit (expr.get_loop_block ());
    1616          140 :   });
    1617          140 : }
    1618              : 
    1619              : void
    1620           82 : TokenCollector::visit (WhileLoopExpr &expr)
    1621              : {
    1622           82 :   describe_node (std::string ("WhileLoopExpr"), [this, &expr] () {
    1623           82 :     visit_loop_common (expr);
    1624           82 :     push (Rust::Token::make (WHILE, expr.get_locus ()));
    1625           82 :     visit (expr.get_predicate_expr ());
    1626           82 :     visit (expr.get_loop_block ());
    1627           82 :   });
    1628           82 : }
    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         2681 : TokenCollector::visit (IfExpr &expr)
    1659              : {
    1660         2681 :   describe_node (std::string ("IfExpr"), [this, &expr] () {
    1661         2681 :     push (Rust::Token::make (IF, expr.get_locus ()));
    1662              : 
    1663         2681 :     visit (expr.get_condition_expr ());
    1664         2681 :     visit (expr.get_if_block ());
    1665         2681 :   });
    1666         2681 : }
    1667              : 
    1668              : void
    1669         1259 : TokenCollector::visit (IfExprConseqElse &expr)
    1670              : {
    1671         1259 :   describe_node (std::string ("IfExprConseqElse"), [this, &expr] () {
    1672         1259 :     visit (static_cast<IfExpr &> (expr));
    1673         1259 :     indentation ();
    1674         1259 :     push (Rust::Token::make (ELSE, expr.get_locus ()));
    1675         1259 :     visit (expr.get_else_block ());
    1676         1259 :   });
    1677         1259 : }
    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         2419 : TokenCollector::visit (MatchArm &arm)
    1705              : {
    1706         2419 :   describe_node (std::string ("MatchArm"), [this, &arm] () {
    1707         2419 :     visit_items_as_lines (arm.get_outer_attrs ());
    1708         2419 :     visit (arm.get_pattern ());
    1709         2419 :     if (arm.has_match_arm_guard ())
    1710              :       {
    1711            1 :         push (Rust::Token::make (IF, UNDEF_LOCATION));
    1712            1 :         visit (arm.get_guard_expr ());
    1713              :       }
    1714         2419 :   });
    1715         2419 : }
    1716              : 
    1717              : void
    1718         2419 : TokenCollector::visit (MatchCase &match_case)
    1719              : {
    1720         2419 :   describe_node (std::string ("MatchCase"), [this, &match_case] () {
    1721         2419 :     indentation ();
    1722         2419 :     visit (match_case.get_arm ());
    1723         2419 :     push (Rust::Token::make (MATCH_ARROW, UNDEF_LOCATION));
    1724         2419 :     visit (match_case.get_expr ());
    1725         2419 :     indentation ();
    1726         2419 :     push (Rust::Token::make (COMMA, UNDEF_LOCATION));
    1727         2419 :     newline ();
    1728         2419 :   });
    1729         2419 : }
    1730              : 
    1731              : void
    1732         1046 : TokenCollector::visit (MatchExpr &expr)
    1733              : {
    1734         1046 :   describe_node (std::string ("MatchExpr"), [this, &expr] () {
    1735         1046 :     push (Rust::Token::make (MATCH_KW, expr.get_locus ()));
    1736         1046 :     visit (expr.get_scrutinee_expr ());
    1737         1046 :     push (Rust::Token::make (LEFT_CURLY, UNDEF_LOCATION));
    1738         1046 :     newline ();
    1739         1046 :     increment_indentation ();
    1740         1046 :     visit_items_as_lines (expr.get_inner_attrs ());
    1741         3465 :     for (auto &arm : expr.get_match_cases ())
    1742              :       {
    1743         2419 :         visit (arm);
    1744              :       }
    1745         1046 :     decrement_indentation ();
    1746         1046 :     indentation ();
    1747         1046 :     push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
    1748         1046 :   });
    1749         1046 : }
    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         4501 : TokenCollector::visit (TypeParam &param)
    1940              : {
    1941              :   // Syntax:
    1942              :   //    IDENTIFIER( : TypeParamBounds? )? ( = Type )?
    1943              :   // TypeParamBounds :
    1944              :   //    TypeParamBound ( + TypeParamBound )* +?
    1945         4501 :   describe_node (std::string ("TypeParam"), [this, &param] () {
    1946         4501 :     visit_items_as_lines (param.get_outer_attrs ());
    1947         9002 :     auto id = param.get_type_representation ().as_string ();
    1948         9002 :     push (Rust::Token::make_identifier (param.get_locus (), std::move (id)));
    1949         4501 :     if (param.has_type_param_bounds ())
    1950              :       {
    1951          802 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
    1952          802 :         visit_items_joined_by_separator (param.get_type_param_bounds (), PLUS);
    1953              :       }
    1954         4501 :     if (param.has_type ())
    1955              :       {
    1956          348 :         push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    1957          348 :         visit (param.get_type ());
    1958              :       }
    1959         4501 :   });
    1960         4501 : }
    1961              : 
    1962              : void
    1963          290 : TokenCollector::visit (WhereClause &rule)
    1964              : {
    1965              :   // Syntax:
    1966              :   //    where ( WhereClauseItem , )* WhereClauseItem ?
    1967              :   // WhereClauseItem :
    1968              :   //    LifetimeWhereClauseItem
    1969              :   //    | TypeBoundWhereClauseItem
    1970          290 :   describe_node (std::string ("WhereClause"), [this, &rule] () {
    1971          290 :     push (Rust::Token::make (WHERE, UNDEF_LOCATION));
    1972          290 :     newline ();
    1973          290 :     increment_indentation ();
    1974          290 :     visit_items_joined_by_separator (rule.get_items (), COMMA);
    1975          290 :     decrement_indentation ();
    1976          290 :   });
    1977          290 : }
    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          310 : TokenCollector::visit (TypeBoundWhereClauseItem &item)
    1996              : {
    1997              :   // Syntax:
    1998              :   //    ForLifetimes? Type : TypeParamBounds?
    1999              :   // TypeParamBounds :
    2000              :   //    TypeParamBound ( + TypeParamBound )* +?
    2001              :   // TypeParamBound :
    2002              :   //    Lifetime | TraitBound
    2003              : 
    2004          310 :   describe_node (std::string ("TypeBoundWhereClauseItem"), [this, &item] () {
    2005          310 :     if (item.has_for_lifetimes ())
    2006            7 :       visit (item.get_for_lifetimes ());
    2007              : 
    2008          310 :     visit (item.get_type ());
    2009              : 
    2010          310 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    2011          310 :     visit_items_joined_by_separator (item.get_type_param_bounds (), PLUS);
    2012          310 :   });
    2013          310 : }
    2014              : 
    2015              : void
    2016         1145 : TokenCollector::visit (Module &module)
    2017              : {
    2018              :   //  Syntax:
    2019              :   //    mod IDENTIFIER ;
    2020              :   //     | mod IDENTIFIER {
    2021              :   //      InnerAttribute*
    2022              :   //      Item*
    2023              :   //    }
    2024         1145 :   describe_node (std::string ("Module"), [this, &module] () {
    2025         1145 :     visit_items_as_lines (module.get_outer_attrs ());
    2026         1145 :     visit (module.get_visibility ());
    2027         2290 :     auto name = module.get_name ().as_string ();
    2028         1145 :     push (Rust::Token::make (MOD, module.get_locus ()));
    2029         2290 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (name)));
    2030              : 
    2031         1145 :     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         1145 :         push (Rust::Token::make (LEFT_CURLY, UNDEF_LOCATION));
    2039         1145 :         newline ();
    2040         1145 :         increment_indentation ();
    2041              : 
    2042         1145 :         visit_items_as_lines (module.get_inner_attrs ());
    2043         1145 :         visit_items_as_lines (module.get_items ());
    2044              : 
    2045         1145 :         decrement_indentation ();
    2046              : 
    2047         1145 :         push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
    2048         1145 :         newline ();
    2049              :       }
    2050         1145 :   });
    2051         1145 : }
    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           17 : TokenCollector::visit (UseTreeGlob &use_tree)
    2076              : {
    2077           17 :   describe_node (std::string ("UseTreeGlob"), [this, &use_tree] () {
    2078           17 :     switch (use_tree.get_glob_type ())
    2079              :       {
    2080           14 :       case UseTreeGlob::PathType::PATH_PREFIXED:
    2081           14 :         {
    2082           14 :           auto path = use_tree.get_path ();
    2083           14 :           visit (path);
    2084           28 :           push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
    2085           14 :         }
    2086           14 :         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           17 :     push (Rust::Token::make (ASTERISK, UNDEF_LOCATION));
    2094           17 :   });
    2095           17 : }
    2096              : 
    2097              : void
    2098          156 : TokenCollector::visit (UseTreeList &use_tree)
    2099              : {
    2100          156 :   describe_node (std::string ("UseTreeList"), [this, &use_tree] () {
    2101          156 :     switch (use_tree.get_path_type ())
    2102              :       {
    2103          156 :       case UseTreeList::PathType::PATH_PREFIXED:
    2104          156 :         {
    2105          156 :           auto path = use_tree.get_path ();
    2106          156 :           visit (path);
    2107              : 
    2108          312 :           push (Rust::Token::make (SCOPE_RESOLUTION, UNDEF_LOCATION));
    2109          156 :         }
    2110          156 :         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          156 :     push (Rust::Token::make (LEFT_CURLY, UNDEF_LOCATION));
    2119          156 :     if (use_tree.has_trees ())
    2120              :       {
    2121          156 :         visit_items_joined_by_separator (use_tree.get_trees (), COMMA);
    2122              :       }
    2123          156 :     push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
    2124          156 :   });
    2125          156 : }
    2126              : 
    2127              : void
    2128         1073 : TokenCollector::visit (UseTreeRebind &use_tree)
    2129              : {
    2130         1073 :   describe_node (std::string ("UseTreeRebind"), [this, &use_tree] () {
    2131         1073 :     auto path = use_tree.get_path ();
    2132         1073 :     visit (path);
    2133         1073 :     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         1073 :   });
    2151         1073 : }
    2152              : 
    2153              : void
    2154          659 : TokenCollector::visit (UseDeclaration &decl)
    2155              : {
    2156          659 :   describe_node (std::string ("UseDeclaration"), [this, &decl] () {
    2157          659 :     visit_items_as_lines (decl.get_outer_attrs ());
    2158          659 :     push (Rust::Token::make (USE, decl.get_locus ()));
    2159          659 :     visit (*decl.get_tree ());
    2160          659 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2161          659 :     newline ();
    2162          659 :   });
    2163          659 : }
    2164              : 
    2165              : void
    2166        18177 : TokenCollector::visit (Function &function)
    2167              : {
    2168              :   // Syntax:
    2169              :   //   FunctionQualifiers fn IDENTIFIER GenericParams?
    2170              :   //      ( FunctionParameters? )
    2171              :   //      FunctionReturnType? WhereClause?
    2172              :   //      ( BlockExpression | ; )
    2173        18177 :   describe_node (std::string ("Function"), [this, &function] () {
    2174        18177 :     visit_items_as_lines (function.get_outer_attrs ());
    2175              : 
    2176        18177 :     visit (function.get_visibility ());
    2177        18177 :     auto qualifiers = function.get_qualifiers ();
    2178        18177 :     visit (qualifiers);
    2179              : 
    2180        18177 :     push (Rust::Token::make (FN_KW, function.get_locus ()));
    2181        36354 :     auto name = function.get_function_name ().as_string ();
    2182        36354 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (name)));
    2183        18177 :     if (function.has_generics ())
    2184         1650 :       visit (function.get_generic_params ());
    2185              : 
    2186        18177 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2187              : 
    2188        18177 :     visit_items_joined_by_separator (function.get_function_params ());
    2189        18177 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2190              : 
    2191        18177 :     if (function.has_return_type ())
    2192              :       {
    2193        13021 :         push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
    2194        13021 :         visit (function.get_return_type ());
    2195              :       }
    2196              : 
    2197        18177 :     if (function.has_where_clause ())
    2198          205 :       visit (function.get_where_clause ());
    2199              : 
    2200        18177 :     if (function.has_body ())
    2201        13993 :       visit (*function.get_definition ());
    2202              :     else
    2203         8368 :       push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2204        18177 :     newline ();
    2205        18177 :   });
    2206        18177 : }
    2207              : 
    2208              : void
    2209         1238 : 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         1238 :   describe_node (std::string ("TypeAlias"), [this, &type_alias] () {
    2216         1238 :     visit_items_as_lines (type_alias.get_outer_attrs ());
    2217         1238 :     if (type_alias.has_visibility ())
    2218           16 :       visit (type_alias.get_visibility ());
    2219         2476 :     auto alias_name = type_alias.get_new_type_name ().as_string ();
    2220         1238 :     push (Rust::Token::make (TYPE, type_alias.get_locus ()));
    2221         1238 :     push (
    2222         2476 :       Rust::Token::make_identifier (UNDEF_LOCATION, std::move (alias_name)));
    2223              : 
    2224         1238 :     if (type_alias.has_generics ())
    2225           22 :       visit (type_alias.get_generic_params ());
    2226              : 
    2227         1238 :     if (type_alias.has_where_clause ())
    2228            0 :       visit (type_alias.get_where_clause ());
    2229              : 
    2230         1238 :     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    2231         1238 :     visit (type_alias.get_type_aliased ());
    2232         2476 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2233         1238 :   });
    2234         1238 : }
    2235              : 
    2236              : void
    2237         1530 : TokenCollector::visit (StructStruct &struct_item)
    2238              : {
    2239         1530 :   describe_node (std::string ("StructStruct"), [this, &struct_item] () {
    2240         1530 :     visit_items_as_lines (struct_item.get_outer_attrs ());
    2241         1530 :     if (struct_item.has_visibility ())
    2242          354 :       visit (struct_item.get_visibility ());
    2243         3060 :     auto struct_name = struct_item.get_identifier ().as_string ();
    2244         1530 :     push (Rust::Token::make (STRUCT_KW, struct_item.get_locus ()));
    2245         1530 :     push (
    2246         3060 :       Rust::Token::make_identifier (UNDEF_LOCATION, std::move (struct_name)));
    2247              : 
    2248         1530 :     if (struct_item.has_generics ())
    2249          488 :       visit (struct_item.get_generic_params ());
    2250         1530 :     if (struct_item.has_where_clause ())
    2251            2 :       visit (struct_item.get_where_clause ());
    2252         1530 :     if (struct_item.is_unit_struct ())
    2253              :       {
    2254          543 :         push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2255          543 :         newline ();
    2256              :       }
    2257              :     else
    2258         1974 :       visit_items_as_block (struct_item.get_fields (),
    2259              :                             {Rust::Token::make (COMMA, UNDEF_LOCATION)});
    2260         1530 :   });
    2261         1530 : }
    2262              : 
    2263              : void
    2264          939 : TokenCollector::visit (TupleStruct &tuple_struct)
    2265              : {
    2266          939 :   describe_node (std::string ("TupleStruct"), [this, &tuple_struct] () {
    2267          939 :     visit_items_as_lines (tuple_struct.get_outer_attrs ());
    2268         1878 :     auto struct_name = tuple_struct.get_identifier ().as_string ();
    2269          939 :     push (Rust::Token::make (STRUCT_KW, tuple_struct.get_locus ()));
    2270          939 :     push (
    2271         1878 :       Rust::Token::make_identifier (UNDEF_LOCATION, std::move (struct_name)));
    2272          939 :     if (tuple_struct.has_generics ())
    2273          287 :       visit (tuple_struct.get_generic_params ());
    2274          939 :     if (tuple_struct.has_where_clause ())
    2275            0 :       visit (tuple_struct.get_where_clause ());
    2276              : 
    2277          939 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2278          939 :     visit_items_joined_by_separator (tuple_struct.get_fields (), COMMA);
    2279          939 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2280          939 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2281          939 :     newline ();
    2282          939 :   });
    2283          939 : }
    2284              : 
    2285              : void
    2286          423 : TokenCollector::visit (EnumItem &item)
    2287              : {
    2288          423 :   describe_node (std::string ("EnumItem"), [this, &item] () {
    2289          423 :     visit_items_as_lines (item.get_outer_attrs ());
    2290          846 :     auto id = item.get_identifier ().as_string ();
    2291          846 :     push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
    2292          423 :   });
    2293          423 : }
    2294              : 
    2295              : void
    2296          391 : TokenCollector::visit (EnumItemTuple &item)
    2297              : {
    2298          391 :   describe_node (std::string ("EnumItemTuple"), [this, &item] () {
    2299          782 :     auto id = item.get_identifier ().as_string ();
    2300          782 :     push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
    2301          391 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2302          391 :     visit_items_joined_by_separator (item.get_tuple_fields (), COMMA);
    2303          782 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2304          391 :   });
    2305          391 : }
    2306              : 
    2307              : void
    2308           79 : TokenCollector::visit (EnumItemStruct &item)
    2309              : {
    2310           79 :   describe_node (std::string ("EnumItemStruct"), [this, &item] () {
    2311          158 :     auto id = item.get_identifier ().as_string ();
    2312          158 :     push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
    2313          158 :     visit_items_as_block (item.get_struct_fields (),
    2314              :                           {Rust::Token::make (COMMA, UNDEF_LOCATION)});
    2315           79 :   });
    2316           79 : }
    2317              : 
    2318              : void
    2319          276 : TokenCollector::visit (EnumItemDiscriminant &item)
    2320              : {
    2321          276 :   describe_node (std::string ("EnumItemDiscriminant"), [this, &item] () {
    2322          552 :     auto id = item.get_identifier ().as_string ();
    2323          552 :     push (Rust::Token::make_identifier (item.get_locus (), std::move (id)));
    2324          276 :     push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    2325          276 :     visit (item.get_expr ());
    2326          276 :   });
    2327          276 : }
    2328              : 
    2329              : void
    2330          499 : TokenCollector::visit (Enum &enumeration)
    2331              : {
    2332          499 :   describe_node (std::string ("Enum"), [this, &enumeration] () {
    2333          499 :     visit_items_as_lines (enumeration.get_outer_attrs ());
    2334          499 :     if (enumeration.has_visibility ())
    2335          267 :       visit (enumeration.get_visibility ());
    2336          998 :     push (Rust::Token::make (ENUM_KW, enumeration.get_locus ()));
    2337          998 :     auto id = enumeration.get_identifier ().as_string ();
    2338          499 :     push (
    2339          998 :       Rust::Token::make_identifier (enumeration.get_locus (), std::move (id)));
    2340          499 :     if (enumeration.has_generics ())
    2341          226 :       visit (enumeration.get_generic_params ());
    2342          499 :     if (enumeration.has_where_clause ())
    2343            0 :       visit (enumeration.get_where_clause ());
    2344              : 
    2345          998 :     visit_items_as_block (enumeration.get_variants (),
    2346              :                           {Rust::Token::make (COMMA, UNDEF_LOCATION)});
    2347          499 :   });
    2348          499 : }
    2349              : 
    2350              : void
    2351          101 : TokenCollector::visit (Union &union_item)
    2352              : {
    2353          101 :   describe_node (std::string ("Union"), [this, &union_item] () {
    2354          101 :     visit_items_as_lines (union_item.get_outer_attrs ());
    2355          202 :     auto id = union_item.get_identifier ().as_string ();
    2356          202 :     push (Rust::Token::make_identifier (union_item.get_locus (),
    2357          101 :                                         Values::WeakKeywords::UNION));
    2358          202 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2359              : 
    2360          101 :     if (union_item.has_generics ())
    2361           74 :       visit (union_item.get_generic_params ());
    2362              : 
    2363          101 :     if (union_item.has_where_clause ())
    2364            0 :       visit (union_item.get_where_clause ());
    2365              : 
    2366          202 :     visit_items_as_block (union_item.get_variants (),
    2367              :                           {Rust::Token::make (COMMA, UNDEF_LOCATION)});
    2368          101 :   });
    2369          101 : }
    2370              : 
    2371              : void
    2372          542 : TokenCollector::visit (ConstantItem &item)
    2373              : {
    2374          542 :   describe_node (std::string ("ConstantItem"), [this, &item] () {
    2375          542 :     visit_items_as_lines (item.get_outer_attrs ());
    2376          542 :     push (Rust::Token::make (CONST, item.get_locus ()));
    2377          542 :     if (item.is_unnamed ())
    2378              :       {
    2379           10 :         push (Rust::Token::make (UNDERSCORE, UNDEF_LOCATION));
    2380              :       }
    2381              :     else
    2382              :       {
    2383         1074 :         push (Rust::Token::make_identifier (item.get_identifier ()));
    2384              :       }
    2385          542 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    2386          542 :     visit (item.get_type ());
    2387          542 :     if (item.has_expr ())
    2388              :       {
    2389          519 :         push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    2390          519 :         visit (item.get_expr ());
    2391              :       }
    2392          542 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2393          542 :   });
    2394          542 : }
    2395              : 
    2396              : void
    2397           52 : TokenCollector::visit (StaticItem &item)
    2398              : {
    2399           52 :   describe_node (std::string ("StaticItem"), [this, &item] () {
    2400           52 :     visit_items_as_lines (item.get_outer_attrs ());
    2401           52 :     push (Rust::Token::make (STATIC_KW, item.get_locus ()));
    2402           52 :     if (item.is_mutable ())
    2403            6 :       push (Rust::Token::make (MUT, UNDEF_LOCATION));
    2404              : 
    2405          104 :     auto id = item.get_identifier ().as_string ();
    2406          104 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2407           52 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    2408              : 
    2409           52 :     visit (item.get_type ());
    2410              : 
    2411           52 :     if (item.has_expr ())
    2412              :       {
    2413           52 :         push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    2414           52 :         visit (item.get_expr ());
    2415              :       }
    2416          104 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2417           52 :   });
    2418           52 : }
    2419              : 
    2420              : void
    2421            0 : TokenCollector::visit_function_common (std::unique_ptr<Type> &return_type,
    2422              :                                        std::unique_ptr<BlockExpr> &block)
    2423              : {
    2424              :   // FIXME: This should format the `<vis> fn <name> ( [args] )` as well
    2425            0 :   if (return_type)
    2426              :     {
    2427            0 :       push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
    2428            0 :       visit (return_type);
    2429              :     }
    2430              : 
    2431            0 :   if (block)
    2432              :     {
    2433            0 :       visit (block);
    2434              :     }
    2435              :   else
    2436              :     {
    2437            0 :       push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2438            0 :       newline ();
    2439              :     }
    2440            0 : }
    2441              : 
    2442              : void
    2443         7912 : TokenCollector::visit (SelfParam &param)
    2444              : {
    2445         7912 :   describe_node (std::string ("SelfParam"), [this, &param] () {
    2446         7912 :     if (param.get_has_ref ())
    2447              :       {
    2448         4839 :         push (Rust::Token::make (AMP, UNDEF_LOCATION));
    2449         4839 :         if (param.has_lifetime ())
    2450              :           {
    2451         4584 :             auto lifetime = param.get_lifetime ();
    2452         4584 :             visit (lifetime);
    2453         4584 :           }
    2454         4839 :         if (param.get_is_mut ())
    2455          782 :           push (Rust::Token::make (MUT, UNDEF_LOCATION));
    2456              :       }
    2457         7912 :     push (Rust::Token::make (SELF, UNDEF_LOCATION));
    2458         7912 :     if (param.has_type ())
    2459              :       {
    2460            3 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
    2461            3 :         visit (param.get_type ());
    2462              :       }
    2463         7912 :   });
    2464         7912 : }
    2465              : 
    2466              : void
    2467          712 : TokenCollector::visit (TraitItemType &item)
    2468              : {
    2469          712 :   describe_node (std::string ("TraitItemType"), [this, &item] () {
    2470          712 :     visit_items_as_lines (item.get_outer_attrs ());
    2471         1424 :     auto id = item.get_identifier ().as_string ();
    2472          712 :     indentation ();
    2473              : 
    2474          712 :     push (Rust::Token::make (TYPE, item.get_locus ()));
    2475         1424 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2476          712 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2477          712 :     newline ();
    2478          712 :   });
    2479          712 : }
    2480              : 
    2481              : void
    2482         3765 : TokenCollector::visit (Trait &trait)
    2483              : {
    2484         3765 :   describe_node (std::string ("Trait"), [this, &trait] () {
    2485         7583 :     for (auto &attr : trait.get_outer_attrs ())
    2486              :       {
    2487         3818 :         visit (attr);
    2488         3818 :         newline ();
    2489         3818 :         indentation ();
    2490              :       }
    2491              : 
    2492         3765 :     visit (trait.get_visibility ());
    2493              : 
    2494         7530 :     auto id = trait.get_identifier ().as_string ();
    2495         3765 :     push (Rust::Token::make (TRAIT, trait.get_locus ()));
    2496         7530 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2497              : 
    2498         3765 :     if (trait.has_generics ())
    2499          610 :       visit (trait.get_generic_params ());
    2500         3765 :     if (!trait.get_type_param_bounds ().empty ())
    2501         1014 :       push (Rust::Token::make ((COLON), trait.get_locus ()));
    2502         3765 :     visit_items_joined_by_separator (trait.get_type_param_bounds (), PLUS);
    2503              : 
    2504         3765 :     visit_items_as_block (trait.get_trait_items (), {});
    2505         3765 :   });
    2506         3765 : }
    2507              : 
    2508              : void
    2509          946 : TokenCollector::visit (InherentImpl &impl)
    2510              : {
    2511          946 :   describe_node (std::string ("InherentImpl"), [this, &impl] () {
    2512          946 :     visit_items_as_lines (impl.get_outer_attrs ());
    2513          946 :     push (Rust::Token::make (IMPL, impl.get_locus ()));
    2514          946 :     visit (impl.get_generic_params ());
    2515              : 
    2516          946 :     visit (impl.get_type ());
    2517              : 
    2518          946 :     if (impl.has_where_clause ())
    2519            0 :       visit (impl.get_where_clause ());
    2520              : 
    2521              :     // FIXME: Handle inner attributes
    2522              : 
    2523          946 :     visit_items_as_block (impl.get_impl_items (), {});
    2524          946 :   });
    2525          946 : }
    2526              : 
    2527              : void
    2528         4508 : TokenCollector::visit (TraitImpl &impl)
    2529              : {
    2530         4508 :   describe_node (std::string ("TraitImpl"), [this, &impl] () {
    2531         4508 :     visit_items_as_lines (impl.get_outer_attrs ());
    2532         4508 :     push (Rust::Token::make (IMPL, impl.get_locus ()));
    2533         4508 :     visit (impl.get_generic_params ());
    2534         4508 :     if (impl.is_exclam ())
    2535           12 :       push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
    2536         4508 :     visit (impl.get_trait_path ());
    2537         4508 :     push (Rust::Token::make (FOR, UNDEF_LOCATION));
    2538         4508 :     visit (impl.get_type ());
    2539              : 
    2540         4508 :     if (impl.has_where_clause ())
    2541           83 :       visit (impl.get_where_clause ());
    2542         4508 :   });
    2543         4508 :   visit_items_as_block (impl.get_impl_items ());
    2544         4508 : }
    2545              : 
    2546              : void
    2547            0 : TokenCollector::visit (ExternalTypeItem &type)
    2548              : {
    2549            0 :   describe_node (std::string ("ExternalTypeItem"), [this, &type] () {
    2550            0 :     visit (type.get_visibility ());
    2551              : 
    2552            0 :     auto id = type.get_identifier ().as_string ();
    2553              : 
    2554            0 :     push (Rust::Token::make (TYPE, UNDEF_LOCATION));
    2555            0 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2556            0 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2557            0 :   });
    2558            0 : }
    2559              : 
    2560              : void
    2561            0 : TokenCollector::visit (ExternalStaticItem &item)
    2562              : {
    2563            0 :   describe_node (std::string ("ExternalStaticItem"), [this, &item] () {
    2564            0 :     auto id = item.get_identifier ().as_string ();
    2565            0 :     visit_items_as_lines (item.get_outer_attrs ());
    2566            0 :     if (item.has_visibility ())
    2567            0 :       visit (item.get_visibility ());
    2568            0 :     push (Rust::Token::make (STATIC_KW, item.get_locus ()));
    2569            0 :     if (item.is_mut ())
    2570            0 :       push (Rust::Token::make (MUT, UNDEF_LOCATION));
    2571            0 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2572            0 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    2573            0 :     visit (item.get_type ());
    2574              :     // TODO: No expr ? The "(= Expression)?" part from the reference seems
    2575              :     // missing in the ast.
    2576            0 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2577            0 :   });
    2578            0 : }
    2579              : 
    2580              : void
    2581         1639 : TokenCollector::visit (ExternBlock &block)
    2582              : {
    2583         1639 :   describe_node (std::string ("ExternBlock"), [this, &block] () {
    2584         1639 :     visit_items_as_lines (block.get_outer_attrs ());
    2585         1639 :     push (Rust::Token::make (EXTERN_KW, block.get_locus ()));
    2586              : 
    2587         1639 :     if (block.has_abi ())
    2588              :       {
    2589         1638 :         auto abi = block.get_abi ();
    2590         3276 :         push (Rust::Token::make_string (UNDEF_LOCATION, std::move (abi)));
    2591         1638 :       }
    2592              : 
    2593         1639 :     visit_items_as_block (block.get_extern_items (), {});
    2594         1639 :   });
    2595         1639 : }
    2596              : 
    2597              : static std::pair<TokenId, TokenId>
    2598         1091 : get_delimiters (DelimType delim)
    2599              : {
    2600         1091 :   switch (delim)
    2601              :     {
    2602         1041 :     case PARENS:
    2603         1041 :       return {LEFT_PAREN, RIGHT_PAREN};
    2604           36 :     case SQUARE:
    2605           36 :       return {LEFT_SQUARE, RIGHT_SQUARE};
    2606           14 :     case CURLY:
    2607           14 :       return {LEFT_CURLY, RIGHT_CURLY};
    2608            0 :     default:
    2609            0 :       rust_unreachable ();
    2610              :     }
    2611              : }
    2612              : 
    2613              : void
    2614          890 : TokenCollector::visit (MacroMatchFragment &match)
    2615              : {
    2616          890 :   describe_node (std::string ("MacroMatchFragment"), [this, &match] () {
    2617         1780 :     auto id = match.get_ident ().as_string ();
    2618          890 :     auto frag_spec = match.get_frag_spec ().as_string ();
    2619          890 :     push (Rust::Token::make (DOLLAR_SIGN, UNDEF_LOCATION));
    2620         1780 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2621          890 :     push (Rust::Token::make (COLON, UNDEF_LOCATION));
    2622         1780 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (frag_spec)));
    2623          890 :   });
    2624          890 : }
    2625              : 
    2626              : void
    2627          472 : TokenCollector::visit (MacroMatchRepetition &repetition)
    2628              : {
    2629          472 :   describe_node (std::string ("MacroMatchRepetition"), [this, &repetition] () {
    2630          472 :     push (Rust::Token::make (DOLLAR_SIGN, UNDEF_LOCATION));
    2631          472 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2632              : 
    2633         1042 :     for (auto &match : repetition.get_matches ())
    2634              :       {
    2635          570 :         visit (match);
    2636              :       }
    2637              : 
    2638          472 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2639              : 
    2640          472 :     if (repetition.has_sep ())
    2641              :       {
    2642          248 :         push (Rust::Token::make (repetition.get_sep ()->get_id (),
    2643          124 :                                  repetition.get_sep ()->get_locus ()));
    2644              :       }
    2645          472 :     switch (repetition.get_op ())
    2646              :       {
    2647          406 :       case MacroMatchRepetition::ANY:
    2648          406 :         push (Rust::Token::make (ASTERISK, UNDEF_LOCATION));
    2649          406 :         break;
    2650           33 :       case MacroMatchRepetition::ONE_OR_MORE:
    2651           33 :         push (Rust::Token::make (PLUS, UNDEF_LOCATION));
    2652           33 :         break;
    2653           33 :       case MacroMatchRepetition::ZERO_OR_ONE:
    2654           33 :         push (Rust::Token::make (QUESTION_MARK, UNDEF_LOCATION));
    2655           33 :         break;
    2656              :       case MacroMatchRepetition::NONE:
    2657              :         break;
    2658              :       }
    2659          472 :   });
    2660          472 : }
    2661              : 
    2662              : void
    2663         1091 : TokenCollector::visit (MacroMatcher &matcher)
    2664              : {
    2665         1091 :   describe_node (std::string ("MacroMatcher"), [this, &matcher] () {
    2666         1091 :     auto delimiters = get_delimiters (matcher.get_delim_type ());
    2667              : 
    2668         1091 :     push (Rust::Token::make (delimiters.first, UNDEF_LOCATION));
    2669              : 
    2670         2408 :     for (auto &item : matcher.get_matches ())
    2671              :       {
    2672         1317 :         visit (item);
    2673              :       }
    2674              : 
    2675         1091 :     push (Rust::Token::make (delimiters.second, UNDEF_LOCATION));
    2676         1091 :   });
    2677         1091 : }
    2678              : 
    2679              : void
    2680         1031 : TokenCollector::visit (MacroRule &rule)
    2681              : {
    2682         1031 :   describe_node (std::string ("MacroRule"), [this, &rule] () {
    2683         1031 :     visit (rule.get_matcher ());
    2684         1031 :     push (Rust::Token::make (MATCH_ARROW, rule.get_locus ()));
    2685         1031 :     visit (rule.get_transcriber ().get_token_tree ());
    2686         1031 :   });
    2687         1031 : }
    2688              : 
    2689              : void
    2690          893 : TokenCollector::visit (MacroRulesDefinition &rules_def)
    2691              : {
    2692          893 :   describe_node (std::string ("MacroRulesDefinition"), [this, &rules_def] () {
    2693         1036 :     for (auto &outer_attr : rules_def.get_outer_attrs ())
    2694          143 :       visit (outer_attr);
    2695              : 
    2696         1786 :     auto rule_name = rules_def.get_rule_name ().as_string ();
    2697              : 
    2698         1786 :     push (Rust::Token::make_identifier (rules_def.get_locus (),
    2699          893 :                                         Values::WeakKeywords::MACRO_RULES));
    2700          893 :     push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
    2701              : 
    2702         1786 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (rule_name)));
    2703              : 
    2704         1786 :     visit_items_as_block (rules_def.get_rules (),
    2705              :                           {Rust::Token::make (SEMICOLON, UNDEF_LOCATION)});
    2706          893 :   });
    2707          893 : }
    2708              : 
    2709              : void
    2710          175 : TokenCollector::visit (MacroInvocation &invocation)
    2711              : {
    2712          175 :   describe_node (std::string ("MacroInvocation"), [this, &invocation] () {
    2713          175 :     auto data = invocation.get_invoc_data ();
    2714          175 :     visit (data.get_path ());
    2715          175 :     push (Rust::Token::make (EXCLAM, UNDEF_LOCATION));
    2716          175 :     visit (data.get_delim_tok_tree ());
    2717          175 :     if (invocation.has_semicolon ())
    2718          348 :       push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    2719          175 :   });
    2720          175 : }
    2721              : 
    2722              : void
    2723            0 : TokenCollector::visit (MetaItemPath &item)
    2724              : {
    2725            0 :   describe_node (std::string ("MetaItemPath"), [this, &item] () {
    2726            0 :     auto path = item.to_path_item ();
    2727            0 :     visit (path);
    2728            0 :   });
    2729            0 : }
    2730              : 
    2731              : void
    2732           14 : TokenCollector::visit (MetaItemSeq &item)
    2733              : {
    2734           14 :   describe_node (std::string ("MetaItemSeq"), [this, &item] () {
    2735           14 :     visit (item.get_path ());
    2736              :     // TODO: Double check this, there is probably a mistake.
    2737           14 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2738           14 :     visit_items_joined_by_separator (item.get_seq (), COMMA);
    2739           14 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2740           14 :   });
    2741           14 : }
    2742              : 
    2743              : void
    2744           42 : TokenCollector::visit (MetaWord &word)
    2745              : {
    2746           42 :   describe_node (std::string ("MetaWord"), [this, &word] () {
    2747           42 :     auto id = word.get_ident ().as_string ();
    2748              : 
    2749           84 :     push (Rust::Token::make_identifier (word.get_locus (), std::move (id)));
    2750           42 :   });
    2751           42 : }
    2752              : 
    2753              : void
    2754          318 : TokenCollector::visit (MetaNameValueStr &name)
    2755              : {
    2756          318 :   describe_node (std::string ("MetaNameValueStr"), [this, &name] () {
    2757          318 :     auto pair = name.get_name_value_pair ();
    2758          318 :     auto id = std::get<0> (pair).as_string ();
    2759          318 :     auto value = std::get<1> (pair);
    2760              : 
    2761          636 :     push (Rust::Token::make_identifier (name.get_locus (), std::move (id)));
    2762          318 :     push (Rust::Token::make (EQUAL, name.get_locus ()));
    2763          318 :     push (Rust::Token::make (DOUBLE_QUOTE, UNDEF_LOCATION));
    2764          636 :     push (Rust::Token::make_identifier (name.get_locus (), std::move (value)));
    2765          636 :     push (Rust::Token::make (DOUBLE_QUOTE, UNDEF_LOCATION));
    2766          318 :   });
    2767          318 : }
    2768              : 
    2769              : void
    2770            0 : TokenCollector::visit (MetaListPaths &list)
    2771              : {
    2772            0 :   describe_node (std::string ("MetaListPath"), [this, &list] () {
    2773            0 :     auto id = list.get_ident ().as_string ();
    2774              : 
    2775            0 :     push (Rust::Token::make_identifier (list.get_locus (), std::move (id)));
    2776            0 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2777              : 
    2778            0 :     visit_items_joined_by_separator (list.get_paths (), COMMA);
    2779              : 
    2780            0 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2781            0 :   });
    2782            0 : }
    2783              : 
    2784              : void
    2785            0 : TokenCollector::visit (MetaListNameValueStr &list)
    2786              : {
    2787            0 :   describe_node (std::string ("MetaListNameValueStr"), [this, &list] () {
    2788            0 :     auto id = list.get_ident ().as_string ();
    2789              : 
    2790            0 :     push (Rust::Token::make_identifier (list.get_locus (), std::move (id)));
    2791            0 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    2792              : 
    2793            0 :     visit_items_joined_by_separator (list.get_values (), COMMA);
    2794              : 
    2795            0 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    2796            0 :   });
    2797            0 : }
    2798              : 
    2799              : // rust-pattern.h
    2800              : void
    2801          415 : TokenCollector::visit (LiteralPattern &pattern)
    2802              : {
    2803          415 :   describe_node (std::string ("LiteralPattern"), [this, &pattern] () {
    2804          415 :     visit (pattern.get_literal (), pattern.get_locus ());
    2805          415 :   });
    2806          415 : }
    2807              : 
    2808              : void
    2809        24166 : TokenCollector::visit (IdentifierPattern &pattern)
    2810              : {
    2811        24166 :   describe_node (std::string ("IdentifierPattern"), [this, &pattern] () {
    2812        24166 :     if (pattern.get_is_ref ())
    2813              :       {
    2814            4 :         push (Rust::Token::make (REF, pattern.get_locus ()));
    2815              :       }
    2816        24166 :     if (pattern.get_is_mut ())
    2817              :       {
    2818         1858 :         push (Rust::Token::make (MUT, UNDEF_LOCATION));
    2819              :       }
    2820              : 
    2821        48332 :     auto id = pattern.get_ident ().as_string ();
    2822        48332 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2823              : 
    2824        24166 :     if (pattern.has_subpattern ())
    2825              :       {
    2826           20 :         push (Rust::Token::make (PATTERN_BIND, UNDEF_LOCATION));
    2827           20 :         visit (pattern.get_subpattern ());
    2828              :       }
    2829        24166 :   });
    2830        24166 : }
    2831              : 
    2832              : void
    2833         1099 : TokenCollector::visit (WildcardPattern &pattern)
    2834              : {
    2835         1099 :   describe_node (std::string ("WildcardPattern"), [this, &pattern] () {
    2836         1099 :     push (Rust::Token::make (UNDERSCORE, pattern.get_locus ()));
    2837         1099 :   });
    2838         1099 : }
    2839              : 
    2840              : void
    2841           44 : TokenCollector::visit (RestPattern &pattern)
    2842              : {
    2843           44 :   describe_node (std::string ("RestPattern"), [this, &pattern] () {
    2844           44 :     push (Rust::Token::make (DOT_DOT, pattern.get_locus ()));
    2845           44 :   });
    2846           44 : }
    2847              : 
    2848              : // void TokenCollector::visit(RangePatternBound& ){}
    2849              : 
    2850              : void
    2851           61 : TokenCollector::visit (RangePatternBoundLiteral &pattern)
    2852              : {
    2853           61 :   describe_node (std::string ("RangePatternBoundLiteral"), [this, &pattern] () {
    2854           61 :     if (pattern.get_has_minus ())
    2855              :       {
    2856           48 :         push (Rust::Token::make (MINUS, pattern.get_locus ()));
    2857              :       }
    2858           61 :     auto literal = pattern.get_literal ();
    2859           61 :     visit (literal);
    2860           61 :   });
    2861           61 : }
    2862              : 
    2863              : void
    2864           21 : TokenCollector::visit (RangePatternBoundPath &pattern)
    2865              : {
    2866           21 :   describe_node (std::string ("RangePatternBoundPath"),
    2867           42 :                  [this, &pattern] () { visit (pattern.get_path ()); });
    2868           21 : }
    2869              : 
    2870              : void
    2871            0 : TokenCollector::visit (RangePatternBoundQualPath &pattern)
    2872              : {
    2873            0 :   describe_node (std::string ("RangePatternBoundQualPath"),
    2874            0 :                  [this, &pattern] () {
    2875            0 :                    visit (pattern.get_qualified_path ());
    2876              :                  });
    2877            0 : }
    2878              : 
    2879              : void
    2880           41 : TokenCollector::visit (RangePattern &pattern)
    2881              : {
    2882           41 :   describe_node (std::string ("RangePattern"), [this, &pattern] () {
    2883           41 :     if (pattern.get_has_lower_bound () && pattern.get_has_upper_bound ())
    2884              :       {
    2885           41 :         visit (pattern.get_lower_bound ());
    2886           41 :         if (pattern.get_has_ellipsis_syntax ())
    2887            0 :           push (Rust::Token::make (ELLIPSIS, pattern.get_locus ()));
    2888              :         else
    2889           82 :           push (Rust::Token::make (DOT_DOT_EQ, pattern.get_locus ()));
    2890           41 :         visit (pattern.get_upper_bound ());
    2891              :       }
    2892            0 :     else if (pattern.get_has_lower_bound ())
    2893              :       {
    2894            0 :         visit (pattern.get_lower_bound ());
    2895            0 :         push (Rust::Token::make (DOT_DOT, pattern.get_locus ()));
    2896              :       }
    2897              :     else
    2898              :       {
    2899            0 :         push (Rust::Token::make (DOT_DOT_EQ, pattern.get_locus ()));
    2900            0 :         visit (pattern.get_upper_bound ());
    2901              :       }
    2902           41 :   });
    2903           41 : }
    2904              : 
    2905              : void
    2906          198 : TokenCollector::visit (ReferencePattern &pattern)
    2907              : 
    2908              : {
    2909          198 :   describe_node (std::string ("ReferencePattern"), [this, &pattern] () {
    2910          198 :     if (pattern.is_double_reference ())
    2911              :       {
    2912           20 :         push (Rust::Token::make (LOGICAL_AND, pattern.get_locus ()));
    2913              :       }
    2914              :     else
    2915              :       {
    2916          376 :         push (Rust::Token::make (AMP, pattern.get_locus ()));
    2917              :       }
    2918              : 
    2919          198 :     if (pattern.get_is_mut ())
    2920              :       {
    2921            0 :         push (Rust::Token::make (MUT, UNDEF_LOCATION));
    2922              :       }
    2923              : 
    2924          198 :     visit (pattern.get_referenced_pattern ());
    2925          198 :   });
    2926          198 : }
    2927              : 
    2928              : // void TokenCollector::visit(StructPatternField& ){}
    2929              : 
    2930              : void
    2931           18 : TokenCollector::visit (StructPatternFieldTuplePat &pattern)
    2932              : {
    2933           18 :   describe_node (std::string ("StructPatternFieldTuplePat"), [this,
    2934              :                                                               &pattern] () {
    2935           18 :     visit_items_as_lines (pattern.get_outer_attrs ());
    2936           18 :     auto str = std::to_string (pattern.get_index ());
    2937           18 :     auto suffix_start = str.length ();
    2938           36 :     push (Rust::Token::make_int (pattern.get_locus (), str, suffix_start,
    2939              :                                  IntegerLiteralBase::Decimal));
    2940           18 :     push (Rust::Token::make (COLON, pattern.get_locus ()));
    2941           18 :     visit (pattern.get_index_pattern ());
    2942           18 :   });
    2943           18 : }
    2944              : 
    2945              : void
    2946          131 : TokenCollector::visit (StructPatternFieldIdentPat &pattern)
    2947              : {
    2948          131 :   describe_node (std::string ("StructPatternFieldIdentPat"), [this,
    2949              :                                                               &pattern] () {
    2950          131 :     visit_items_as_lines (pattern.get_outer_attrs ());
    2951              : 
    2952          131 :     auto id = pattern.get_identifier ().as_string ();
    2953          262 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2954              : 
    2955          131 :     push (Rust::Token::make (COLON, pattern.get_locus ()));
    2956              : 
    2957          131 :     visit (pattern.get_ident_pattern ());
    2958          131 :   });
    2959          131 : }
    2960              : 
    2961              : void
    2962           91 : TokenCollector::visit (StructPatternFieldIdent &pattern)
    2963              : {
    2964           91 :   describe_node (std::string ("StructPatternFieldIdent"), [this, &pattern] () {
    2965           91 :     visit_items_as_lines (pattern.get_outer_attrs ());
    2966           91 :     if (pattern.is_ref ())
    2967            0 :       push (Rust::Token::make (REF, UNDEF_LOCATION));
    2968           91 :     if (pattern.is_mut ())
    2969            4 :       push (Rust::Token::make (MUT, UNDEF_LOCATION));
    2970              : 
    2971           91 :     auto id = pattern.get_identifier ().as_string ();
    2972          182 :     push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (id)));
    2973           91 :   });
    2974           91 : }
    2975              : 
    2976              : void
    2977          141 : TokenCollector::visit (StructPattern &pattern)
    2978              : {
    2979          141 :   describe_node (std::string ("StructPattern"), [this, &pattern] () {
    2980          141 :     visit (pattern.get_path ());
    2981          141 :     push (Rust::Token::make (LEFT_CURLY, pattern.get_locus ()));
    2982          141 :     auto elems = pattern.get_struct_pattern_elems ();
    2983          141 :     if (elems.has_struct_pattern_fields ())
    2984              :       {
    2985          140 :         visit_items_joined_by_separator (elems.get_struct_pattern_fields ());
    2986          140 :         if (elems.has_rest ())
    2987              :           {
    2988            3 :             push (Rust::Token::make (COMMA, UNDEF_LOCATION));
    2989            3 :             visit_items_as_lines (elems.get_etc_outer_attrs ());
    2990              :           }
    2991              :       }
    2992              :     else
    2993              :       {
    2994            1 :         visit_items_as_lines (elems.get_etc_outer_attrs ());
    2995              :       }
    2996              : 
    2997          282 :     push (Rust::Token::make (RIGHT_CURLY, UNDEF_LOCATION));
    2998          141 :   });
    2999          141 : }
    3000              : 
    3001              : // void TokenCollector::visit(TupleStructItems& ){}
    3002              : 
    3003              : void
    3004          936 : TokenCollector::visit (TupleStructItemsNoRest &pattern)
    3005              : {
    3006          936 :   describe_node (std::string ("TupleStructItemsNoRange"), [this, &pattern] () {
    3007          936 :     visit_items_joined_by_separator (pattern.get_patterns ());
    3008          936 :   });
    3009          936 : }
    3010              : 
    3011              : void
    3012           36 : TokenCollector::visit (TupleStructItemsHasRest &pattern)
    3013              : {
    3014           36 :   describe_node (std::string ("TupleStructItemsRange"), [this, &pattern] () {
    3015           65 :     for (auto &lower : pattern.get_lower_patterns ())
    3016              :       {
    3017           29 :         visit (lower);
    3018              :       }
    3019           36 :     push (Rust::Token::make (DOT_DOT, UNDEF_LOCATION));
    3020           65 :     for (auto &upper : pattern.get_lower_patterns ())
    3021              :       {
    3022           29 :         visit (upper);
    3023              :       }
    3024           36 :   });
    3025           36 : }
    3026              : 
    3027              : void
    3028          972 : TokenCollector::visit (TupleStructPattern &pattern)
    3029              : {
    3030          972 :   describe_node (std::string ("TupleStructPattern"), [this, &pattern] () {
    3031          972 :     visit (pattern.get_path ());
    3032          972 :     push (Rust::Token::make (LEFT_PAREN, pattern.get_locus ()));
    3033          972 :     visit (pattern.get_items ());
    3034          972 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    3035          972 :   });
    3036          972 : }
    3037              : 
    3038              : // void
    3039              : // TokenCollector::visit (TuplePatternItems &)
    3040              : // {}
    3041              : 
    3042              : void
    3043          412 : TokenCollector::visit (TuplePatternItemsNoRest &pattern)
    3044              : {
    3045          412 :   describe_node (std::string ("TuplePatternItemsMultiple"), [this,
    3046              :                                                              &pattern] () {
    3047          412 :     visit_items_joined_by_separator (pattern.get_patterns (), COMMA);
    3048          412 :   });
    3049          412 : }
    3050              : 
    3051              : void
    3052           31 : TokenCollector::visit (TuplePatternItemsHasRest &pattern)
    3053              : {
    3054           31 :   describe_node (std::string ("TuplePatternItemsRanged"), [this, &pattern] () {
    3055           58 :     for (auto &lower : pattern.get_lower_patterns ())
    3056              :       {
    3057           27 :         visit (lower);
    3058              :       }
    3059           31 :     push (Rust::Token::make (DOT_DOT, UNDEF_LOCATION));
    3060           58 :     for (auto &upper : pattern.get_lower_patterns ())
    3061              :       {
    3062           27 :         visit (upper);
    3063              :       }
    3064           31 :   });
    3065           31 : }
    3066              : 
    3067              : void
    3068          443 : TokenCollector::visit (TuplePattern &pattern)
    3069              : {
    3070          443 :   describe_node (std::string ("TuplePattern"), [this, &pattern] () {
    3071          443 :     push (Rust::Token::make (LEFT_PAREN, pattern.get_locus ()));
    3072          443 :     visit (pattern.get_items ());
    3073          443 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    3074          443 :   });
    3075          443 : }
    3076              : 
    3077              : void
    3078            1 : TokenCollector::visit (GroupedPattern &pattern)
    3079              : {
    3080            1 :   describe_node (std::string ("GroupedPattern"), [this, &pattern] () {
    3081            1 :     push (Rust::Token::make (LEFT_PAREN, pattern.get_locus ()));
    3082            1 :     visit (pattern.get_pattern_in_parens ());
    3083            1 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    3084            1 :   });
    3085            1 : }
    3086              : 
    3087              : void
    3088           75 : TokenCollector::visit (SlicePattern &pattern)
    3089              : {
    3090           75 :   describe_node (std::string ("SlicePattern"), [this, &pattern] () {
    3091           75 :     push (Rust::Token::make (LEFT_SQUARE, pattern.get_locus ()));
    3092           75 :     visit_items_joined_by_separator (pattern.get_patterns (), COMMA);
    3093           75 :     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
    3094           75 :   });
    3095           75 : }
    3096              : 
    3097              : void
    3098          145 : TokenCollector::visit (AltPattern &pattern)
    3099              : {
    3100          145 :   describe_node (std::string ("AltPattern"), [this, &pattern] () {
    3101          145 :     visit_items_joined_by_separator (pattern.get_alts (), PIPE);
    3102          145 :   });
    3103          145 : }
    3104              : 
    3105              : // rust-stmt.h
    3106              : void
    3107           45 : TokenCollector::visit (EmptyStmt &)
    3108           45 : {}
    3109              : 
    3110              : void
    3111        12753 : TokenCollector::visit (LetStmt &stmt)
    3112              : {
    3113        12753 :   describe_node (std::string ("LetStmt"), [this, &stmt] () {
    3114        12753 :     push (Rust::Token::make (LET, stmt.get_locus ()));
    3115        12753 :     auto &pattern = stmt.get_pattern ();
    3116        12753 :     visit (pattern);
    3117              : 
    3118        12753 :     if (stmt.has_type ())
    3119              :       {
    3120         2125 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
    3121         2125 :         visit (stmt.get_type ());
    3122              :       }
    3123              : 
    3124        12753 :     if (stmt.has_type ())
    3125              :       {
    3126         2125 :         push (Rust::Token::make (COLON, UNDEF_LOCATION));
    3127         2125 :         visit (stmt.get_type ());
    3128              :       }
    3129              : 
    3130        12753 :     if (stmt.has_init_expr ())
    3131              :       {
    3132        11634 :         push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
    3133        11634 :         visit (stmt.get_init_expr ());
    3134              :       }
    3135              : 
    3136        12753 :     if (stmt.has_else_expr ())
    3137              :       {
    3138            5 :         push (Rust::Token::make (ELSE, UNDEF_LOCATION));
    3139            5 :         visit (stmt.get_else_expr ());
    3140              :       }
    3141              : 
    3142        12753 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    3143        12753 :   });
    3144        12753 : }
    3145              : 
    3146              : void
    3147        11096 : TokenCollector::visit (ExprStmt &stmt)
    3148              : {
    3149        11096 :   describe_node (std::string ("ExprStmt"), [this, &stmt] () {
    3150        11096 :     visit (stmt.get_expr ());
    3151              : 
    3152        11096 :     if (stmt.is_semicolon_followed ())
    3153        17678 :       push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    3154        11096 :   });
    3155        11096 : }
    3156              : 
    3157              : // rust-type.h
    3158              : void
    3159         2108 : TokenCollector::visit (TraitBound &bound)
    3160              : {
    3161              :   // Syntax:
    3162              :   //      ?? ForLifetimes? TypePath
    3163              :   //   | ( ?? ForLifetimes? TypePath )
    3164         2108 :   describe_node (std::string ("TraitBound"), [this, &bound] () {
    3165         2108 :     if (bound.has_opening_question_mark ())
    3166          792 :       push (Rust::Token::make (QUESTION_MARK, bound.get_locus ()));
    3167              : 
    3168         2108 :     if (bound.has_for_lifetimes ())
    3169            7 :       visit (bound.get_for_lifetimes ());
    3170              : 
    3171         2108 :     visit (bound.get_type_path ());
    3172         2108 :   });
    3173         2108 : }
    3174              : 
    3175              : void
    3176            0 : TokenCollector::visit (ImplTraitType &type)
    3177              : {
    3178              :   // Syntax:
    3179              :   //    impl TypeParamBounds
    3180              :   // TypeParamBounds :
    3181              :   //    TypeParamBound ( + TypeParamBound )* +?
    3182            0 :   describe_node (std::string ("ImplTraitType"), [this, &type] () {
    3183            0 :     push (Rust::Token::make (IMPL, type.get_locus ()));
    3184            0 :     visit_items_joined_by_separator (type.get_type_param_bounds (), PLUS);
    3185            0 :   });
    3186            0 : }
    3187              : 
    3188              : void
    3189           11 : TokenCollector::visit (TraitObjectType &type)
    3190              : {
    3191              :   // Syntax:
    3192              :   //   dyn? TypeParamBounds
    3193              :   // TypeParamBounds :
    3194              :   //   TypeParamBound ( + TypeParamBound )* +?
    3195           11 :   describe_node (std::string ("TraiObjectType"), [this, &type] () {
    3196           11 :     if (type.is_dyn ())
    3197           22 :       push (Rust::Token::make (DYN, type.get_locus ()));
    3198           11 :     visit_items_joined_by_separator (type.get_type_param_bounds (), PLUS);
    3199           11 :   });
    3200           11 : }
    3201              : 
    3202              : void
    3203            5 : TokenCollector::visit (ParenthesisedType &type)
    3204              : {
    3205              :   // Syntax:
    3206              :   //    ( Type )
    3207            5 :   describe_node (std::string ("ParenthesisedType"), [this, &type] () {
    3208            5 :     push (Rust::Token::make (LEFT_PAREN, type.get_locus ()));
    3209            5 :     visit (type.get_type_in_parens ());
    3210            5 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    3211            5 :   });
    3212            5 : }
    3213              : 
    3214              : void
    3215           28 : TokenCollector::visit (ImplTraitTypeOneBound &type)
    3216              : {
    3217              :   // Syntax:
    3218              :   //    impl TraitBound
    3219              : 
    3220           28 :   describe_node (std::string ("ImplTraitTypeOneBound"), [this, &type] () {
    3221           28 :     push (Rust::Token::make (IMPL, type.get_locus ()));
    3222           28 :     visit (type.get_trait_bound ());
    3223           28 :   });
    3224           28 : }
    3225              : 
    3226              : void
    3227          326 : TokenCollector::visit (TraitObjectTypeOneBound &type)
    3228              : {
    3229              :   // Syntax:
    3230              :   //    dyn? TraitBound
    3231          326 :   describe_node (std::string ("TraitObjectTypeOneBound"), [this, &type] () {
    3232          326 :     if (type.is_dyn ())
    3233          652 :       push (Rust::Token::make (DYN, type.get_locus ()));
    3234          326 :     visit (type.get_trait_bound ());
    3235          326 :   });
    3236          326 : }
    3237              : 
    3238              : void
    3239          414 : TokenCollector::visit (TupleType &type)
    3240              : {
    3241              :   // Syntax:
    3242              :   //   ( )
    3243              :   //   | ( ( Type , )+ Type? )
    3244              : 
    3245          414 :   describe_node (std::string ("TupleType"), [this, &type] () {
    3246          414 :     push (Rust::Token::make (LEFT_PAREN, type.get_locus ()));
    3247          414 :     visit_items_joined_by_separator (type.get_elems (), COMMA);
    3248          414 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    3249          414 :   });
    3250          414 : }
    3251              : 
    3252              : void
    3253          185 : TokenCollector::visit (NeverType &type)
    3254              : {
    3255              :   // Syntax:
    3256              :   //  !
    3257              : 
    3258          185 :   describe_node (std::string ("NeverType"), [this, &type] () {
    3259          185 :     push (Rust::Token::make (EXCLAM, type.get_locus ()));
    3260          185 :   });
    3261          185 : }
    3262              : 
    3263              : void
    3264         6975 : TokenCollector::visit (RawPointerType &type)
    3265              : {
    3266              :   // Syntax:
    3267              :   //    * ( mut | const ) TypeNoBounds
    3268         6975 :   describe_node (std::string ("RawPointerType"), [this, &type] () {
    3269         6975 :     push (Rust::Token::make (ASTERISK, type.get_locus ()));
    3270         6975 :     if (type.get_pointer_type () == RawPointerType::MUT)
    3271         1518 :       push (Rust::Token::make (MUT, UNDEF_LOCATION));
    3272              :     else /* RawPointerType::CONST */
    3273        12432 :       push (Rust::Token::make (CONST, UNDEF_LOCATION));
    3274              : 
    3275         6975 :     visit (type.get_type_pointed_to ());
    3276         6975 :   });
    3277         6975 : }
    3278              : 
    3279              : void
    3280         4724 : TokenCollector::visit (ReferenceType &type)
    3281              : {
    3282              :   // Syntax:
    3283              :   //    & Lifetime? mut? TypeNoBounds
    3284         4724 :   describe_node (std::string ("ReferenceType"), [this, &type] () {
    3285         4724 :     push (Rust::Token::make (AMP, type.get_locus ()));
    3286              : 
    3287         4724 :     if (type.has_lifetime ())
    3288              :       {
    3289         4724 :         visit (type.get_lifetime ());
    3290              :       }
    3291              : 
    3292         4724 :     if (type.get_has_mut ())
    3293          644 :       push (Rust::Token::make (MUT, UNDEF_LOCATION));
    3294              : 
    3295         4724 :     visit (type.get_type_referenced ());
    3296         4724 :   });
    3297         4724 : }
    3298              : 
    3299              : void
    3300          843 : TokenCollector::visit (ArrayType &type)
    3301              : {
    3302              :   // Syntax:
    3303              :   //    [type Type ; Expression ]
    3304          843 :   describe_node (std::string ("ArrayType"), [this, &type] () {
    3305          843 :     push (Rust::Token::make (LEFT_SQUARE, type.get_locus ()));
    3306          843 :     visit (type.get_elem_type ());
    3307          843 :     push (Rust::Token::make (SEMICOLON, UNDEF_LOCATION));
    3308          843 :     visit (type.get_size_expr ());
    3309          843 :     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
    3310          843 :   });
    3311          843 : }
    3312              : 
    3313              : void
    3314          930 : TokenCollector::visit (SliceType &type)
    3315              : {
    3316              :   // Syntax:
    3317              :   //    [type Type ]
    3318              : 
    3319          930 :   describe_node (std::string ("SliceType"), [this, &type] () {
    3320          930 :     push (Rust::Token::make (LEFT_SQUARE, type.get_locus ()));
    3321          930 :     visit (type.get_elem_type ());
    3322          930 :     push (Rust::Token::make (RIGHT_SQUARE, UNDEF_LOCATION));
    3323          930 :   });
    3324          930 : }
    3325              : 
    3326              : void
    3327          261 : TokenCollector::visit (InferredType &type)
    3328              : {
    3329              :   // Syntax:
    3330              :   //    _
    3331          261 :   describe_node (std::string ("InferredType"), [this, &type] () {
    3332          261 :     push (Rust::Token::make (UNDERSCORE, type.get_locus ()));
    3333          261 :   });
    3334          261 : }
    3335              : 
    3336              : void
    3337           79 : TokenCollector::visit (BareFunctionType &type)
    3338              : {
    3339              :   // Syntax:
    3340              :   //    ForLifetimes? FunctionTypeQualifiers fn
    3341              :   //      ( FunctionParametersMaybeNamedVariadic? )
    3342              :   //      BareFunctionReturnType?
    3343              :   //
    3344              :   //    BareFunctionReturnType:
    3345              :   //      -> TypeNoBounds
    3346              :   //
    3347              :   //    FunctionParametersMaybeNamedVariadic :
    3348              :   //      MaybeNamedFunctionParameters |
    3349              :   //      MaybeNamedFunctionParametersVariadic
    3350              :   //
    3351              :   //    MaybeNamedFunctionParameters :
    3352              :   //      MaybeNamedParam ( , MaybeNamedParam )* ,?
    3353              :   //
    3354              :   //    MaybeNamedFunctionParametersVariadic :
    3355              :   //      ( MaybeNamedParam , )* MaybeNamedParam , OuterAttribute* ...
    3356           79 :   describe_node (std::string ("BareFunctionType"), [this, &type] () {
    3357           79 :     if (type.has_for_lifetimes ())
    3358            0 :       visit (type.get_for_lifetimes ());
    3359              : 
    3360           79 :     visit (type.get_function_qualifiers ());
    3361              : 
    3362           79 :     push (Rust::Token::make (FN_KW, type.get_locus ()));
    3363           79 :     push (Rust::Token::make (LEFT_PAREN, UNDEF_LOCATION));
    3364              : 
    3365           79 :     visit_items_joined_by_separator (type.get_function_params (), COMMA);
    3366              : 
    3367           79 :     if (type.is_variadic ())
    3368              :       {
    3369            0 :         push (Rust::Token::make (COMMA, UNDEF_LOCATION));
    3370            0 :         for (auto &item : type.get_variadic_attr ())
    3371              :           {
    3372            0 :             visit (item);
    3373              :           }
    3374            0 :         push (Rust::Token::make (ELLIPSIS, UNDEF_LOCATION));
    3375              :       }
    3376              : 
    3377           79 :     push (Rust::Token::make (RIGHT_PAREN, UNDEF_LOCATION));
    3378              : 
    3379           79 :     if (type.has_return_type ())
    3380              :       {
    3381           65 :         push (Rust::Token::make (RETURN_TYPE, UNDEF_LOCATION));
    3382           65 :         visit (type.get_return_type ());
    3383              :       }
    3384           79 :   });
    3385           79 : }
    3386              : 
    3387              : void
    3388            0 : TokenCollector::visit (AST::FormatArgs &fmt)
    3389              : {
    3390            0 :   push (Rust::Token::make_identifier (fmt.get_locus (), "format_args"));
    3391            0 :   push (Rust::Token::make (EXCLAM, fmt.get_locus ()));
    3392            0 :   push (Rust::Token::make (LEFT_PAREN, fmt.get_locus ()));
    3393              : 
    3394            0 :   std::string reconstructed_template = "\"";
    3395            0 :   const auto &template_pieces = fmt.get_template ();
    3396              : 
    3397            0 :   for (const auto &piece : template_pieces.get_pieces ())
    3398              :     {
    3399            0 :       if (piece.tag == Fmt::ffi::Piece::Tag::String)
    3400              :         {
    3401            0 :           std::string literal = piece.string._0.to_string ();
    3402            0 :           for (char c : literal)
    3403              :             {
    3404            0 :               if (c == '"' || c == '\\')
    3405              :                 {
    3406            0 :                   reconstructed_template += '\\';
    3407              :                 }
    3408            0 :               else if (c == '\n')
    3409              :                 {
    3410            0 :                   reconstructed_template += "\\n";
    3411            0 :                   continue;
    3412              :                 }
    3413            0 :               else if (c == '\r')
    3414              :                 {
    3415            0 :                   reconstructed_template += "\\r";
    3416            0 :                   continue;
    3417              :                 }
    3418            0 :               else if (c == '\t')
    3419              :                 {
    3420            0 :                   reconstructed_template += "\\t";
    3421            0 :                   continue;
    3422              :                 }
    3423            0 :               reconstructed_template += c;
    3424              :             }
    3425            0 :         }
    3426            0 :       else if (piece.tag == Fmt::ffi::Piece::Tag::NextArgument)
    3427              :         {
    3428            0 :           reconstructed_template += "{";
    3429              : 
    3430            0 :           const auto &argument = piece.next_argument._0;
    3431            0 :           const auto &position = argument.position;
    3432              : 
    3433            0 :           switch (position.tag)
    3434              :             {
    3435              :             case Fmt::ffi::Position::Tag::ArgumentImplicitlyIs:
    3436              :               break;
    3437            0 :             case Fmt::ffi::Position::Tag::ArgumentIs:
    3438            0 :               reconstructed_template
    3439            0 :                 += std::to_string (position.argument_is._0);
    3440            0 :               break;
    3441            0 :             case Fmt::ffi::Position::Tag::ArgumentNamed:
    3442            0 :               reconstructed_template += position.argument_named._0.to_string ();
    3443            0 :               break;
    3444              :             }
    3445              : 
    3446              :           // Add format specifiers if any (like :?, :x, etc.)
    3447            0 :           const auto &format_spec = argument.format;
    3448              : 
    3449            0 :           bool has_format_spec = false;
    3450            0 :           std::string format_part;
    3451              : 
    3452              :           // For now, skipping the complex format specifications that
    3453              :           // use FFIOpt since FFIOpt::get_opt() has a bug.
    3454              : 
    3455              :           // Alignment
    3456            0 :           if (format_spec.align != Fmt::ffi::Alignment::AlignUnknown)
    3457              :             {
    3458            0 :               has_format_spec = true;
    3459            0 :               switch (format_spec.align)
    3460              :                 {
    3461            0 :                 case Fmt::ffi::Alignment::AlignLeft:
    3462            0 :                   format_part += "<";
    3463            0 :                   break;
    3464            0 :                 case Fmt::ffi::Alignment::AlignRight:
    3465            0 :                   format_part += ">";
    3466            0 :                   break;
    3467            0 :                 case Fmt::ffi::Alignment::AlignCenter:
    3468            0 :                   format_part += "^";
    3469            0 :                   break;
    3470              :                 case Fmt::ffi::Alignment::AlignUnknown:
    3471              :                   break;
    3472              :                 }
    3473              :             }
    3474              : 
    3475              :           // Alternate flag
    3476            0 :           if (format_spec.alternate)
    3477              :             {
    3478            0 :               has_format_spec = true;
    3479            0 :               format_part += "#";
    3480              :             }
    3481              : 
    3482              :           // Zero pad flag
    3483            0 :           if (format_spec.zero_pad)
    3484              :             {
    3485            0 :               has_format_spec = true;
    3486            0 :               format_part += "0";
    3487              :             }
    3488              : 
    3489              :           // Width
    3490            0 :           if (format_spec.width.tag != Fmt::ffi::Count::Tag::CountImplied)
    3491              :             {
    3492            0 :               has_format_spec = true;
    3493            0 :               switch (format_spec.width.tag)
    3494              :                 {
    3495            0 :                 case Fmt::ffi::Count::Tag::CountIs:
    3496            0 :                   format_part += std::to_string (format_spec.width.count_is._0);
    3497            0 :                   break;
    3498            0 :                 case Fmt::ffi::Count::Tag::CountIsParam:
    3499            0 :                   format_part
    3500            0 :                     += std::to_string (format_spec.width.count_is_param._0)
    3501            0 :                        + "$";
    3502            0 :                   break;
    3503            0 :                 case Fmt::ffi::Count::Tag::CountIsName:
    3504            0 :                   format_part
    3505            0 :                     += format_spec.width.count_is_name._0.to_string () + "$";
    3506            0 :                   break;
    3507            0 :                 case Fmt::ffi::Count::Tag::CountIsStar:
    3508            0 :                   format_part += "*";
    3509            0 :                   break;
    3510              :                 case Fmt::ffi::Count::Tag::CountImplied:
    3511              :                   break;
    3512              :                 }
    3513              :             }
    3514              : 
    3515              :           // Precision
    3516            0 :           if (format_spec.precision.tag != Fmt::ffi::Count::Tag::CountImplied)
    3517              :             {
    3518            0 :               has_format_spec = true;
    3519            0 :               format_part += ".";
    3520            0 :               switch (format_spec.precision.tag)
    3521              :                 {
    3522            0 :                 case Fmt::ffi::Count::Tag::CountIs:
    3523            0 :                   format_part
    3524            0 :                     += std::to_string (format_spec.precision.count_is._0);
    3525            0 :                   break;
    3526            0 :                 case Fmt::ffi::Count::Tag::CountIsParam:
    3527            0 :                   format_part
    3528            0 :                     += std::to_string (format_spec.precision.count_is_param._0)
    3529            0 :                        + "$";
    3530            0 :                   break;
    3531            0 :                 case Fmt::ffi::Count::Tag::CountIsName:
    3532            0 :                   format_part
    3533            0 :                     += format_spec.precision.count_is_name._0.to_string ()
    3534            0 :                        + "$";
    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              :           // Type/trait (like ?, x, X, etc.)
    3545            0 :           std::string type_str = format_spec.ty.to_string ();
    3546            0 :           if (!type_str.empty ())
    3547              :             {
    3548            0 :               has_format_spec = true;
    3549            0 :               format_part += type_str;
    3550              :             }
    3551              : 
    3552              :           // Add the format specification if any
    3553            0 :           if (has_format_spec)
    3554              :             {
    3555            0 :               reconstructed_template += ":";
    3556            0 :               reconstructed_template += format_part;
    3557              :             }
    3558              : 
    3559            0 :           reconstructed_template += "}";
    3560              :         }
    3561              :     }
    3562            0 :   reconstructed_template += "\"";
    3563              : 
    3564            0 :   push (Rust::Token::make_string (fmt.get_locus (), reconstructed_template));
    3565              : 
    3566              :   // Visit format arguments if any exist
    3567            0 :   auto &arguments = fmt.get_arguments ();
    3568            0 :   if (!arguments.empty ())
    3569              :     {
    3570            0 :       push (Rust::Token::make (COMMA, fmt.get_locus ()));
    3571              : 
    3572            0 :       auto &args = arguments.get_args ();
    3573            0 :       for (size_t i = 0; i < args.size (); ++i)
    3574              :         {
    3575            0 :           if (i > 0)
    3576              :             {
    3577            0 :               push (Rust::Token::make (COMMA, fmt.get_locus ()));
    3578              :             }
    3579              : 
    3580            0 :           auto kind = args[i].get_kind ();
    3581              : 
    3582              :           // Handle named arguments: name = expr
    3583            0 :           if (kind.kind == FormatArgumentKind::Kind::Named)
    3584              :             {
    3585            0 :               auto ident = kind.get_ident ().as_string ();
    3586            0 :               push (Rust::Token::make_identifier (fmt.get_locus (),
    3587              :                                                   std::move (ident)));
    3588            0 :               push (Rust::Token::make (EQUAL, fmt.get_locus ()));
    3589            0 :             }
    3590              :           // Note: Captured arguments are handled implicitly in the
    3591              :           // template reconstruction They don't need explicit "name ="
    3592              :           // syntax in the reconstructed macro call
    3593              : 
    3594            0 :           auto &expr = args[i].get_expr ();
    3595            0 :           expr.accept_vis (*this);
    3596            0 :         }
    3597              :     }
    3598              : 
    3599            0 :   push (Rust::Token::make (RIGHT_PAREN, fmt.get_locus ()));
    3600            0 : }
    3601              : 
    3602              : void
    3603           14 : TokenCollector::visit (AST::OffsetOf &offset_of)
    3604              : {
    3605           14 :   auto loc = offset_of.get_locus ();
    3606              : 
    3607           28 :   push (Rust::Token::make_identifier (loc, "offset_of"));
    3608           14 :   push (Rust::Token::make (EXCLAM, loc));
    3609           14 :   push (Rust::Token::make (LEFT_PAREN, loc));
    3610              : 
    3611           14 :   visit (offset_of.get_type ());
    3612              : 
    3613           14 :   push (Rust::Token::make (COMMA, loc));
    3614              : 
    3615           14 :   push (Rust::Token::make_identifier (offset_of.get_field ()));
    3616              : 
    3617           14 :   push (Rust::Token::make (RIGHT_PAREN, loc));
    3618           14 : }
    3619              : 
    3620              : } // namespace AST
    3621              : } // namespace Rust
        

Generated by: LCOV version 2.4-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.