@@ -34,17 +34,12 @@ make_string (Location locus, std::string value)
34
34
PrimitiveCoreType::CORETYPE_STR, {}, locus));
35
35
}
36
36
37
- /* Parse a single string literal from the given delimited token tree,
38
- and return the LiteralExpr for it. Allow for an optional trailing comma,
39
- but otherwise enforce that these are the only tokens. */
37
+ /* Match the end token of a macro given the start delimiter of the macro */
40
38
41
- std::unique_ptr<AST::LiteralExpr>
42
- parse_single_string_literal (AST::DelimTokenTree &invoc_token_tree,
43
- Location invoc_locus )
39
+ static inline TokenId
40
+ macro_end_token (AST::DelimTokenTree &invoc_token_tree,
41
+ Parser<MacroInvocLexer> &parser )
44
42
{
45
- MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
46
- Parser<MacroInvocLexer> parser (std::move (lex));
47
-
48
43
auto last_token_id = TokenId::RIGHT_CURLY;
49
44
switch (invoc_token_tree.get_delim_type ())
50
45
{
@@ -63,6 +58,22 @@ parse_single_string_literal (AST::DelimTokenTree &invoc_token_tree,
63
58
break ;
64
59
}
65
60
61
+ return last_token_id;
62
+ }
63
+
64
+ /* Parse a single string literal from the given delimited token tree,
65
+ and return the LiteralExpr for it. Allow for an optional trailing comma,
66
+ but otherwise enforce that these are the only tokens. */
67
+
68
+ std::unique_ptr<AST::LiteralExpr>
69
+ parse_single_string_literal (AST::DelimTokenTree &invoc_token_tree,
70
+ Location invoc_locus)
71
+ {
72
+ MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
73
+ Parser<MacroInvocLexer> parser (std::move (lex));
74
+
75
+ auto last_token_id = macro_end_token (invoc_token_tree, parser);
76
+
66
77
std::unique_ptr<AST::LiteralExpr> lit_expr = nullptr ;
67
78
68
79
if (parser.peek_current_token ()->get_id () == STRING_LITERAL)
@@ -252,4 +263,44 @@ MacroBuiltin::compile_error (Location invoc_locus, AST::MacroInvocData &invoc)
252
263
return AST::ASTFragment::create_error ();
253
264
}
254
265
266
+ /* Expand builtin macro concat!(), which joins all the literal parameters
267
+ into a string with no delimiter. */
268
+
269
+ AST::ASTFragment
270
+ MacroBuiltin::concat (Location invoc_locus, AST::MacroInvocData &invoc)
271
+ {
272
+ auto invoc_token_tree = invoc.get_delim_tok_tree ();
273
+ MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
274
+ Parser<MacroInvocLexer> parser (std::move (lex));
275
+ auto str = std::string ();
276
+ bool has_error = false ;
277
+
278
+ auto last_token_id = macro_end_token (invoc_token_tree, parser);
279
+
280
+ /* NOTE: concat! could accept no argument, so we don't have any checks here */
281
+ while (parser.peek_current_token ()->get_id () != last_token_id)
282
+ {
283
+ auto lit_expr = parser.parse_literal_expr ();
284
+ if (lit_expr)
285
+ {
286
+ str += lit_expr->as_string ();
287
+ }
288
+ else
289
+ {
290
+ rust_error_at (parser.peek_current_token ()->get_locus (),
291
+ " argument must be a constant literal" );
292
+ has_error = true ;
293
+ }
294
+ parser.maybe_skip_token (COMMA);
295
+ }
296
+
297
+ parser.skip_token (last_token_id);
298
+
299
+ if (has_error)
300
+ return AST::ASTFragment::create_error ();
301
+
302
+ auto node = AST::SingleASTNode (make_string (invoc_locus, str));
303
+ return AST::ASTFragment ({node});
304
+ }
305
+
255
306
} // namespace Rust
0 commit comments