aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/expand/rust-macro-builtins.cc
diff options
context:
space:
mode:
authorArthur Cohen <arthur.cohen@embecosm.com>2024-02-16 18:27:22 +0100
committerCohenArthur <arthur.cohen@embecosm.com>2024-03-01 15:42:36 +0000
commitafed72d7137afe4ab4c7db44262379ba6dda4eb9 (patch)
tree24d8b8c13d34bd86db7094b134e19e255def747e /gcc/rust/expand/rust-macro-builtins.cc
parent38e3cffdbdee48cc4793948f1551b075672f6fdd (diff)
downloadgcc-afed72d7137afe4ab4c7db44262379ba6dda4eb9.zip
gcc-afed72d7137afe4ab4c7db44262379ba6dda4eb9.tar.gz
gcc-afed72d7137afe4ab4c7db44262379ba6dda4eb9.tar.bz2
format-args: Fix Rust interface and add input parsing.
gcc/rust/ChangeLog: * Make-lang.in: Do not build Rust library in release mode. * ast/rust-ast.cc: Make FormatArgs inherit from AST::Expr * ast/rust-builtin-ast-nodes.h: Improve FormatArg* nodes and helpers. * ast/rust-fmt.cc (Pieces::collect): Fix interface to match FFI function. * ast/rust-fmt.h (collect_pieces): Likewise. (struct Pieces): Add append_newline parameter. * expand/rust-macro-builtins.cc: Add proper parsing of format_args input. * hir/rust-ast-lower-base.cc: Include diagnostics header. libgrust/ChangeLog: * libformat_parser/src/lib.rs: Switch interface to use more parser parameters. * libformat_parser/src/bin.rs: Use new interface.
Diffstat (limited to 'gcc/rust/expand/rust-macro-builtins.cc')
-rw-r--r--gcc/rust/expand/rust-macro-builtins.cc182
1 files changed, 141 insertions, 41 deletions
diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc
index 9e6716c..b42d1ec 100644
--- a/gcc/rust/expand/rust-macro-builtins.cc
+++ b/gcc/rust/expand/rust-macro-builtins.cc
@@ -16,6 +16,7 @@
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+#include "expected.h"
#include "libproc_macro_internal/tokenstream.h"
#include "rust-ast-full-decls.h"
#include "rust-builtin-ast-nodes.h"
@@ -35,6 +36,7 @@
#include "rust-session-manager.h"
#include "rust-attribute-values.h"
#include "rust-fmt.h"
+#include "rust-token.h"
namespace Rust {
@@ -956,34 +958,116 @@ MacroBuiltin::stringify_handler (location_t invoc_locus,
return AST::Fragment ({node}, std::move (token));
}
-tl::optional<AST::Fragment>
-MacroBuiltin::format_args_handler (location_t invoc_locus,
- AST::MacroInvocData &invoc,
- AST::FormatArgs::Newline nl)
+struct FormatArgsInput
{
- // Remove the delimiters from the macro invocation:
- // the invoc data for `format_args!(fmt, arg1, arg2)` is `(fmt, arg1, arg2)`,
- // so we pop the front and back to remove the parentheses (or curly brackets,
- // or brackets)
- auto tokens = invoc.get_delim_tok_tree ().to_token_stream ();
- tokens.erase (tokens.begin ());
- tokens.pop_back ();
+ std::unique_ptr<AST::Expr> format_str;
+ AST::FormatArguments args;
+ // bool is_literal?
+};
- auto append_newline = nl == AST::FormatArgs::Newline::Yes ? true : false;
- auto fmt_arg
- = parse_single_string_literal (append_newline ? BuiltinMacro::FormatArgsNl
- : BuiltinMacro::FormatArgs,
- invoc.get_delim_tok_tree (), invoc_locus,
- invoc.get_expander ());
+struct FormatArgsParseError
+{
+ enum class Kind
+ {
+ MissingArguments
+ } kind;
+};
+
+static tl::expected<FormatArgsInput, FormatArgsParseError>
+format_args_parse_arguments (AST::MacroInvocData &invoc)
+{
+ MacroInvocLexer lex (invoc.get_delim_tok_tree ().to_token_stream ());
+ Parser<MacroInvocLexer> parser (lex);
+
+ // TODO: check if EOF - return that format_args!() requires at least one
+ // argument
- if (!fmt_arg->is_literal ())
+ auto args = AST::FormatArguments ();
+ auto last_token_id = macro_end_token (invoc.get_delim_tok_tree (), parser);
+ std::unique_ptr<AST::Expr> format_str = nullptr;
+
+ // TODO: Handle the case where we're not parsing a string literal (macro
+ // invocation for e.g.)
+ if (parser.peek_current_token ()->get_id () == STRING_LITERAL)
+ format_str = parser.parse_literal_expr ();
+
+ // TODO: Allow implicit captures ONLY if the the first arg is a string literal
+ // and not a macro invocation
+
+ // TODO: How to consume all of the arguments until the delimiter?
+
+ // TODO: What we then want to do is as follows:
+ // for each token, check if it is an identifier
+ // yes? is the next token an equal sign (=)
+ // yes?
+ // -> if that identifier is already present in our map, error
+ // out
+ // -> parse an expression, return a FormatArgument::Named
+ // no?
+ // -> if there have been named arguments before, error out
+ // (positional after named error)
+ // -> parse an expression, return a FormatArgument::Normal
+ while (parser.peek_current_token ()->get_id () != last_token_id)
{
- rust_sorry_at (
- invoc_locus,
- "cannot yet use eager macro invocations as format strings");
- return AST::Fragment::create_empty ();
+ parser.skip_token (COMMA);
+
+ if (parser.peek_current_token ()->get_id () == IDENTIFIER
+ && parser.peek (1)->get_id () == EQUAL)
+ {
+ // FIXME: This is ugly - just add a parser.parse_identifier()?
+ auto ident_tok = parser.peek_current_token ();
+ auto ident = Identifier (ident_tok);
+
+ parser.skip_token (IDENTIFIER);
+ parser.skip_token (EQUAL);
+
+ auto expr = parser.parse_expr ();
+
+ // TODO: Handle graciously
+ if (!expr)
+ rust_unreachable ();
+
+ args.push (AST::FormatArgument::named (ident, std::move (expr)));
+ }
+ else
+ {
+ auto expr = parser.parse_expr ();
+
+ // TODO: Handle graciously
+ if (!expr)
+ rust_unreachable ();
+
+ args.push (AST::FormatArgument::normal (std::move (expr)));
+ }
+ // we need to skip commas, don't we?
}
+ return FormatArgsInput{std::move (format_str), std::move (args)};
+}
+
+tl::optional<AST::Fragment>
+MacroBuiltin::format_args_handler (location_t invoc_locus,
+ AST::MacroInvocData &invoc,
+ AST::FormatArgs::Newline nl)
+{
+ auto input = format_args_parse_arguments (invoc);
+
+ // auto fmt_arg
+ // // FIXME: this eneds to be split up into a smaller function
+ // = parse_single_string_literal (append_newline ?
+ // BuiltinMacro::FormatArgsNl
+ // : BuiltinMacro::FormatArgs,
+ // invoc.get_delim_tok_tree (), invoc_locus,
+ // invoc.get_expander ());
+
+ // if (!fmt_arg->is_literal ())
+ // {
+ // rust_sorry_at (
+ // invoc_locus,
+ // "cannot yet use eager macro invocations as format strings");
+ // return AST::Fragment::create_empty ();
+ // }
+
// FIXME: We need to handle this
// // if it is not a literal, it's an eager macro invocation - return it
// if (!fmt_expr->is_literal ())
@@ -993,38 +1077,54 @@ MacroBuiltin::format_args_handler (location_t invoc_locus,
// token_tree.to_token_stream ());
// }
- auto fmt_str = static_cast<AST::LiteralExpr &> (*fmt_arg.get ());
+ // auto fmt_str = static_cast<AST::LiteralExpr &> (*fmt_arg.get ());
// Switch on the format string to know if the string is raw or cooked
- switch (fmt_str.get_lit_type ())
- {
- // case AST::Literal::RAW_STRING:
- case AST::Literal::STRING:
- break;
- case AST::Literal::CHAR:
- case AST::Literal::BYTE:
- case AST::Literal::BYTE_STRING:
- case AST::Literal::INT:
- case AST::Literal::FLOAT:
- case AST::Literal::BOOL:
- case AST::Literal::ERROR:
- rust_unreachable ();
- }
+ // switch (fmt_str.get_lit_type ())
+ // {
+ // // case AST::Literal::RAW_STRING:
+ // case AST::Literal::STRING:
+ // break;
+ // case AST::Literal::CHAR:
+ // case AST::Literal::BYTE:
+ // case AST::Literal::BYTE_STRING:
+ // case AST::Literal::INT:
+ // case AST::Literal::FLOAT:
+ // case AST::Literal::BOOL:
+ // case AST::Literal::ERROR:
+ // rust_unreachable ();
+ // }
+
+ // Remove the delimiters from the macro invocation:
+ // the invoc data for `format_args!(fmt, arg1, arg2)` is `(fmt, arg1, arg2)`,
+ // so we pop the front and back to remove the parentheses (or curly brackets,
+ // or brackets)
+ auto tokens = invoc.get_delim_tok_tree ().to_token_stream ();
+ tokens.erase (tokens.begin ());
+ tokens.pop_back ();
std::stringstream stream;
for (const auto &tok : tokens)
stream << tok->as_string () << ' ';
- rust_debug ("[ARTHUR]: `%s`", stream.str ().c_str ());
-
- auto pieces = Fmt::Pieces::collect (stream.str ());
+ auto append_newline = nl == AST::FormatArgs::Newline::Yes ? true : false;
+ auto pieces = Fmt::Pieces::collect (stream.str (), append_newline);
// TODO:
// do the transformation into an AST::FormatArgs node
// return that
// expand it during lowering
- return AST::Fragment::create_empty ();
+ // TODO: we now need to take care of creating `unfinished_literal`? this is
+ // for creating the `template`
+
+ auto fmt_args_node = new AST::FormatArgs (invoc_locus, std::move (pieces),
+ std::move (input->args));
+ auto node = std::unique_ptr<AST::Expr> (fmt_args_node);
+ auto single_node = AST::SingleASTNode (std::move (node));
+
+ return AST::Fragment ({std::move (single_node)},
+ invoc.get_delim_tok_tree ().to_token_stream ());
}
tl::optional<AST::Fragment>