From patchwork Wed Apr 5 14:02:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 79619 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp334595vqo; Wed, 5 Apr 2023 07:08:09 -0700 (PDT) X-Google-Smtp-Source: AKy350bKurKhgPAwBxacdZIosO64lZGNTTezQemDDAdKqv22uQtpTpOQssKn35J0n6ykQRl261ZG X-Received: by 2002:a17:906:f988:b0:931:6b2b:a671 with SMTP id li8-20020a170906f98800b009316b2ba671mr2893511ejb.65.1680703689165; Wed, 05 Apr 2023 07:08:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1680703689; cv=none; d=google.com; s=arc-20160816; b=nENft37/Xkq8EX4aV8Ddo0WM8eBZ+qnAJbgHu/rCOTFP81x8v4/ltbQBfgtv4ySVdG uPiBaZlyh2HFGg4vrxKmkuf//t9MeMz/HQX9sqRMEX5otmm4obdL3lY0/idk/9C+TofL bFom0CDQCBxc/8V8XbcFmJHycTHLfsL0BI2hPDLv3wzRxGZxs//hNuf+N9hsKyg4dA7O BUDG9AXrLZIybZYF7V4pVHL87hpj31X9qh4M1v1nKpUVhuWOUFHn2YieIWzZE14oulTN vcLaobChPSLLjT6PdII6JXCqSCBkdULnkdXo/GciKtw5xYqVMbbDtu+ijmWX5GApMg0G eiPQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence :content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature:dmarc-filter :delivered-to; bh=fey2adoMyhHkhtZZLm06vZfC1VjIUPwv0hjPjOivt98=; b=dYJwxVz/zXIoamoCB61wC6umxjUxdArdU1ODgytidZSqrvX2J/fVeFcp090+f4WAyw miGqNqLY3ywD6Cf8fll4iDQg6ot2/m/GDRudPNt0tQg8rstY8VB0gl7HhWyTMj31lAts idmlqOv40AbsNGUEKeBBPvAx4d+056k8q1r278EQmFZIOelKckU1V3Y8gRuk7eRI8OUe 23K8x3wPXJZDEx2HWYKYTQiLNOzRKVs5H10etJP79rwqx7Moy09zKL9d5eVls3SjElIE i1nx8jpsXCU7GcSdrNePEU/9IqwfTPrBnFbI5rZM1uYToh14TewjD7h1PWgQ9b2YVjJd a4zg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@embecosm.com header.s=google header.b="TX/+nac1"; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id f22-20020a170906049600b009332ffacd59si74744eja.765.2023.04.05.07.08.08 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 07:08:09 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@embecosm.com header.s=google header.b="TX/+nac1"; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1B07B3882050 for ; Wed, 5 Apr 2023 14:06:26 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x330.google.com (mail-wm1-x330.google.com [IPv6:2a00:1450:4864:20::330]) by sourceware.org (Postfix) with ESMTPS id 9600D3856974 for ; Wed, 5 Apr 2023 14:05:33 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9600D3856974 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wm1-x330.google.com with SMTP id m6-20020a05600c3b0600b003ee6e324b19so22072170wms.1 for ; Wed, 05 Apr 2023 07:05:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; t=1680703532; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=fey2adoMyhHkhtZZLm06vZfC1VjIUPwv0hjPjOivt98=; b=TX/+nac1no4MGt4QGpFA2+PZE3rmGsZT+oGcdZt73wRD/yT+CpMUzdZ8gplximcYxY OdD6e4/xWNjGX+pWnfV9c08odZuLpa81B6GxNhLfH02RQOheC6FIlX457sy6dWzEWUj9 fbtbUp2KWmaTwkGw0egwDrHRTEdaRle0HcjraDyIjUThjYuDAJ5vpUJ6pFJ7Nl9dVElx 7xDV/BDL/LsY0IKwf5ZEVSvjo+V6UrhnH0klH32bW2RnzTnDZuRvOsBGtd9PPuwwFUkl 743nZFrFJgjjYUvy644rGnvy6GomCH1vAA9hnE1c90MLTyU8vpGPCsbNzdlymvLAc9Xu FcMg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680703532; h=content-transfer-encoding:mime-version:reply-to: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=fey2adoMyhHkhtZZLm06vZfC1VjIUPwv0hjPjOivt98=; b=5wK3MxXwPXfJgKsTl1ojMgyrRs+xwkNpJmziqNM860Y+mDzZN8CrCQRQ6v4Qs74Unp q+ZopnDRTr02Sc9dkRzGIwymUiHZAh4XEl7gFvbROCPvUwf9uOy9wdZ3xa8HsqYqI9KU s/kBYfoMCukyBUbO9e8wqLVMOi6jreKgoBPAmumZ4Caeg5iKWUL8jAxYAwtaCUjTvq3g 271qJFbvILNbhvT4VaveYAqj+0CVqxXMwWZHNCcheHZBg4XfsszItyB5IFBmYjulHvS4 +e3MkhKkcxYqgiS5OM/DewfkGzB+XO5/DyaYtoI66+MYCt1p8oaVauaLdYtuImm46fIh 7CLA== X-Gm-Message-State: AAQBX9cqHXhmhHcXB10dUqkxS/oR72bowUlyUbRou0r7Bf+ex8oAxx+Q NRsAnT3kUioo80PSYuU4y1+FrpKoPgZ7ScpzJg== X-Received: by 2002:a7b:c7cd:0:b0:3df:e6bb:768 with SMTP id z13-20020a7bc7cd000000b003dfe6bb0768mr4705848wmk.24.1680703531754; Wed, 05 Apr 2023 07:05:31 -0700 (PDT) Received: from platypus.localdomain ([62.23.166.218]) by smtp.gmail.com with ESMTPSA id ay8-20020a05600c1e0800b003edddae1068sm2330150wmb.9.2023.04.05.07.05.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 05 Apr 2023 07:05:31 -0700 (PDT) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, Raiki Tamura Subject: [committed 05/88] gccrs: Implement declarative macro 2.0 parser Date: Wed, 5 Apr 2023 16:02:49 +0200 Message-Id: <20230405140411.3016563-6-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230405140411.3016563-1-arthur.cohen@embecosm.com> References: <20230405140411.3016563-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-14.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1762345551143988528?= X-GMAIL-MSGID: =?utf-8?q?1762345551143988528?= From: Raiki Tamura gcc/rust/ChangeLog: * ast/rust-ast-full-decls.h (class MacroItem): Remove forward declaration. * ast/rust-ast-full-test.cc (MacroRulesDefinition): Rework MacroRulesDefinition class * ast/rust-ast.h (class MacroItem): Remove abstract class. * ast/rust-item.h (class MacroItem): Remove forward declaration. * ast/rust-macro.h (class MacroItem): Likewise. (class MacroRulesDefinition): Add MacroKind enum. (class MacroInvocation): Fix inheritance. * lex/rust-token.h: Token "macro" is now used. * parse/rust-parse-impl.h (Parser::parse_item): Add handling for MACRO. (Parser::parse_vis_item): Call into parse_decl_macro_def. (Parser::parse_macro_item): Delete function. (Parser::parse_macro_rules_def): Return MBE macros only. (Parser::parse_decl_macro_def): New function. (Parser::parse_stmt): Handle MACRO token. (Parser::parse_stmt_or_expr_without_block): Call into parse_macro_rules_def. * parse/rust-parse.h: Declare new function. gcc/testsuite/ChangeLog: * rust/compile/decl_macro1.rs: New test. * rust/compile/decl_macro2.rs: New test. * rust/compile/decl_macro3.rs: New test. * rust/compile/decl_macro4.rs: New test. * rust/compile/decl_macro5.rs: New test. * rust/compile/decl_macro6.rs: New test. * rust/compile/decl_macro7.rs: New test. * rust/execute/torture/decl_macro1.rs: New test. * rust/execute/torture/decl_macro2.rs: New test. * rust/execute/torture/decl_macro3.rs: New test. * rust/execute/torture/decl_macro4.rs: New test. Signed-off-by: Raiki Tamura --- gcc/rust/ast/rust-ast-full-decls.h | 1 - gcc/rust/ast/rust-ast-full-test.cc | 1 + gcc/rust/ast/rust-ast.h | 5 - gcc/rust/ast/rust-item.h | 2 - gcc/rust/ast/rust-macro.h | 65 +++-- gcc/rust/lex/rust-token.h | 2 +- gcc/rust/parse/rust-parse-impl.h | 229 +++++++++++++----- gcc/rust/parse/rust-parse.h | 3 +- gcc/testsuite/rust/compile/decl_macro1.rs | 2 + gcc/testsuite/rust/compile/decl_macro2.rs | 2 + gcc/testsuite/rust/compile/decl_macro3.rs | 4 + gcc/testsuite/rust/compile/decl_macro4.rs | 5 + gcc/testsuite/rust/compile/decl_macro5.rs | 5 + gcc/testsuite/rust/compile/decl_macro6.rs | 5 + gcc/testsuite/rust/compile/decl_macro7.rs | 4 + .../rust/execute/torture/decl_macro1.rs | 8 + .../rust/execute/torture/decl_macro2.rs | 8 + .../rust/execute/torture/decl_macro3.rs | 15 ++ .../rust/execute/torture/decl_macro4.rs | 15 ++ 19 files changed, 301 insertions(+), 80 deletions(-) create mode 100644 gcc/testsuite/rust/compile/decl_macro1.rs create mode 100644 gcc/testsuite/rust/compile/decl_macro2.rs create mode 100644 gcc/testsuite/rust/compile/decl_macro3.rs create mode 100644 gcc/testsuite/rust/compile/decl_macro4.rs create mode 100644 gcc/testsuite/rust/compile/decl_macro5.rs create mode 100644 gcc/testsuite/rust/compile/decl_macro6.rs create mode 100644 gcc/testsuite/rust/compile/decl_macro7.rs create mode 100644 gcc/testsuite/rust/execute/torture/decl_macro1.rs create mode 100644 gcc/testsuite/rust/execute/torture/decl_macro2.rs create mode 100644 gcc/testsuite/rust/execute/torture/decl_macro3.rs create mode 100644 gcc/testsuite/rust/execute/torture/decl_macro4.rs diff --git a/gcc/rust/ast/rust-ast-full-decls.h b/gcc/rust/ast/rust-ast-full-decls.h index 136a25ab9aa..58b12a1be0e 100644 --- a/gcc/rust/ast/rust-ast-full-decls.h +++ b/gcc/rust/ast/rust-ast-full-decls.h @@ -51,7 +51,6 @@ class Lifetime; class GenericParam; class LifetimeParam; class ConstGenericParam; -class MacroItem; class TraitItem; class InherentImplItem; class TraitImplItem; diff --git a/gcc/rust/ast/rust-ast-full-test.cc b/gcc/rust/ast/rust-ast-full-test.cc index 4f593dcbd49..280f59ffb16 100644 --- a/gcc/rust/ast/rust-ast-full-test.cc +++ b/gcc/rust/ast/rust-ast-full-test.cc @@ -1284,6 +1284,7 @@ MacroRulesDefinition::as_string () const // get outer attrs str += append_attributes (outer_attrs, OUTER); + // TODO: deal with macro_2_0 str += "macro_rules!"; str += rule_name; diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h index aa86f2f9826..5f18233eb0f 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -1350,11 +1350,6 @@ protected: } }; -// A macro item AST node - abstract base class -class MacroItem : public Item -{ -}; - // Item used in trait declarations - abstract base class class TraitItem { diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h index 7ea7b86562f..37ed2beabfc 100644 --- a/gcc/rust/ast/rust-item.h +++ b/gcc/rust/ast/rust-item.h @@ -4391,8 +4391,6 @@ protected: } }; -// Replaced with forward decls - defined in "rust-macro.h" -class MacroItem; class MacroRulesDefinition; } // namespace AST } // namespace Rust diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h index fc4b5b82fb5..bff8c7ac6fb 100644 --- a/gcc/rust/ast/rust-macro.h +++ b/gcc/rust/ast/rust-macro.h @@ -23,13 +23,11 @@ #include "rust-ast.h" #include "rust-ast-fragment.h" #include "rust-location.h" +#include "rust-item.h" +#include "rust-make-unique.h" namespace Rust { namespace AST { - -// Decls as definitions moved to rust-ast.h -class MacroItem; - class MacroFragSpec { public: @@ -446,8 +444,18 @@ public: }; // A macro rules definition item AST node -class MacroRulesDefinition : public MacroItem +class MacroRulesDefinition : public VisItem { +public: + enum MacroKind + { + // Macro by Example (legacy macro rules) + MBE, + // Declarative macros 2.0 + DeclMacro, + }; + +private: std::vector outer_attrs; Identifier rule_name; // MacroRulesDef rules_def; @@ -460,6 +468,7 @@ class MacroRulesDefinition : public MacroItem std::function associated_transcriber; // Since we can't compare std::functions, we need to use an extra boolean bool is_builtin_rule; + MacroKind kind; /** * Default function to use as an associated transcriber. This function should @@ -479,27 +488,51 @@ class MacroRulesDefinition : public MacroItem * I am not aware of the implications of this decision. The rustc spec does * mention that using the same parser for macro definitions and invocations * is "extremely self-referential and non-intuitive". */ - -public: - std::string as_string () const override; - MacroRulesDefinition (Identifier rule_name, DelimType delim_type, std::vector rules, - std::vector outer_attrs, Location locus) - : outer_attrs (std::move (outer_attrs)), rule_name (std::move (rule_name)), + std::vector outer_attrs, Location locus, + MacroKind kind, Visibility vis) + : VisItem (std::move (vis), outer_attrs), + outer_attrs (std::move (outer_attrs)), rule_name (std::move (rule_name)), delim_type (delim_type), rules (std::move (rules)), locus (locus), - associated_transcriber (dummy_builtin), is_builtin_rule (false) + associated_transcriber (dummy_builtin), is_builtin_rule (false), + kind (kind) {} MacroRulesDefinition ( Identifier builtin_name, DelimType delim_type, - std::function associated_transcriber) - : outer_attrs (std::vector ()), rule_name (builtin_name), + std::function associated_transcriber, + MacroKind kind, Visibility vis) + : VisItem (std::move (vis), std::vector ()), + outer_attrs (std::vector ()), rule_name (builtin_name), delim_type (delim_type), rules (std::vector ()), locus (Location ()), associated_transcriber (associated_transcriber), - is_builtin_rule (true) + is_builtin_rule (true), kind (kind) {} +public: + std::string as_string () const override; + + static std::unique_ptr + mbe (Identifier rule_name, DelimType delim_type, std::vector rules, + std::vector outer_attrs, Location locus) + { + return Rust::make_unique ( + MacroRulesDefinition (rule_name, delim_type, rules, outer_attrs, locus, + AST::MacroRulesDefinition::MacroKind::MBE, + AST::Visibility::create_error ())); + } + + static std::unique_ptr + decl_macro (Identifier rule_name, std::vector rules, + std::vector outer_attrs, Location locus, + Visibility vis) + { + return Rust::make_unique (MacroRulesDefinition ( + rule_name, AST::DelimType::CURLY, rules, outer_attrs, locus, + AST::MacroRulesDefinition::MacroKind::DeclMacro, vis)); + } + void accept_vis (ASTVisitor &vis) override; // Invalid if rule name is empty, so base stripping on that. @@ -549,7 +582,7 @@ protected: * compile time */ class MacroInvocation : public TypeNoBounds, public Pattern, - public MacroItem, + public Item, public TraitItem, public TraitImplItem, public InherentImplItem, diff --git a/gcc/rust/lex/rust-token.h b/gcc/rust/lex/rust-token.h index 18f1afa664b..0fc55a20beb 100644 --- a/gcc/rust/lex/rust-token.h +++ b/gcc/rust/lex/rust-token.h @@ -171,7 +171,7 @@ enum PrimitiveCoreType RS_TOKEN_KEYWORD (IN, "in") \ RS_TOKEN_KEYWORD (LET, "let") \ RS_TOKEN_KEYWORD (LOOP, "loop") \ - RS_TOKEN_KEYWORD (MACRO, "macro") /* unused */ \ + RS_TOKEN_KEYWORD (MACRO, "macro") \ RS_TOKEN_KEYWORD (MATCH_TOK, "match") \ RS_TOKEN_KEYWORD (MOD, "mod") \ RS_TOKEN_KEYWORD (MOVE, "move") \ diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h index 959e0338a10..d71bafded63 100644 --- a/gcc/rust/parse/rust-parse-impl.h +++ b/gcc/rust/parse/rust-parse-impl.h @@ -1032,11 +1032,6 @@ Parser::parse_item (bool called_from_statement) // parse outer attributes for item AST::AttrVec outer_attrs = parse_outer_attributes (); - - // TODO: decide how to deal with VisItem vs MacroItem dichotomy - /* best current solution: catch all keywords that would imply a VisItem in a - * switch and have MacroItem as a last resort */ - const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) @@ -1064,6 +1059,7 @@ Parser::parse_item (bool called_from_statement) case STATIC_TOK: case TRAIT: case IMPL: + case MACRO: /* TODO: implement union keyword but not really because of * context-dependence crappy hack way to parse a union written below to * separate it from the good code. */ @@ -1078,7 +1074,7 @@ Parser::parse_item (bool called_from_statement) case CRATE: case DOLLAR_SIGN: // almost certainly macro invocation semi - return parse_macro_item (std::move (outer_attrs)); + return parse_macro_invocation_semi (std::move (outer_attrs)); break; // crappy hack to do union "keyword" case IDENTIFIER: @@ -1092,19 +1088,18 @@ Parser::parse_item (bool called_from_statement) else if (t->get_str () == "macro_rules") { // macro_rules! macro item - return parse_macro_item (std::move (outer_attrs)); + return parse_macro_rules_def (std::move (outer_attrs)); } else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION || lexer.peek_token (1)->get_id () == EXCLAM) { /* path (probably) or macro invocation, so probably a macro invocation * semi */ - return parse_macro_item (std::move (outer_attrs)); + return parse_macro_invocation_semi (std::move (outer_attrs)); } gcc_fallthrough (); default: // otherwise unrecognised - // return parse_macro_item(std::move(outer_attrs)); add_error (Error (t->get_locus (), "unrecognised token %qs for start of %s", t->get_token_description (), @@ -1335,6 +1330,8 @@ Parser::parse_vis_item (AST::AttrVec outer_attrs) lexer.skip_token (1); // TODO: is this right thing to do? return nullptr; } + case MACRO: + return parse_decl_macro_def (std::move (vis), std::move (outer_attrs)); default: // otherwise vis item clearly doesn't exist, which is not an error // has a catch-all post-switch return to allow other breaks to occur @@ -1343,42 +1340,6 @@ Parser::parse_vis_item (AST::AttrVec outer_attrs) return nullptr; } -// Parses a MacroItem (either a MacroInvocationSemi or MacroRulesDefinition). -template -std::unique_ptr -Parser::parse_macro_item (AST::AttrVec outer_attrs) -{ - const_TokenPtr t = lexer.peek_token (); - - /* dodgy way of detecting macro due to weird context-dependence thing. - * probably can be improved */ - // TODO: ensure that string compare works properly - if (t->get_id () == IDENTIFIER && t->get_str () == "macro_rules") - { - return parse_macro_rules_def (std::move (outer_attrs)); - } - else - { - // DEBUG: TODO: remove - rust_debug ( - "DEBUG - parse_macro_item called and token is not macro_rules"); - if (t->get_id () == IDENTIFIER) - { - rust_debug ("just add to last error: token is not macro_rules and is " - "instead '%s'", - t->get_str ().c_str ()); - } - else - { - rust_debug ("just add to last error: token is not macro_rules and is " - "not an identifier either - it is '%s'", - t->get_token_description ()); - } - - return parse_macro_invocation_semi (std::move (outer_attrs)); - } -} - // Parses a macro rules definition syntax extension whatever thing. template std::unique_ptr @@ -1512,16 +1473,16 @@ Parser::parse_macro_rules_def (AST::AttrVec outer_attrs) { // as this is the end, allow recovery (probably) - may change return std::unique_ptr ( - new AST::MacroRulesDefinition ( + AST::MacroRulesDefinition::mbe ( std::move (rule_name), delim_type, std::move (macro_rules), std::move (outer_attrs), macro_locus)); } } return std::unique_ptr ( - new AST::MacroRulesDefinition (std::move (rule_name), delim_type, - std::move (macro_rules), - std::move (outer_attrs), macro_locus)); + AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type, + std::move (macro_rules), + std::move (outer_attrs), macro_locus)); } else { @@ -1541,6 +1502,165 @@ Parser::parse_macro_rules_def (AST::AttrVec outer_attrs) } } +// Parses a declarative macro 2.0 definition. +template +std::unique_ptr +Parser::parse_decl_macro_def (AST::Visibility vis, + AST::AttrVec outer_attrs) +{ + // ensure that first token is identifier saying "macro" + const_TokenPtr t = lexer.peek_token (); + if (t->get_id () != MACRO) + { + Error error ( + t->get_locus (), + "declarative macro definition does not start with %"); + add_error (std::move (error)); + + // skip after somewhere? + return nullptr; + } + lexer.skip_token (); + Location macro_locus = t->get_locus (); + + // parse macro name + const_TokenPtr ident_tok = expect_token (IDENTIFIER); + if (ident_tok == nullptr) + { + return nullptr; + } + Identifier rule_name = ident_tok->get_str (); + + t = lexer.peek_token (); + if (t->get_id () == LEFT_PAREN) + { + // single definiton of macro rule + // e.g. `macro foo($e:expr) {}` + + // parse macro matcher + Location locus = lexer.peek_token ()->get_locus (); + AST::MacroMatcher matcher = parse_macro_matcher (); + if (matcher.is_error ()) + return nullptr; + + // check delimiter of macro matcher + if (matcher.get_delim_type () != AST::DelimType::PARENS) + { + Error error (locus, "only parenthesis can be used for a macro " + "matcher in declarative macro definition"); + add_error (std::move (error)); + return nullptr; + } + + Location transcriber_loc = lexer.peek_token ()->get_locus (); + AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree (); + AST::MacroTranscriber transcriber (delim_tok_tree, transcriber_loc); + + if (transcriber.get_token_tree ().get_delim_type () + != AST::DelimType::CURLY) + { + Error error (transcriber_loc, + "only braces can be used for a macro transcriber " + "in declarative macro definition"); + add_error (std::move (error)); + return nullptr; + } + + AST::MacroRule macro_rule + = AST::MacroRule (std::move (matcher), std::move (transcriber), locus); + std::vector macro_rules; + macro_rules.push_back (macro_rule); + + return std::unique_ptr ( + AST::MacroRulesDefinition::decl_macro (std::move (rule_name), + macro_rules, + std::move (outer_attrs), + macro_locus, vis)); + } + else if (t->get_id () == LEFT_CURLY) + { + // multiple definitions of macro rule separated by comma + // e.g. `macro foo { () => {}, ($e:expr) => {}, }` + + // parse left curly + const_TokenPtr left_curly = expect_token (LEFT_CURLY); + if (left_curly == nullptr) + { + return nullptr; + } + + // parse actual macro rules + std::vector macro_rules; + + // must be at least one macro rule, so parse it + AST::MacroRule initial_rule = parse_macro_rule (); + if (initial_rule.is_error ()) + { + Error error ( + lexer.peek_token ()->get_locus (), + "required first macro rule in declarative macro definition " + "could not be parsed"); + add_error (std::move (error)); + + // skip after somewhere? + return nullptr; + } + macro_rules.push_back (std::move (initial_rule)); + + t = lexer.peek_token (); + // parse macro rules + while (t->get_id () == COMMA) + { + // skip comma + lexer.skip_token (); + + // don't parse if end of macro rules + if (token_id_matches_delims (lexer.peek_token ()->get_id (), + AST::CURLY)) + { + break; + } + + // try to parse next rule + AST::MacroRule rule = parse_macro_rule (); + if (rule.is_error ()) + { + Error error ( + lexer.peek_token ()->get_locus (), + "failed to parse macro rule in declarative macro definition"); + add_error (std::move (error)); + + return nullptr; + } + + macro_rules.push_back (std::move (rule)); + + t = lexer.peek_token (); + } + + // parse right curly + const_TokenPtr right_curly = expect_token (RIGHT_CURLY); + if (right_curly == nullptr) + { + return nullptr; + } + + return std::unique_ptr ( + AST::MacroRulesDefinition::decl_macro (std::move (rule_name), + std::move (macro_rules), + std::move (outer_attrs), + macro_locus, vis)); + } + else + { + add_error (Error (t->get_locus (), + "unexpected token %qs - expecting delimiters " + "(for a declarative macro definiton)", + t->get_token_description ())); + return nullptr; + } +} + // Parses a semi-coloned (except for full block) macro invocation item. template std::unique_ptr @@ -6004,6 +6124,7 @@ Parser::parse_stmt (ParseRestrictions restrictions) case STATIC_TOK: case TRAIT: case IMPL: + case MACRO: /* TODO: implement union keyword but not really because of * context-dependence crappy hack way to parse a union written below to * separate it from the good code. */ @@ -6019,7 +6140,7 @@ Parser::parse_stmt (ParseRestrictions restrictions) case CRATE: case DOLLAR_SIGN: // almost certainly macro invocation semi - return parse_macro_item (std::move (outer_attrs)); + return parse_macro_invocation_semi (std::move (outer_attrs)); break; // crappy hack to do union "keyword" case IDENTIFIER: @@ -6032,7 +6153,7 @@ Parser::parse_stmt (ParseRestrictions restrictions) else if (t->get_str () == "macro_rules") { // macro_rules! macro item - return parse_macro_item (std::move (outer_attrs)); + return parse_macro_rules_def (std::move (outer_attrs)); } else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION || lexer.peek_token (1)->get_id () == EXCLAM) @@ -6040,7 +6161,7 @@ Parser::parse_stmt (ParseRestrictions restrictions) // FIXME: ensure doesn't take any expressions by mistake /* path (probably) or macro invocation, so probably a macro * invocation semi */ - return parse_macro_item (std::move (outer_attrs)); + return parse_macro_invocation_semi (std::move (outer_attrs)); } gcc_fallthrough (); // TODO: find out how to disable gcc "implicit fallthrough" warning @@ -11711,8 +11832,8 @@ Parser::parse_stmt_or_expr_without_block () else if (t->get_str () == "macro_rules") { // macro_rules! macro item - std::unique_ptr item ( - parse_macro_item (std::move (outer_attrs))); + std::unique_ptr item ( + parse_macro_rules_def (std::move (outer_attrs))); return ExprOrStmt (std::move (item)); } else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h index 8449181b12f..5c0fcc3f174 100644 --- a/gcc/rust/parse/rust-parse.h +++ b/gcc/rust/parse/rust-parse.h @@ -197,6 +197,8 @@ private: AST::DelimTokenTree parse_delim_token_tree (); std::unique_ptr parse_macro_rules_def (AST::AttrVec outer_attrs); + std::unique_ptr + parse_decl_macro_def (AST::Visibility vis, AST::AttrVec outer_attrs); std::unique_ptr parse_macro_invocation_semi (AST::AttrVec outer_attrs); std::unique_ptr @@ -209,7 +211,6 @@ private: // Top-level item-related std::unique_ptr parse_vis_item (AST::AttrVec outer_attrs); - std::unique_ptr parse_macro_item (AST::AttrVec outer_attrs); // VisItem subclass-related std::unique_ptr parse_module (AST::Visibility vis, diff --git a/gcc/testsuite/rust/compile/decl_macro1.rs b/gcc/testsuite/rust/compile/decl_macro1.rs new file mode 100644 index 00000000000..4a81a71e500 --- /dev/null +++ b/gcc/testsuite/rust/compile/decl_macro1.rs @@ -0,0 +1,2 @@ +#![feature(decl_macro)] +macro m() {} diff --git a/gcc/testsuite/rust/compile/decl_macro2.rs b/gcc/testsuite/rust/compile/decl_macro2.rs new file mode 100644 index 00000000000..cbe19b0c14b --- /dev/null +++ b/gcc/testsuite/rust/compile/decl_macro2.rs @@ -0,0 +1,2 @@ +#![feature(decl_macro)] +pub macro m($e: expr) { $e + $e } diff --git a/gcc/testsuite/rust/compile/decl_macro3.rs b/gcc/testsuite/rust/compile/decl_macro3.rs new file mode 100644 index 00000000000..d48da7835f9 --- /dev/null +++ b/gcc/testsuite/rust/compile/decl_macro3.rs @@ -0,0 +1,4 @@ +#![feature(decl_macro)] +macro foo { + () => {} +} diff --git a/gcc/testsuite/rust/compile/decl_macro4.rs b/gcc/testsuite/rust/compile/decl_macro4.rs new file mode 100644 index 00000000000..b8576cf0dd8 --- /dev/null +++ b/gcc/testsuite/rust/compile/decl_macro4.rs @@ -0,0 +1,5 @@ +#![feature(decl_macro)] +macro foo { + () => { 0 }, + ($n: expr) => { $n + 1 }, +} \ No newline at end of file diff --git a/gcc/testsuite/rust/compile/decl_macro5.rs b/gcc/testsuite/rust/compile/decl_macro5.rs new file mode 100644 index 00000000000..b4ea20ffa74 --- /dev/null +++ b/gcc/testsuite/rust/compile/decl_macro5.rs @@ -0,0 +1,5 @@ +#![feature(decl_macro)] +macro foo { + () => [], + ($h: expr, $(t: expr),*) => ($h), +} diff --git a/gcc/testsuite/rust/compile/decl_macro6.rs b/gcc/testsuite/rust/compile/decl_macro6.rs new file mode 100644 index 00000000000..5c5e7002a98 --- /dev/null +++ b/gcc/testsuite/rust/compile/decl_macro6.rs @@ -0,0 +1,5 @@ +#![feature(decl_macro)] +macro m {} +// { dg-error "unexpected token .\}. - expecting delimiters .for a macro matcher." "" { target *-*-* } .-1 } +// { dg-error "required first macro rule in declarative macro definition could not be parsed" "" { target *-*-* } .-2 } +// { dg-error "failed to parse item in crate" "" { target *-*-* } .-3 } diff --git a/gcc/testsuite/rust/compile/decl_macro7.rs b/gcc/testsuite/rust/compile/decl_macro7.rs new file mode 100644 index 00000000000..7327fb56782 --- /dev/null +++ b/gcc/testsuite/rust/compile/decl_macro7.rs @@ -0,0 +1,4 @@ +#![feature(decl_macro)] +pub macro hello() [ "Hello" ] +// { dg-error "only braces can be used for a macro transcriber in declarative macro definition" "" { target *-*-* } .-1 } +// { dg-error "failed to parse item in crate" } \ No newline at end of file diff --git a/gcc/testsuite/rust/execute/torture/decl_macro1.rs b/gcc/testsuite/rust/execute/torture/decl_macro1.rs new file mode 100644 index 00000000000..accc8b1db8e --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/decl_macro1.rs @@ -0,0 +1,8 @@ +#![feature(decl_macro)] +macro one() { + 1 +} + +fn main() -> i32 { + one!() - 1 +} diff --git a/gcc/testsuite/rust/execute/torture/decl_macro2.rs b/gcc/testsuite/rust/execute/torture/decl_macro2.rs new file mode 100644 index 00000000000..f42b96262fe --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/decl_macro2.rs @@ -0,0 +1,8 @@ +#![feature(decl_macro)] +macro one { + () => { 1 } +} + +fn main() -> i32 { + one!() - 1 +} diff --git a/gcc/testsuite/rust/execute/torture/decl_macro3.rs b/gcc/testsuite/rust/execute/torture/decl_macro3.rs new file mode 100644 index 00000000000..fa2cf793cf2 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/decl_macro3.rs @@ -0,0 +1,15 @@ +#![feature(decl_macro)] +macro add { + ($e:expr) => { + $e + }, + ($h:expr, $($t:expr),*) => { + $h + add!($($t),*) + }, +} + +fn main() -> i32 { + let a = add!(1, 2, 3); + + a - 6 +} diff --git a/gcc/testsuite/rust/execute/torture/decl_macro4.rs b/gcc/testsuite/rust/execute/torture/decl_macro4.rs new file mode 100644 index 00000000000..e700e63161d --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/decl_macro4.rs @@ -0,0 +1,15 @@ +#![feature(decl_macro)] +pub macro add { + ($e:expr) => { + $e + }, + ($h:expr, $($t:expr),*) => { + $h + add!($($t),*) + }, +} + +fn main() -> i32 { + let a = add!(1, 2, 3); + + a - 6 +}