Skip to content

Commit 9e1d673

Browse files
Magnus-MageP-E-P
authored andcommitted
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]>
1 parent dab88dc commit 9e1d673

File tree

2 files changed

+217
-2
lines changed

2 files changed

+217
-2
lines changed

gcc/rust/ast/rust-ast-collector.cc

Lines changed: 210 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2997,8 +2997,216 @@ TokenCollector::visit (BareFunctionType &type)
29972997
void
29982998
TokenCollector::visit (AST::FormatArgs &fmt)
29992999
{
3000-
rust_sorry_at (fmt.get_locus (), "%s:%u: unimplemented FormatArgs visitor",
3001-
__FILE__, __LINE__);
3000+
push (Rust::Token::make_identifier (fmt.get_locus (), "format_args"));
3001+
push (Rust::Token::make (EXCLAM, fmt.get_locus ()));
3002+
push (Rust::Token::make (LEFT_PAREN, fmt.get_locus ()));
3003+
3004+
std::string reconstructed_template = "\"";
3005+
const auto &template_pieces = fmt.get_template ();
3006+
3007+
for (const auto &piece : template_pieces.get_pieces ())
3008+
{
3009+
if (piece.tag == Fmt::ffi::Piece::Tag::String)
3010+
{
3011+
std::string literal = piece.string._0.to_string ();
3012+
for (char c : literal)
3013+
{
3014+
if (c == '"' || c == '\\')
3015+
{
3016+
reconstructed_template += '\\';
3017+
}
3018+
else if (c == '\n')
3019+
{
3020+
reconstructed_template += "\\n";
3021+
continue;
3022+
}
3023+
else if (c == '\r')
3024+
{
3025+
reconstructed_template += "\\r";
3026+
continue;
3027+
}
3028+
else if (c == '\t')
3029+
{
3030+
reconstructed_template += "\\t";
3031+
continue;
3032+
}
3033+
reconstructed_template += c;
3034+
}
3035+
}
3036+
else if (piece.tag == Fmt::ffi::Piece::Tag::NextArgument)
3037+
{
3038+
reconstructed_template += "{";
3039+
3040+
const auto &argument = piece.next_argument._0;
3041+
const auto &position = argument.position;
3042+
3043+
switch (position.tag)
3044+
{
3045+
case Fmt::ffi::Position::Tag::ArgumentImplicitlyIs:
3046+
break;
3047+
case Fmt::ffi::Position::Tag::ArgumentIs:
3048+
reconstructed_template
3049+
+= std::to_string (position.argument_is._0);
3050+
break;
3051+
case Fmt::ffi::Position::Tag::ArgumentNamed:
3052+
reconstructed_template += position.argument_named._0.to_string ();
3053+
break;
3054+
}
3055+
3056+
// Add format specifiers if any (like :?, :x, etc.)
3057+
const auto &format_spec = argument.format;
3058+
3059+
bool has_format_spec = false;
3060+
std::string format_part;
3061+
3062+
// For now, skipping the complex format specifications that use FFIOpt
3063+
// since FFIOpt::get_opt() has a bug.
3064+
3065+
// Alignment
3066+
if (format_spec.align != Fmt::ffi::Alignment::AlignUnknown)
3067+
{
3068+
has_format_spec = true;
3069+
switch (format_spec.align)
3070+
{
3071+
case Fmt::ffi::Alignment::AlignLeft:
3072+
format_part += "<";
3073+
break;
3074+
case Fmt::ffi::Alignment::AlignRight:
3075+
format_part += ">";
3076+
break;
3077+
case Fmt::ffi::Alignment::AlignCenter:
3078+
format_part += "^";
3079+
break;
3080+
case Fmt::ffi::Alignment::AlignUnknown:
3081+
break;
3082+
}
3083+
}
3084+
3085+
// Alternate flag
3086+
if (format_spec.alternate)
3087+
{
3088+
has_format_spec = true;
3089+
format_part += "#";
3090+
}
3091+
3092+
// Zero pad flag
3093+
if (format_spec.zero_pad)
3094+
{
3095+
has_format_spec = true;
3096+
format_part += "0";
3097+
}
3098+
3099+
// Width
3100+
if (format_spec.width.tag != Fmt::ffi::Count::Tag::CountImplied)
3101+
{
3102+
has_format_spec = true;
3103+
switch (format_spec.width.tag)
3104+
{
3105+
case Fmt::ffi::Count::Tag::CountIs:
3106+
format_part += std::to_string (format_spec.width.count_is._0);
3107+
break;
3108+
case Fmt::ffi::Count::Tag::CountIsParam:
3109+
format_part
3110+
+= std::to_string (format_spec.width.count_is_param._0)
3111+
+ "$";
3112+
break;
3113+
case Fmt::ffi::Count::Tag::CountIsName:
3114+
format_part
3115+
+= format_spec.width.count_is_name._0.to_string () + "$";
3116+
break;
3117+
case Fmt::ffi::Count::Tag::CountIsStar:
3118+
format_part += "*";
3119+
break;
3120+
case Fmt::ffi::Count::Tag::CountImplied:
3121+
break;
3122+
}
3123+
}
3124+
3125+
// Precision
3126+
if (format_spec.precision.tag != Fmt::ffi::Count::Tag::CountImplied)
3127+
{
3128+
has_format_spec = true;
3129+
format_part += ".";
3130+
switch (format_spec.precision.tag)
3131+
{
3132+
case Fmt::ffi::Count::Tag::CountIs:
3133+
format_part
3134+
+= std::to_string (format_spec.precision.count_is._0);
3135+
break;
3136+
case Fmt::ffi::Count::Tag::CountIsParam:
3137+
format_part
3138+
+= std::to_string (format_spec.precision.count_is_param._0)
3139+
+ "$";
3140+
break;
3141+
case Fmt::ffi::Count::Tag::CountIsName:
3142+
format_part
3143+
+= format_spec.precision.count_is_name._0.to_string ()
3144+
+ "$";
3145+
break;
3146+
case Fmt::ffi::Count::Tag::CountIsStar:
3147+
format_part += "*";
3148+
break;
3149+
case Fmt::ffi::Count::Tag::CountImplied:
3150+
break;
3151+
}
3152+
}
3153+
3154+
// Type/trait (like ?, x, X, etc.)
3155+
std::string type_str = format_spec.ty.to_string ();
3156+
if (!type_str.empty ())
3157+
{
3158+
has_format_spec = true;
3159+
format_part += type_str;
3160+
}
3161+
3162+
// Add the format specification if any
3163+
if (has_format_spec)
3164+
{
3165+
reconstructed_template += ":";
3166+
reconstructed_template += format_part;
3167+
}
3168+
3169+
reconstructed_template += "}";
3170+
}
3171+
}
3172+
reconstructed_template += "\"";
3173+
3174+
push (Rust::Token::make_string (fmt.get_locus (), reconstructed_template));
3175+
3176+
// Visit format arguments if any exist
3177+
auto &arguments = fmt.get_arguments ();
3178+
if (!arguments.empty ())
3179+
{
3180+
push (Rust::Token::make (COMMA, fmt.get_locus ()));
3181+
3182+
auto &args = arguments.get_args ();
3183+
for (size_t i = 0; i < args.size (); ++i)
3184+
{
3185+
if (i > 0)
3186+
{
3187+
push (Rust::Token::make (COMMA, fmt.get_locus ()));
3188+
}
3189+
3190+
auto kind = args[i].get_kind ();
3191+
3192+
// Handle named arguments: name = expr
3193+
if (kind.kind == FormatArgumentKind::Kind::Named)
3194+
{
3195+
auto ident = kind.get_ident ().as_string ();
3196+
push (Rust::Token::make_identifier (fmt.get_locus (),
3197+
std::move (ident)));
3198+
push (Rust::Token::make (EQUAL, fmt.get_locus ()));
3199+
}
3200+
// Note: Captured arguments are handled implicitly in the template
3201+
// reconstruction They don't need explicit "name =" syntax in the
3202+
// reconstructed macro call
3203+
3204+
auto &expr = args[i].get_expr ();
3205+
expr.accept_vis (*this);
3206+
}
3207+
}
3208+
3209+
push (Rust::Token::make (RIGHT_PAREN, fmt.get_locus ()));
30023210
}
30033211

30043212
void

gcc/rust/ast/rust-builtin-ast-nodes.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class FormatArgument
134134

135135
FormatArgumentKind get_kind () const { return kind; }
136136
const Expr &get_expr () const { return *expr; }
137+
Expr &get_expr () { return *expr; }
137138

138139
private:
139140
FormatArgument (FormatArgumentKind::Kind kind, tl::optional<Identifier> ident,
@@ -164,6 +165,11 @@ class FormatArguments
164165
void push (FormatArgument &&elt) { args.emplace_back (std::move (elt)); }
165166
const FormatArgument at (size_t idx) const { return args.at (idx); }
166167

168+
const std::vector<FormatArgument> &get_args () const { return args; }
169+
std::vector<FormatArgument> &get_args () { return args; }
170+
size_t size () const { return args.size (); }
171+
bool empty () const { return args.empty (); }
172+
167173
private:
168174
std::vector<FormatArgument> args;
169175
};
@@ -200,6 +206,7 @@ class FormatArgs : public Expr
200206

201207
const Fmt::Pieces &get_template () const { return template_pieces; }
202208
const FormatArguments &get_arguments () const { return arguments; }
209+
FormatArguments &get_arguments () { return arguments; }
203210
virtual location_t get_locus () const override;
204211

205212
Expr::Kind get_expr_kind () const override { return Expr::Kind::FormatArgs; }

0 commit comments

Comments
 (0)