https://gcc.gnu.org/g:22baf6c75f43f84500c964e67417d07738177436
commit r16-4864-g22baf6c75f43f84500c964e67417d07738177436 Author: Magnus-Mage <[email protected]> Date: Sun Sep 7 21:10:20 2025 +0530 gccrs: Implement TokenCollector::visit(AST::FormatArgs&) 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 <[email protected]> Diff: --- gcc/rust/ast/rust-ast-collector.cc | 212 +++++++++++++++++++++++++++++++++- gcc/rust/ast/rust-builtin-ast-nodes.h | 7 ++ 2 files changed, 217 insertions(+), 2 deletions(-) diff --git a/gcc/rust/ast/rust-ast-collector.cc b/gcc/rust/ast/rust-ast-collector.cc index 1060831862a8..842f35f288d5 100644 --- a/gcc/rust/ast/rust-ast-collector.cc +++ b/gcc/rust/ast/rust-ast-collector.cc @@ -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 diff --git a/gcc/rust/ast/rust-builtin-ast-nodes.h b/gcc/rust/ast/rust-builtin-ast-nodes.h index 2856a6434495..c784ad67109c 100644 --- a/gcc/rust/ast/rust-builtin-ast-nodes.h +++ b/gcc/rust/ast/rust-builtin-ast-nodes.h @@ -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; }
