]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Implement TokenCollector::visit(AST::FormatArgs&)
authorMagnus-Mage <romescha123@gmail.com>
Sun, 7 Sep 2025 15:40:20 +0000 (21:10 +0530)
committerArthur Cohen <arthur.cohen@embecosm.com>
Thu, 30 Oct 2025 20:30:51 +0000 (21:30 +0100)
This allows visiting format_args! during token collection.

gcc/rust/ChangeLog:

* ast/rust-ast-collector.cc (TokenCollector::visit): Implement
FormatArgs visitor to reconstruct format_args! macro syntax.
* ast/rust-builtin-ast-nodes.h (FormatArguments): Add get_args(),
size(), and empty() accessor methods.

Signed-off-by: Magnus-Mage <romescha123@gmail.com>
gcc/rust/ast/rust-ast-collector.cc
gcc/rust/ast/rust-builtin-ast-nodes.h

index 1060831862a87d148b852e951f7305d992849f6c..842f35f288d5b4228b9c9aaef0d95657bf98e096 100644 (file)
@@ -2997,8 +2997,216 @@ TokenCollector::visit (BareFunctionType &type)
 void
 TokenCollector::visit (AST::FormatArgs &fmt)
 {
-  rust_sorry_at (fmt.get_locus (), "%s:%u: unimplemented FormatArgs visitor",
-                __FILE__, __LINE__);
+  push (Rust::Token::make_identifier (fmt.get_locus (), "format_args"));
+  push (Rust::Token::make (EXCLAM, fmt.get_locus ()));
+  push (Rust::Token::make (LEFT_PAREN, fmt.get_locus ()));
+
+  std::string reconstructed_template = "\"";
+  const auto &template_pieces = fmt.get_template ();
+
+  for (const auto &piece : template_pieces.get_pieces ())
+    {
+      if (piece.tag == Fmt::ffi::Piece::Tag::String)
+       {
+         std::string literal = piece.string._0.to_string ();
+         for (char c : literal)
+           {
+             if (c == '"' || c == '\\')
+               {
+                 reconstructed_template += '\\';
+               }
+             else if (c == '\n')
+               {
+                 reconstructed_template += "\\n";
+                 continue;
+               }
+             else if (c == '\r')
+               {
+                 reconstructed_template += "\\r";
+                 continue;
+               }
+             else if (c == '\t')
+               {
+                 reconstructed_template += "\\t";
+                 continue;
+               }
+             reconstructed_template += c;
+           }
+       }
+      else if (piece.tag == Fmt::ffi::Piece::Tag::NextArgument)
+       {
+         reconstructed_template += "{";
+
+         const auto &argument = piece.next_argument._0;
+         const auto &position = argument.position;
+
+         switch (position.tag)
+           {
+           case Fmt::ffi::Position::Tag::ArgumentImplicitlyIs:
+             break;
+           case Fmt::ffi::Position::Tag::ArgumentIs:
+             reconstructed_template
+               += std::to_string (position.argument_is._0);
+             break;
+           case Fmt::ffi::Position::Tag::ArgumentNamed:
+             reconstructed_template += position.argument_named._0.to_string ();
+             break;
+           }
+
+         // Add format specifiers if any (like :?, :x, etc.)
+         const auto &format_spec = argument.format;
+
+         bool has_format_spec = false;
+         std::string format_part;
+
+         // For now, skipping the complex format specifications that use FFIOpt
+         // since FFIOpt::get_opt() has a bug.
+
+         // Alignment
+         if (format_spec.align != Fmt::ffi::Alignment::AlignUnknown)
+           {
+             has_format_spec = true;
+             switch (format_spec.align)
+               {
+               case Fmt::ffi::Alignment::AlignLeft:
+                 format_part += "<";
+                 break;
+               case Fmt::ffi::Alignment::AlignRight:
+                 format_part += ">";
+                 break;
+               case Fmt::ffi::Alignment::AlignCenter:
+                 format_part += "^";
+                 break;
+               case Fmt::ffi::Alignment::AlignUnknown:
+                 break;
+               }
+           }
+
+         // Alternate flag
+         if (format_spec.alternate)
+           {
+             has_format_spec = true;
+             format_part += "#";
+           }
+
+         // Zero pad flag
+         if (format_spec.zero_pad)
+           {
+             has_format_spec = true;
+             format_part += "0";
+           }
+
+         // Width
+         if (format_spec.width.tag != Fmt::ffi::Count::Tag::CountImplied)
+           {
+             has_format_spec = true;
+             switch (format_spec.width.tag)
+               {
+               case Fmt::ffi::Count::Tag::CountIs:
+                 format_part += std::to_string (format_spec.width.count_is._0);
+                 break;
+               case Fmt::ffi::Count::Tag::CountIsParam:
+                 format_part
+                   += std::to_string (format_spec.width.count_is_param._0)
+                      + "$";
+                 break;
+               case Fmt::ffi::Count::Tag::CountIsName:
+                 format_part
+                   += format_spec.width.count_is_name._0.to_string () + "$";
+                 break;
+               case Fmt::ffi::Count::Tag::CountIsStar:
+                 format_part += "*";
+                 break;
+               case Fmt::ffi::Count::Tag::CountImplied:
+                 break;
+               }
+           }
+
+         // Precision
+         if (format_spec.precision.tag != Fmt::ffi::Count::Tag::CountImplied)
+           {
+             has_format_spec = true;
+             format_part += ".";
+             switch (format_spec.precision.tag)
+               {
+               case Fmt::ffi::Count::Tag::CountIs:
+                 format_part
+                   += std::to_string (format_spec.precision.count_is._0);
+                 break;
+               case Fmt::ffi::Count::Tag::CountIsParam:
+                 format_part
+                   += std::to_string (format_spec.precision.count_is_param._0)
+                      + "$";
+                 break;
+               case Fmt::ffi::Count::Tag::CountIsName:
+                 format_part
+                   += format_spec.precision.count_is_name._0.to_string ()
+                      + "$";
+                 break;
+               case Fmt::ffi::Count::Tag::CountIsStar:
+                 format_part += "*";
+                 break;
+               case Fmt::ffi::Count::Tag::CountImplied:
+                 break;
+               }
+           }
+
+         // Type/trait (like ?, x, X, etc.)
+         std::string type_str = format_spec.ty.to_string ();
+         if (!type_str.empty ())
+           {
+             has_format_spec = true;
+             format_part += type_str;
+           }
+
+         // Add the format specification if any
+         if (has_format_spec)
+           {
+             reconstructed_template += ":";
+             reconstructed_template += format_part;
+           }
+
+         reconstructed_template += "}";
+       }
+    }
+  reconstructed_template += "\"";
+
+  push (Rust::Token::make_string (fmt.get_locus (), reconstructed_template));
+
+  // Visit format arguments if any exist
+  auto &arguments = fmt.get_arguments ();
+  if (!arguments.empty ())
+    {
+      push (Rust::Token::make (COMMA, fmt.get_locus ()));
+
+      auto &args = arguments.get_args ();
+      for (size_t i = 0; i < args.size (); ++i)
+       {
+         if (i > 0)
+           {
+             push (Rust::Token::make (COMMA, fmt.get_locus ()));
+           }
+
+         auto kind = args[i].get_kind ();
+
+         // Handle named arguments: name = expr
+         if (kind.kind == FormatArgumentKind::Kind::Named)
+           {
+             auto ident = kind.get_ident ().as_string ();
+             push (Rust::Token::make_identifier (fmt.get_locus (),
+                                                 std::move (ident)));
+             push (Rust::Token::make (EQUAL, fmt.get_locus ()));
+           }
+         // Note: Captured arguments are handled implicitly in the template
+         // reconstruction They don't need explicit "name =" syntax in the
+         // reconstructed macro call
+
+         auto &expr = args[i].get_expr ();
+         expr.accept_vis (*this);
+       }
+    }
+
+  push (Rust::Token::make (RIGHT_PAREN, fmt.get_locus ()));
 }
 
 void
index 2856a643449531c7d1e29a7f8a25312fc97c65f6..c784ad67109cbcf48a97c348838bd10675f66c1f 100644 (file)
@@ -134,6 +134,7 @@ public:
 
   FormatArgumentKind get_kind () const { return kind; }
   const Expr &get_expr () const { return *expr; }
+  Expr &get_expr () { return *expr; }
 
 private:
   FormatArgument (FormatArgumentKind::Kind kind, tl::optional<Identifier> ident,
@@ -164,6 +165,11 @@ public:
   void push (FormatArgument &&elt) { args.emplace_back (std::move (elt)); }
   const FormatArgument at (size_t idx) const { return args.at (idx); }
 
+  const std::vector<FormatArgument> &get_args () const { return args; }
+  std::vector<FormatArgument> &get_args () { return args; }
+  size_t size () const { return args.size (); }
+  bool empty () const { return args.empty (); }
+
 private:
   std::vector<FormatArgument> args;
 };
@@ -200,6 +206,7 @@ public:
 
   const Fmt::Pieces &get_template () const { return template_pieces; }
   const FormatArguments &get_arguments () const { return arguments; }
+  FormatArguments &get_arguments () { return arguments; }
   virtual location_t get_locus () const override;
 
   Expr::Kind get_expr_kind () const override { return Expr::Kind::FormatArgs; }