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