1 // Copyright (C) 2024 Free Software Foundation, Inc.
3 // This file is part of GCC.
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
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
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/>.
19 #include "rust-expand-format-args.h"
20 #include "rust-ast-fragment.h"
22 #include "rust-builtin-ast-nodes.h"
23 #include "rust-ast-builder.h"
24 #include "rust-diagnostics.h"
25 #include "rust-expr.h"
27 #include "rust-path.h"
28 #include "rust-system.h"
29 #include "rust-token.h"
34 static std::unique_ptr
<AST::Expr
>
35 format_arg (const AST::Builder
&builder
, std::unique_ptr
<AST::Expr
> &&to_format
,
36 const std::string
&trait
)
38 auto formatter_fn
= std::unique_ptr
<AST::Expr
> (new AST::PathInExpression (
39 builder
.path_in_expression ({"core", "fmt", trait
, "fmt"})));
41 auto path
= std::unique_ptr
<AST::Expr
> (new AST::PathInExpression (
42 builder
.path_in_expression ({"core", "fmt", "ArgumentV1", "new"})));
44 auto args
= std::vector
<std::unique_ptr
<AST::Expr
>> ();
45 args
.emplace_back (std::move (to_format
));
46 args
.emplace_back (std::move (formatter_fn
));
48 return builder
.call (std::move (path
), std::move (args
));
52 get_trait_name (ffi::FormatSpec format_specifier
)
54 static const std::unordered_map
<std::string
, std::string
> spec_map
= {
55 {"", "Display"}, {"?", "Debug"}, {"e", "LowerExp"},
56 {"E", "UpperExp"}, {"o", "Octal"}, {"p", "Pointer"},
57 {"b", "Binary"}, {"x", "LowerHex"}, {"X", "UpperHex"},
60 auto it
= spec_map
.find (format_specifier
.ty
.to_string ());
62 if (it
== spec_map
.end ())
68 tl::optional
<AST::Fragment
>
69 expand_format_args (AST::FormatArgs
&fmt
,
70 std::vector
<std::unique_ptr
<AST::Token
>> &&tokens
)
72 auto loc
= fmt
.get_locus ();
73 auto builder
= AST::Builder (loc
);
74 auto &arguments
= fmt
.get_arguments ();
76 auto static_pieces
= std::vector
<std::unique_ptr
<AST::Expr
>> ();
78 = std::vector
<std::pair
<std::unique_ptr
<AST::Expr
>, ffi::FormatSpec
>> ();
80 for (const auto &node
: fmt
.get_template ().get_pieces ())
84 case ffi::Piece::Tag::String
:
85 static_pieces
.emplace_back (
86 builder
.literal_string (node
.string
._0
.to_string ()));
88 case ffi::Piece::Tag::NextArgument
: {
89 auto next_argument
= node
.next_argument
._0
;
90 switch (node
.next_argument
._0
.position
.tag
)
92 case ffi::Position::Tag::ArgumentImplicitlyIs
: {
93 auto idx
= next_argument
.position
.argument_implicitly_is
._0
;
94 auto trait
= next_argument
.format
;
95 auto arg
= arguments
.at (idx
);
97 // FIXME(Arthur): This API sucks
98 rust_assert (arg
.get_kind ().kind
99 == AST::FormatArgumentKind::Kind::Normal
);
101 args
.push_back ({arg
.get_expr ().clone_expr (), trait
});
104 case ffi::Position::Tag::ArgumentIs
:
105 case ffi::Position::Tag::ArgumentNamed
:
106 rust_sorry_at (loc
, "unhandled argument position specifier");
114 auto args_array
= std::vector
<std::unique_ptr
<AST::Expr
>> ();
115 for (auto &&arg
: args
)
116 args_array
.emplace_back (format_arg (builder
,
117 builder
.ref (std::move (arg
.first
)),
118 get_trait_name (arg
.second
)));
120 auto pieces
= builder
.ref (builder
.array (std::move (static_pieces
)));
121 auto args_slice
= builder
.ref (builder
.array (std::move (args_array
)));
123 auto final_path
= make_unique
<AST::PathInExpression
> (
124 builder
.path_in_expression ({"core", "fmt", "Arguments", "new_v1"}));
125 auto final_args
= std::vector
<std::unique_ptr
<AST::Expr
>> ();
126 final_args
.emplace_back (std::move (pieces
));
127 final_args
.emplace_back (std::move (args_slice
));
130 = builder
.call (std::move (final_path
), std::move (final_args
));
132 auto node
= AST::SingleASTNode (std::move (final_call
));
134 return AST::Fragment ({node
}, std::move (tokens
));