Branch data Line data Source code
1 : : // Copyright (C) 2024-2025 Free Software Foundation, Inc.
2 : :
3 : : // This file is part of GCC.
4 : :
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.
9 : :
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.
14 : :
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/>.
18 : :
19 : : #ifndef RUST_AST_BUILTIN_NODES_H
20 : : #define RUST_AST_BUILTIN_NODES_H
21 : :
22 : : #include "rust-system.h"
23 : : #include "line-map.h"
24 : : #include "optional.h"
25 : : #include "rust-ast.h"
26 : : #include "rust-fmt.h"
27 : :
28 : : namespace Rust {
29 : : namespace AST {
30 : :
31 : : // Definitions, from rustc's `FormatArgs` AST struct
32 : : // https://github.com/rust-lang/rust/blob/1be468815c/compiler/rustc_ast/src/format.rs
33 : : //
34 : : // format_args!("hello {abc:.xyz$}!!", abc="world");
35 : : // └──────────────────────────────────────────────┘
36 : : // FormatArgs
37 : : //
38 : : // format_args!("hello {abc:.xyz$}!!", abc="world");
39 : : // └─────────┘
40 : : // argument
41 : : //
42 : : // format_args!("hello {abc:.xyz$}!!", abc="world");
43 : : // └───────────────────┘
44 : : // template
45 : : //
46 : : // format_args!("hello {abc:.xyz$}!!", abc="world");
47 : : // └────┘└─────────┘└┘
48 : : // pieces
49 : : //
50 : : // format_args!("hello {abc:.xyz$}!!", abc="world");
51 : : // └────┘ └┘
52 : : // literal pieces
53 : : //
54 : : // format_args!("hello {abc:.xyz$}!!", abc="world");
55 : : // └─────────┘
56 : : // placeholder
57 : : //
58 : : // format_args!("hello {abc:.xyz$}!!", abc="world");
59 : : // └─┘ └─┘
60 : : // positions (could be names, numbers, empty, or `*`)
61 : :
62 : : // FIXME: Merge with the class below this one?
63 : 119 : class FormatArgumentKind
64 : : {
65 : : public:
66 : : enum class Kind
67 : : {
68 : : Normal,
69 : : Named,
70 : : Captured,
71 : : } kind;
72 : :
73 : 0 : Identifier &get_ident ()
74 : : {
75 : 0 : rust_assert (kind == Kind::Captured || kind == Kind::Named);
76 : :
77 : 0 : return ident.value ();
78 : : }
79 : :
80 : 122 : FormatArgumentKind (Kind kind, tl::optional<Identifier> ident)
81 : 244 : : kind (kind), ident (ident)
82 : : {}
83 : :
84 : 428 : FormatArgumentKind (const FormatArgumentKind &other)
85 : 428 : {
86 : 428 : kind = other.kind;
87 : 428 : ident = other.ident;
88 : : }
89 : :
90 : : FormatArgumentKind operator= (const FormatArgumentKind &other)
91 : : {
92 : : kind = other.kind;
93 : : ident = other.ident;
94 : :
95 : : return *this;
96 : : }
97 : :
98 : : private:
99 : : tl::optional<Identifier> ident;
100 : : };
101 : :
102 : : class FormatArgument
103 : : {
104 : : public:
105 : 121 : static FormatArgument normal (std::unique_ptr<Expr> expr)
106 : : {
107 : 121 : return FormatArgument (FormatArgumentKind::Kind::Normal, tl::nullopt,
108 : 121 : std::move (expr));
109 : : }
110 : :
111 : 1 : static FormatArgument named (Identifier ident, std::unique_ptr<Expr> expr)
112 : : {
113 : 1 : return FormatArgument (FormatArgumentKind::Kind::Named, ident,
114 : 2 : std::move (expr));
115 : : }
116 : :
117 : : static FormatArgument captured (Identifier ident, std::unique_ptr<Expr> expr)
118 : : {
119 : : return FormatArgument (FormatArgumentKind::Kind::Captured, ident,
120 : : std::move (expr));
121 : : }
122 : :
123 : 309 : FormatArgument (const FormatArgument &other)
124 : 309 : : kind (other.kind), expr (other.expr->clone_expr ())
125 : 309 : {}
126 : :
127 : : FormatArgument operator= (const FormatArgument &other)
128 : : {
129 : : kind = other.kind;
130 : : expr = other.expr->clone_expr ();
131 : :
132 : : return *this;
133 : : }
134 : :
135 : 119 : FormatArgumentKind get_kind () const { return kind; }
136 : : const Expr &get_expr () const { return *expr; }
137 : 119 : Expr &get_expr () { return *expr; }
138 : :
139 : : private:
140 : 122 : FormatArgument (FormatArgumentKind::Kind kind, tl::optional<Identifier> ident,
141 : : std::unique_ptr<Expr> expr)
142 : 122 : : kind (FormatArgumentKind (kind, ident)), expr (std::move (expr))
143 : 122 : {}
144 : :
145 : : FormatArgumentKind kind;
146 : : std::unique_ptr<Expr> expr;
147 : : };
148 : :
149 : 152 : class FormatArguments
150 : : {
151 : : public:
152 : 76 : FormatArguments () {}
153 : 76 : FormatArguments (FormatArguments &&) = default;
154 : 0 : FormatArguments (const FormatArguments &other)
155 : 0 : {
156 : 0 : args = std::vector<FormatArgument> ();
157 : 0 : args.reserve (other.args.size ());
158 : :
159 : 0 : for (const auto &arg : other.args)
160 : 0 : args.emplace_back (arg);
161 : 0 : };
162 : :
163 : : FormatArguments &operator= (const FormatArguments &other) = default;
164 : :
165 : 122 : void push (FormatArgument &&elt) { args.emplace_back (std::move (elt)); }
166 : 119 : const FormatArgument at (size_t idx) const { return args.at (idx); }
167 : :
168 : : const std::vector<FormatArgument> &get_args () const { return args; }
169 : 0 : std::vector<FormatArgument> &get_args () { return args; }
170 : : size_t size () const { return args.size (); }
171 : 0 : bool empty () const { return args.empty (); }
172 : :
173 : : private:
174 : : std::vector<FormatArgument> args;
175 : : };
176 : :
177 : : // TODO: Format documentation better
178 : : // Having a separate AST node for `format_args!()` expansion allows some
179 : : // important optimizations which help reduce generated code a lot. For example,
180 : : // turning `format_args!("a {} {} {}", 15, "hey", 'a')` directly into
181 : : // `format_args!("a 15 hey a")`, since all arguments are literals. Or,
182 : : // flattening imbricated `format_args!()` calls: `format_args!("heyo {}",
183 : : // format_args!("result: {}", some_result))` -> `format_args!("heyo result: {}",
184 : : // some_result)`
185 : : // FIXME: Move to rust-macro.h
186 : : class FormatArgs : public Expr
187 : : {
188 : : public:
189 : : enum class Newline
190 : : {
191 : : Yes,
192 : : No
193 : : };
194 : :
195 : 76 : FormatArgs (location_t loc, Fmt::Pieces &&template_str,
196 : : FormatArguments &&arguments)
197 : 152 : : loc (loc), template_pieces (std::move (template_str)),
198 : 76 : arguments (std::move (arguments))
199 : 76 : {}
200 : :
201 : : FormatArgs (FormatArgs &&other) = default;
202 : 0 : FormatArgs (const FormatArgs &other) = default;
203 : : FormatArgs &operator= (const FormatArgs &other) = default;
204 : :
205 : : void accept_vis (AST::ASTVisitor &vis) override;
206 : :
207 : 76 : const Fmt::Pieces &get_template () const { return template_pieces; }
208 : : const FormatArguments &get_arguments () const { return arguments; }
209 : 76 : FormatArguments &get_arguments () { return arguments; }
210 : : virtual location_t get_locus () const override;
211 : :
212 : 0 : Expr::Kind get_expr_kind () const override { return Expr::Kind::FormatArgs; }
213 : :
214 : : private:
215 : : location_t loc;
216 : : // FIXME: This probably needs to be a separate type - it is one in rustc's
217 : : // expansion of format_args!(). There is extra handling associated with it.
218 : : // we can maybe do that in rust-fmt.cc? in collect_pieces()? like do the
219 : : // transformation into something we can handle better
220 : : Fmt::Pieces template_pieces;
221 : : FormatArguments arguments;
222 : :
223 : : bool marked_for_strip = false;
224 : :
225 : : protected:
226 : : virtual std::string as_string () const override;
227 : : virtual bool is_expr_without_block () const override;
228 : : virtual void mark_for_strip () override;
229 : : virtual bool is_marked_for_strip () const override;
230 : : virtual std::vector<Attribute> &get_outer_attrs () override;
231 : : virtual void set_outer_attrs (std::vector<Attribute>) override;
232 : : virtual Expr *clone_expr_impl () const override;
233 : : };
234 : :
235 : : /**
236 : : * The node associated with the builtin offset_of!() macro
237 : : */
238 : : class OffsetOf : public Expr
239 : : {
240 : : public:
241 : 16 : OffsetOf (std::unique_ptr<Type> &&type, Identifier field, location_t loc)
242 : 16 : : type (std::move (type)), field (field), loc (loc)
243 : 16 : {}
244 : :
245 : 96 : OffsetOf (const OffsetOf &other)
246 : 96 : : type (other.type->clone_type ()), field (other.field), loc (other.loc),
247 : 96 : marked_for_strip (other.marked_for_strip)
248 : 96 : {}
249 : :
250 : : OffsetOf &operator= (const OffsetOf &other)
251 : : {
252 : : type = other.type->clone_type ();
253 : : field = other.field;
254 : : loc = other.loc;
255 : : marked_for_strip = other.marked_for_strip;
256 : :
257 : : return *this;
258 : : }
259 : :
260 : : void accept_vis (AST::ASTVisitor &vis) override;
261 : :
262 : 30 : virtual location_t get_locus () const override { return loc; }
263 : : const Type &get_type () const { return *type; }
264 : 154 : Type &get_type () { return *type; }
265 : 30 : std::unique_ptr<Type> &get_type_ptr () { return type; }
266 : 15 : const Identifier &get_field () const { return field; }
267 : :
268 : 0 : bool is_expr_without_block () const override { return false; }
269 : :
270 : 0 : void mark_for_strip () override { marked_for_strip = true; }
271 : 30 : bool is_marked_for_strip () const override { return marked_for_strip; }
272 : :
273 : : std::string as_string () const override;
274 : :
275 : : std::vector<Attribute> &get_outer_attrs () override;
276 : : void set_outer_attrs (std::vector<Attribute>) override;
277 : : Expr *clone_expr_impl () const override;
278 : :
279 : 15 : Expr::Kind get_expr_kind () const override { return Expr::Kind::OffsetOf; }
280 : :
281 : : private:
282 : : std::unique_ptr<Type> type;
283 : : Identifier field;
284 : :
285 : : location_t loc;
286 : : bool marked_for_strip = false;
287 : : };
288 : :
289 : : } // namespace AST
290 : : } // namespace Rust
291 : :
292 : : #endif // ! RUST_AST_BUILTIN_NODES_H
|