libcpp, c, middle-end: Optimize initializers using #embed in C
[official-gcc.git] / gcc / rust / expand / rust-expand-format-args.cc
blob3f76344ea5bfc886b2f8308624690f2eb6beaa67
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
8 // version.
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.
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"
21 #include "rust-ast.h"
22 #include "rust-builtin-ast-nodes.h"
23 #include "rust-ast-builder.h"
24 #include "rust-diagnostics.h"
25 #include "rust-expr.h"
26 #include "rust-fmt.h"
27 #include "rust-path.h"
28 #include "rust-system.h"
29 #include "rust-token.h"
31 namespace Rust {
32 namespace Fmt {
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));
51 const std::string &
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 ())
63 rust_unreachable ();
65 return it->second;
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>> ();
77 auto args
78 = std::vector<std::pair<std::unique_ptr<AST::Expr>, ffi::FormatSpec>> ();
80 for (const auto &node : fmt.get_template ().get_pieces ())
82 switch (node.tag)
84 case ffi::Piece::Tag::String:
85 static_pieces.emplace_back (
86 builder.literal_string (node.string._0.to_string ()));
87 break;
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});
103 break;
104 case ffi::Position::Tag::ArgumentIs:
105 case ffi::Position::Tag::ArgumentNamed:
106 rust_sorry_at (loc, "unhandled argument position specifier");
107 break;
110 break;
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));
129 auto final_call
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));
137 } // namespace Fmt
138 } // namespace Rust