From patchwork Thu Aug 1 14:56:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 1967764 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=embecosm.com header.i=@embecosm.com header.a=rsa-sha256 header.s=google header.b=T6F9Dpte; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WZXcj0hPwz1yZv for ; Fri, 2 Aug 2024 01:16:53 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5F5F03861018 for ; Thu, 1 Aug 2024 15:16:51 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-ed1-x530.google.com (mail-ed1-x530.google.com [IPv6:2a00:1450:4864:20::530]) by sourceware.org (Postfix) with ESMTPS id D1C75385C6C3 for ; Thu, 1 Aug 2024 14:58:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D1C75385C6C3 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org D1C75385C6C3 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a00:1450:4864:20::530 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722524357; cv=none; b=azYato8ksdaz1FAK4PTIcPvUA281n2hTwilRxCqQwbUOdv2dxe81To68xqmqtJqWT1B/MWhOkeCjcFkqdmFjLxBWhWHDNItSFaYP/n96sxlVHfPZy6O6XSEvhLKOEE0MPnjgEeZcgdAEVBloCz0p5qap9lkeCDyGhn1IUemkHcI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722524357; c=relaxed/simple; bh=hE2fNLFZu/OspAxKxK3BexofSoNU4P0XJbSacXm6BpQ=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=qgyFfT3lIaQl+VhvL4PeSGTQgnj1Zq81BDWezmMZNlLX3JgdRfvdmAndj1kS8HhEoTbHQageOjTdghcxsDwuH9SfSB8QT+EWkEY3DFSb9m4pdXW0D7yh25FGf6FHHMXP7Y+DXSzvr4alx/mbHuo1m6g/Me96tF7W3t7j0gO1/Mo= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-ed1-x530.google.com with SMTP id 4fb4d7f45d1cf-5a10835480bso10291864a12.2 for ; Thu, 01 Aug 2024 07:58:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; t=1722524335; x=1723129135; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=zCS8mYKDydcLnPC7q4u4Fvf6oneqI6f8XZQuQ6htjVg=; b=T6F9DpteRG8WAF56R86OhNIy+3jtPm3zz4wLF7sgXOJ+9OLHAxT+VKP9dXTzxb+/4A CuhxyFPDgnXNt2cEDxq+WAsGcdsAhUe/Mw2yHATnvChqqnKzpBw8H4pyKIthhDSaBw4P b0OChCy1XsPWIr4VPhg5T4Y88PF+hhNPlgDzIXoPFpN9q8NCo1sJQ8FC2WfNyZG9boE3 ZnW2aMp5PV8OtER+OBAZztWOzGWZTHNl5a3iEP3Vczi6e5UklSg2LGc6Icf5utSOlKkJ Y0+kPl3YFOEA+/pp77e5b+pkMp4C0jcx7ww5oQu4rSyofTKAAxdfWWXH8hOvmDzRUx0u Tu2w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722524335; x=1723129135; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=zCS8mYKDydcLnPC7q4u4Fvf6oneqI6f8XZQuQ6htjVg=; b=eDolVH8wFb/Rd8Pf8D0aTfo5/NFt/vXKYFP/kN4voXTY1fEHzBKTMlOaiJlwmMZEnm 5JTPCsHPtEGwSB9U/v1PYusV8KZBQutSyvZh5MopYrjozC2Mfsj30SHEMc3vxx6jO6rY lXN2bJO9BwdbuqjIHlGBE8fkchLF39QD4gQ9TE4FfiV9/dmP9Ke16wJ9RwuT8s52kxU7 BKY4/UKzWLI85pe936seRB2iG6i/mAFnNSyzX81nrv39SQJh1/e63S2pvjo6FfexCFVN jQcPJhj8eMzWncmq9tnQNd7hvaSrnWBqbQ1aE+684HoKLUbqqQY9yotQHzBSrzd74H20 hJoQ== X-Gm-Message-State: AOJu0YwVHnQb4YpqK4I5lmvBKsTjNCGCdwyPBkkrPZ/EF3qkYaM4szyM Wy4fsVzpd+3G9bYVnBPbJId3J1zTrLcZQx4o+ITK/fMa1kYXaIaOgGlZHe1Vgp6j9i1DlhjbI8m LiE+p X-Google-Smtp-Source: AGHT+IHq9dSyeLA+ub+/0JL+Ck4ZZndbXnhhpYddKN2ncyJCD5sYsQdAGCM3sXOeOmrrNU2UkCNuEw== X-Received: by 2002:aa7:cad6:0:b0:5a3:3b44:ae00 with SMTP id 4fb4d7f45d1cf-5b7f3eba08amr476951a12.20.1722524335053; Thu, 01 Aug 2024 07:58:55 -0700 (PDT) Received: from platypus.lan ([2a04:cec2:9:dc84:3622:6733:ff49:ee91]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5ac63590592sm10252456a12.25.2024.08.01.07.58.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 Aug 2024 07:58:54 -0700 (PDT) From: Arthur Cohen To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, Arthur Cohen Subject: [PATCH 031/125] gccrs: format-args: Fix Rust interface and add input parsing. Date: Thu, 1 Aug 2024 16:56:27 +0200 Message-ID: <20240801145809.366388-33-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240801145809.366388-2-arthur.cohen@embecosm.com> References: <20240801145809.366388-2-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-12.6 required=5.0 tests=BAYES_00, BODY_8BITS, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org gcc/rust/ChangeLog: * 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. --- gcc/rust/ast/rust-ast.cc | 51 +++++++ gcc/rust/ast/rust-builtin-ast-nodes.h | 133 ++++++++++++++++-- gcc/rust/ast/rust-fmt.cc | 38 +++++- gcc/rust/ast/rust-fmt.h | 21 ++- gcc/rust/expand/rust-macro-builtins.cc | 182 +++++++++++++++++++------ gcc/rust/hir/rust-ast-lower-base.cc | 1 + libgrust/libformat_parser/src/bin.rs | 5 +- libgrust/libformat_parser/src/lib.rs | 63 ++++++--- 8 files changed, 416 insertions(+), 78 deletions(-) diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc index 5d571b46622..f3dabc6cd0f 100644 --- a/gcc/rust/ast/rust-ast.cc +++ b/gcc/rust/ast/rust-ast.cc @@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see #include "rust-ast.h" #include "optional.h" +#include "rust-builtin-ast-nodes.h" #include "rust-system.h" #include "rust-ast-full.h" #include "rust-diagnostics.h" @@ -5054,6 +5055,56 @@ FormatArgs::accept_vis (ASTVisitor &vis) vis.visit (*this); } +std::string +FormatArgs::as_string () const +{ + // FIXME(Arthur): Improve + return "FormatArgs"; +} + +location_t +FormatArgs::get_locus () const +{ + rust_unreachable (); +} + +bool +FormatArgs::is_expr_without_block () const +{ + return false; +} + +void +FormatArgs::mark_for_strip () +{ + marked_for_strip = true; +} + +bool +FormatArgs::is_marked_for_strip () const +{ + return marked_for_strip; +} + +std::vector & +FormatArgs::get_outer_attrs () +{ + rust_unreachable (); +} + +void FormatArgs::set_outer_attrs (std::vector) +{ + rust_unreachable (); +} + +Expr * +FormatArgs::clone_expr_impl () const +{ + std::cerr << "[ARTHUR] cloning FormatArgs! " << std::endl; + + return new FormatArgs (*this); +} + } // namespace AST std::ostream & diff --git a/gcc/rust/ast/rust-builtin-ast-nodes.h b/gcc/rust/ast/rust-builtin-ast-nodes.h index 3998fbfb4a7..6e267173a55 100644 --- a/gcc/rust/ast/rust-builtin-ast-nodes.h +++ b/gcc/rust/ast/rust-builtin-ast-nodes.h @@ -59,9 +59,17 @@ namespace AST { // └─┘ └─┘ // positions (could be names, numbers, empty, or `*`) +// FIXME: Merge with the class below this one? class FormatArgumentKind { public: + enum class Kind + { + Normal, + Named, + Captured, + } kind; + Identifier &get_ident () { rust_assert (kind == Kind::Captured || kind == Kind::Named); @@ -69,25 +77,90 @@ public: return ident.value (); } -private: - enum class Kind + FormatArgumentKind (Kind kind, tl::optional ident) + : kind (kind), ident (ident) + {} + + FormatArgumentKind (const FormatArgumentKind &other) { - Normal, - Named, - Captured, - } kind; + kind = other.kind; + ident = other.ident; + } + + FormatArgumentKind operator= (const FormatArgumentKind &other) + { + kind = other.kind; + ident = other.ident; + return *this; + } + +private: tl::optional ident; }; class FormatArgument { +public: + static FormatArgument normal (std::unique_ptr expr) + { + return FormatArgument (FormatArgumentKind::Kind::Normal, tl::nullopt, + std::move (expr)); + } + + static FormatArgument named (Identifier ident, std::unique_ptr expr) + { + return FormatArgument (FormatArgumentKind::Kind::Named, ident, + std::move (expr)); + } + + static FormatArgument captured (Identifier ident, std::unique_ptr expr) + { + return FormatArgument (FormatArgumentKind::Kind::Captured, ident, + std::move (expr)); + } + + FormatArgument (const FormatArgument &other) + : kind (other.kind), expr (other.expr->clone_expr ()) + {} + + FormatArgument operator= (const FormatArgument &other) + { + kind = other.kind; + expr = other.expr->clone_expr (); + + return *this; + } + +private: + FormatArgument (FormatArgumentKind::Kind kind, tl::optional ident, + std::unique_ptr expr) + : kind (FormatArgumentKind (kind, ident)), expr (std::move (expr)) + {} + FormatArgumentKind kind; std::unique_ptr expr; }; class FormatArguments { +public: + FormatArguments () {} + FormatArguments (FormatArguments &&) = default; + FormatArguments (const FormatArguments &other) + { + args = std::vector (); + args.reserve (other.args.size ()); + + for (const auto &arg : other.args) + args.emplace_back (arg); + }; + + FormatArguments &operator= (const FormatArguments &other) = default; + + void push (FormatArgument &&elt) { args.emplace_back (std::move (elt)); } + +private: std::vector args; }; @@ -100,7 +173,7 @@ class FormatArguments // format_args!("result: {}", some_result))` -> `format_args!("heyo result: {}", // some_result)` // FIXME: Move to rust-macro.h -class FormatArgs : public Visitable +class FormatArgs : public Expr { public: enum class Newline @@ -109,18 +182,56 @@ public: No }; - FormatArgs (location_t loc, Fmt::PieceSlice template_str, - FormatArguments arguments) + FormatArgs (location_t loc, Fmt::Pieces &&template_str, + FormatArguments &&arguments) : loc (loc), template_str (std::move (template_str)), arguments (std::move (arguments)) {} - void accept_vis (AST::ASTVisitor &vis); + FormatArgs (FormatArgs &&other) + : loc (std::move (other.loc)), + template_str (std::move (other.template_str)), + arguments (std::move (other.arguments)) + { + std::cerr << "[ARTHUR] moving FormatArgs" << std::endl; + } + + // FIXME: This might be invalid - we are reusing the same memory allocated + // on the Rust side for `other`. This is probably valid as long as we only + // ever read that memory and never write to it. + FormatArgs (const FormatArgs &other) + : loc (other.loc), template_str (other.template_str), + arguments (other.arguments) + { + std::cerr << "[ARTHUR] copying FormatArgs" << std::endl; + } + + // FormatArgs &operator= (const FormatArgs &other) = default; + // : template_str (other.template_str), arguments (other.arguments) + // {} + + void accept_vis (AST::ASTVisitor &vis) override; private: location_t loc; - Fmt::PieceSlice template_str; + // FIXME: This probably needs to be a separate type - it is one in rustc's + // expansion of format_args!(). There is extra handling associated with it. + // we can maybe do that in rust-fmt.cc? in collect_pieces()? like do the + // transformation into something we can handle better + Fmt::Pieces template_str; FormatArguments arguments; + + bool marked_for_strip = false; + +protected: + virtual std::string as_string () const override; + virtual location_t get_locus () const override; + virtual bool is_expr_without_block () const override; + virtual void mark_for_strip () override; + virtual bool is_marked_for_strip () const override; + virtual std::vector &get_outer_attrs () override; + virtual void set_outer_attrs (std::vector) override; + virtual Expr *clone_expr_impl () const override; }; } // namespace AST diff --git a/gcc/rust/ast/rust-fmt.cc b/gcc/rust/ast/rust-fmt.cc index 511e94740c5..c367e30d546 100644 --- a/gcc/rust/ast/rust-fmt.cc +++ b/gcc/rust/ast/rust-fmt.cc @@ -23,9 +23,9 @@ namespace Rust { namespace Fmt { Pieces -Pieces::collect (std::string &&to_parse) +Pieces::collect (std::string &&to_parse, bool append_newline) { - auto piece_slice = collect_pieces (to_parse.c_str ()); + auto piece_slice = collect_pieces (to_parse.c_str (), append_newline); rust_debug ("[ARTHUR] %p, %lu", (const void *) piece_slice.base_ptr, piece_slice.len); @@ -37,7 +37,39 @@ Pieces::collect (std::string &&to_parse) return Pieces (piece_slice, std::move (to_parse)); } -Pieces::~Pieces () { destroy_pieces (slice); } +Pieces::~Pieces () +{ + std::cerr << "Arthur: destoying pieces. this: " << (void *) this + << " slice: " << slice.base_ptr << std::endl; + destroy_pieces (slice); +} + +Pieces::Pieces (const Pieces &other) : to_parse (other.to_parse) +{ + slice = clone_pieces (other.slice.base_ptr, other.slice.len, other.slice.cap); + std::cerr << "Arthur: copying pieces: other.to_parse: " + << (void *) other.to_parse.c_str () + << " ours to_parse: " << (void *) to_parse.c_str () << std::endl; + // auto pieces = std::vector (slice.base_ptr, slice.base_ptr + slice.len); +} + +Pieces & +Pieces::operator= (const Pieces &other) +{ + slice = clone_pieces (other.slice.base_ptr, other.slice.len, other.slice.cap); + to_parse = other.to_parse; + + return *this; +} + +Pieces::Pieces (Pieces &&other) + : slice ( + clone_pieces (other.slice.base_ptr, other.slice.len, other.slice.cap)), + to_parse (std::move (other.to_parse)) +{ + std::cerr << "Arthur: moving pieces. to_parse: " << (void *) to_parse.c_str () + << " base_ptr/slice: " << (void *) slice.base_ptr << std::endl; +} } // namespace Fmt } // namespace Rust diff --git a/gcc/rust/ast/rust-fmt.h b/gcc/rust/ast/rust-fmt.h index 0bf9695bb6d..22447c4eba0 100644 --- a/gcc/rust/ast/rust-fmt.h +++ b/gcc/rust/ast/rust-fmt.h @@ -222,7 +222,7 @@ struct Piece struct NextArgument_Body { - const Argument *_0; + Argument _0; }; Tag tag; @@ -243,7 +243,10 @@ struct PieceSlice extern "C" { PieceSlice -collect_pieces (const char *input); +collect_pieces (const char *input, bool append_newline); + +PieceSlice +clone_pieces (const Piece *base_ptr, size_t len, size_t cap); void destroy_pieces (PieceSlice); @@ -251,9 +254,21 @@ void destroy_pieces (PieceSlice); struct Pieces { - static Pieces collect (std::string &&to_parse); + static Pieces collect (std::string &&to_parse, bool append_newline); ~Pieces (); + Pieces (const Pieces &other); + Pieces &operator= (const Pieces &other); + + Pieces (Pieces &&other); + + // { + // slice = clone_pieces (&other.slice); + // to_parse = other.to_parse; + + // return *this; + // } + private: Pieces (PieceSlice slice, std::string &&to_parse) : slice (slice), to_parse (std::move (to_parse)) diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc index 9e6716c5975..b42d1ec9367 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 // . +#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 -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 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 +format_args_parse_arguments (AST::MacroInvocData &invoc) +{ + MacroInvocLexer lex (invoc.get_delim_tok_tree ().to_token_stream ()); + Parser 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 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 +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 (*fmt_arg.get ()); + // auto fmt_str = static_cast (*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 (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 diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index fa37d62d026..54c05208e7b 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -22,6 +22,7 @@ #include "rust-ast-lower-extern.h" #include "rust-ast.h" #include "rust-attribute-values.h" +#include "rust-diagnostics.h" #include "rust-item.h" #include "rust-system.h" diff --git a/libgrust/libformat_parser/src/bin.rs b/libgrust/libformat_parser/src/bin.rs index 4b1f903ad5f..5f46497c946 100644 --- a/libgrust/libformat_parser/src/bin.rs +++ b/libgrust/libformat_parser/src/bin.rs @@ -2,6 +2,9 @@ use libformat_parser::rust; fn main() { dbg!(rust::collect_pieces( - std::env::args().nth(1).unwrap().as_str() + std::env::args().nth(1).unwrap().as_str(), + None, + None, + false )); } diff --git a/libgrust/libformat_parser/src/lib.rs b/libgrust/libformat_parser/src/lib.rs index c164578a103..6bf78c4f2a8 100644 --- a/libgrust/libformat_parser/src/lib.rs +++ b/libgrust/libformat_parser/src/lib.rs @@ -77,20 +77,15 @@ mod ffi { /// A piece is a portion of the format string which represents the next part /// to emit. These are emitted as a stream by the `Parser` class. - #[derive(Clone, Debug, PartialEq)] + #[derive(Debug, Clone, PartialEq)] #[repr(C)] pub enum Piece<'a> { /// A literal string which should directly be emitted String(&'a str), /// This describes that formatting should process the next argument (as /// specified inside) for emission. - NextArgument(*const Argument<'a>), - } - - impl<'a> Drop for Piece<'a> { - fn drop(&mut self) { - println!("dropping Piece: {:?}", self) - } + // do we need a pointer here? we're doing big cloning anyway + NextArgument(Argument<'a>), } /// Representation of an argument specification. @@ -216,7 +211,7 @@ mod ffi { let ptr = Box::leak(x); let dst = Into::::into(*ptr); - Piece::NextArgument(&dst as *const Argument) + Piece::NextArgument(dst) } } } @@ -321,8 +316,13 @@ mod ffi { pub mod rust { use generic_format_parser::{ParseMode, Parser, Piece}; - pub fn collect_pieces(input: &str) -> Vec> { - let parser = Parser::new(input, None, None, true, ParseMode::Format); + pub fn collect_pieces( + input: &str, + style: Option, + snippet: Option, + append_newline: bool, + ) -> Vec> { + let parser = Parser::new(input, style, snippet, append_newline, ParseMode::Format); parser.into_iter().collect() } @@ -337,16 +337,18 @@ pub struct PieceSlice { } #[no_mangle] -pub extern "C" fn collect_pieces(input: *const libc::c_char) -> PieceSlice { +pub extern "C" fn collect_pieces(input: *const libc::c_char, append_newline: bool) -> PieceSlice { + dbg!(input); + // FIXME: Add comment let str = unsafe { CStr::from_ptr(input) }; - dbg!(str); // FIXME: No unwrap - let pieces: Vec> = rust::collect_pieces(str.to_str().unwrap()) - .into_iter() - .map(Into::into) - .collect(); + let pieces: Vec> = + rust::collect_pieces(str.to_str().unwrap(), None, None, append_newline) + .into_iter() + .map(Into::into) + .collect(); println!("[ARTHUR]: debug: {:?}, {:?}", pieces.as_ptr(), pieces.len()); @@ -358,6 +360,29 @@ pub extern "C" fn collect_pieces(input: *const libc::c_char) -> PieceSlice { } #[no_mangle] -pub extern "C" fn destroy_pieces(PieceSlice { base_ptr, len, cap }: PieceSlice) { - let _ = unsafe { Vec::from_raw_parts(base_ptr, len, cap) }; +pub unsafe extern "C" fn destroy_pieces(PieceSlice { base_ptr, len, cap }: PieceSlice) { + eprintln!("[ARTHUR] destroying pieces: {base_ptr:?} {len} {cap}"); + drop(Vec::from_raw_parts(base_ptr, len, cap)); +} + +#[no_mangle] +pub extern "C" fn clone_pieces( + base_ptr: *mut ffi::Piece<'static>, + len: usize, + cap: usize, +) -> PieceSlice { + eprintln!("[ARTHUR] cloning pieces: {base_ptr:?} {len} {cap}"); + + let v = unsafe { Vec::from_raw_parts(base_ptr, len, cap) }; + + let cloned_v = v.clone(); + + // FIXME: Add documentation + v.leak(); + + PieceSlice { + len: cloned_v.len(), + cap: cloned_v.capacity(), + base_ptr: dbg!(cloned_v.leak().as_mut_ptr()), + } }