Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package perl-XS-Parse-Keyword for 
openSUSE:Factory checked in at 2022-12-14 14:10:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/perl-XS-Parse-Keyword (Old)
 and      /work/SRC/openSUSE:Factory/.perl-XS-Parse-Keyword.new.1835 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "perl-XS-Parse-Keyword"

Wed Dec 14 14:10:54 2022 rev:10 rq:1042728 version:0.30

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/perl-XS-Parse-Keyword/perl-XS-Parse-Keyword.changes  
    2022-11-09 12:56:40.200089005 +0100
+++ 
/work/SRC/openSUSE:Factory/.perl-XS-Parse-Keyword.new.1835/perl-XS-Parse-Keyword.changes
    2022-12-14 14:11:08.391536946 +0100
@@ -1,0 +2,29 @@
+Sun Dec  4 03:10:55 UTC 2022 - Tina Müller <timueller+p...@suse.de>
+
+- updated to 0.30
+   see /usr/share/doc/packages/perl-XS-Parse-Keyword/Changes
+
+  0.30    2022-12-03
+          [CHANGES]
+           * Added XPK_STAGED_ANONSUB; inspired a bit by XS::Parse::Sublike for
+             customising the parsing of anonmethod
+  0.29    2022-12-01
+          [CHANGES]
+           * Added XPK_PREFIXED_TERMEXPR_ENTERLEAVE
+          [BUGFIXES]
+           * Don't try to call `SvPVX()` on a `newSV(0)` because -DDEBUGGING
+             perls get upset (RT145278)
+           * Remember to `break` out of switch block cases when testing for
+             `KEYWORD_PLUGIN_*` return values
+  0.28    2022-11-25
+          [CHANGES]
+           * Include a XSParseInfixClassification field in the XSParseInfixInfo
+             structure
+           * Do not permit mixed identifier/non characters in the names of
+             registered infix operators
+           * No longer supports XSParseInfix ABI version 0
+          [BUGFIXES]
+           * When parsing an infix operator name, make sure not to be confused
+             by additional identifier characters immediately after it
+
+-------------------------------------------------------------------

Old:
----
  XS-Parse-Keyword-0.27.tar.gz

New:
----
  XS-Parse-Keyword-0.30.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ perl-XS-Parse-Keyword.spec ++++++
--- /var/tmp/diff_new_pack.pwRy9C/_old  2022-12-14 14:11:09.027540218 +0100
+++ /var/tmp/diff_new_pack.pwRy9C/_new  2022-12-14 14:11:09.031540238 +0100
@@ -18,7 +18,7 @@
 
 %define cpan_name XS-Parse-Keyword
 Name:           perl-XS-Parse-Keyword
-Version:        0.27
+Version:        0.30
 Release:        0
 License:        Artistic-1.0 OR GPL-1.0-or-later
 Summary:        XS functions to assist in parsing keyword syntax

++++++ XS-Parse-Keyword-0.27.tar.gz -> XS-Parse-Keyword-0.30.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/Changes 
new/XS-Parse-Keyword-0.30/Changes
--- old/XS-Parse-Keyword-0.27/Changes   2022-10-31 23:09:16.000000000 +0100
+++ new/XS-Parse-Keyword-0.30/Changes   2022-12-03 15:51:44.000000000 +0100
@@ -1,5 +1,32 @@
 Revision history for XS-Parse-Keyword
 
+0.30    2022-12-03
+        [CHANGES]
+         * Added XPK_STAGED_ANONSUB; inspired a bit by XS::Parse::Sublike for
+           customising the parsing of anonmethod
+
+0.29    2022-12-01
+        [CHANGES]
+         * Added XPK_PREFIXED_TERMEXPR_ENTERLEAVE
+
+        [BUGFIXES]
+         * Don't try to call `SvPVX()` on a `newSV(0)` because -DDEBUGGING
+           perls get upset (RT145278)
+         * Remember to `break` out of switch block cases when testing for
+           `KEYWORD_PLUGIN_*` return values
+
+0.28    2022-11-25
+        [CHANGES]
+         * Include a XSParseInfixClassification field in the XSParseInfixInfo
+           structure
+         * Do not permit mixed identifier/non characters in the names of
+           registered infix operators
+         * No longer supports XSParseInfix ABI version 0
+
+        [BUGFIXES]
+         * When parsing an infix operator name, make sure not to be confused
+           by additional identifier characters immediately after it
+
 0.27    2022-10-31
         [CHANGES]
          * Updates to XS::Parse::Infix for latest `infix-plugin` perl5 branch
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/META.json 
new/XS-Parse-Keyword-0.30/META.json
--- old/XS-Parse-Keyword-0.27/META.json 2022-10-31 23:09:16.000000000 +0100
+++ new/XS-Parse-Keyword-0.30/META.json 2022-12-03 15:51:44.000000000 +0100
@@ -40,19 +40,19 @@
    "provides" : {
       "XS::Parse::Infix" : {
          "file" : "lib/XS/Parse/Infix.pm",
-         "version" : "0.27"
+         "version" : "0.30"
       },
       "XS::Parse::Infix::Builder" : {
          "file" : "lib/XS/Parse/Infix/Builder.pm",
-         "version" : "0.27"
+         "version" : "0.30"
       },
       "XS::Parse::Keyword" : {
          "file" : "lib/XS/Parse/Keyword.pm",
-         "version" : "0.27"
+         "version" : "0.30"
       },
       "XS::Parse::Keyword::Builder" : {
          "file" : "lib/XS/Parse/Keyword/Builder.pm",
-         "version" : "0.27"
+         "version" : "0.30"
       }
    },
    "release_status" : "stable",
@@ -61,6 +61,6 @@
          "http://dev.perl.org/licenses/";
       ]
    },
-   "version" : "0.27",
-   "x_serialization_backend" : "JSON::PP version 4.06"
+   "version" : "0.30",
+   "x_serialization_backend" : "JSON::PP version 4.07"
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/META.yml 
new/XS-Parse-Keyword-0.30/META.yml
--- old/XS-Parse-Keyword-0.27/META.yml  2022-10-31 23:09:16.000000000 +0100
+++ new/XS-Parse-Keyword-0.30/META.yml  2022-12-03 15:51:44.000000000 +0100
@@ -19,19 +19,19 @@
 provides:
   XS::Parse::Infix:
     file: lib/XS/Parse/Infix.pm
-    version: '0.27'
+    version: '0.30'
   XS::Parse::Infix::Builder:
     file: lib/XS/Parse/Infix/Builder.pm
-    version: '0.27'
+    version: '0.30'
   XS::Parse::Keyword:
     file: lib/XS/Parse/Keyword.pm
-    version: '0.27'
+    version: '0.30'
   XS::Parse::Keyword::Builder:
     file: lib/XS/Parse/Keyword/Builder.pm
-    version: '0.27'
+    version: '0.30'
 requires:
   perl: '5.014'
 resources:
   license: http://dev.perl.org/licenses/
-version: '0.27'
+version: '0.30'
 x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/README 
new/XS-Parse-Keyword-0.30/README
--- old/XS-Parse-Keyword-0.27/README    2022-10-31 23:09:16.000000000 +0100
+++ new/XS-Parse-Keyword-0.30/README    2022-12-03 15:51:44.000000000 +0100
@@ -260,12 +260,67 @@
 
  XPK_ANONSUB
 
-    atomic, emits op.
+    atomic, emits cv.
 
     A brace-delimited block of code is expected, and assembled into the
     body of a new anonymous subroutine. This will be passed as a protosub
     CV in the cv field.
 
+ XPK_STAGED_ANONSUB
+
+       XPK_STAGED_ANONSUB(stages ...)
+
+    structural, emits cv.
+
+    A variant of XPK_ANONSUB which accepts additional function pointers to
+    be invoked at various points during parsing and compilation. These can
+    be used to interrupt the normal parsing in a manner similar to
+    XS::Parse::Sublike, though currently somewhat less flexibly.
+
+    The stages list may contain elements of the following types. Not every
+    stage must be present, but any that are present must be in the
+    following order. Multiple copies of each stage are permitted; they are
+    invoked in the written order, with parser code happening inbetween.
+
+    XPK_ANONSUB_PREPARE
+
+         XPK_ANONSUB_PREPARE(&callback)
+
+      atomic, emits nothing.
+
+      Invokes the callback before start_subparse().
+
+    XPK_ANONSUB_START
+
+         XPK_ANONSUB_START(&callback)
+
+      atomic, emits nothing.
+
+      Invokes the callback after block_start() but before parsing the
+      actual block contents.
+
+    XPK_ANONSUB_END
+
+         OP *op_wrapper_callback(pTHX_ OP *o, void *hookdata);
+      
+         XPK_ANONSUB_END(&op_wrapper_callback)
+
+      atomic, emits nothing.
+
+      Invokes the callback after parsing the block contents but before
+      calling block_end(). The callback may modify the optree if required
+      and return a new one.
+
+    XPK_ANONSUB_WRAP
+
+         XPK_ANONSUB_WRAP(&op_wrapper_callback)
+
+      atomic, emits nothing.
+
+      Invokes the callback after block_end() but before passing the optree
+      to newATTRSUB(). The callback may modify the optree if required and
+      return a new one.
+
  XPK_ARITHEXPR
 
     atomic, emits op.
@@ -294,6 +349,20 @@
     Variants of XPK_TERMEXPR which puts the expression in void or scalar
     context.
 
+ XPK_PREFIXED_TERMEXPR_ENTERLEAVE
+
+       XPK_PREFIXED_TERMEXPR_ENTERLEAVE(pieces ...)
+
+    A variant of XPK_TERMEXPR which expects a sequence pieces first before
+    it parses a term expression, similar to how
+    XPK_PREFIXED_BLOCK_ENTERLEAVE works. The entire operation is wrapped in
+    an ENTER/LEAVE pair.
+
+    This is intended just for use of XPK_SETUP pieces as prefixes. Any
+    other pieces which actually parse real input are likely to cause
+    overly-complex, subtle, or outright ambiguous grammars, and should be
+    avoided.
+
  XPK_LISTEXPR
 
     atomic, emits op.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/XSParseInfix.h 
new/XS-Parse-Keyword-0.30/XSParseInfix.h
--- old/XS-Parse-Keyword-0.27/XSParseInfix.h    2022-10-31 23:09:16.000000000 
+0100
+++ new/XS-Parse-Keyword-0.30/XSParseInfix.h    2022-12-03 15:51:44.000000000 
+0100
@@ -71,6 +71,8 @@
 
   const struct XSParseInfixHooks *hooks;
   void *hookdata;
+
+  enum XSParseInfixClassification cls;
 };
 
 static bool (*parse_infix_func)(pTHX_ enum XSParseInfixSelection select, 
struct XSParseInfixInfo **infop);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/XSParseKeyword.h 
new/XS-Parse-Keyword-0.30/XSParseKeyword.h
--- old/XS-Parse-Keyword-0.27/XSParseKeyword.h  2022-10-31 23:09:16.000000000 
+0100
+++ new/XS-Parse-Keyword-0.30/XSParseKeyword.h  2022-12-03 15:51:44.000000000 
+0100
@@ -7,10 +7,12 @@
 struct XSParseKeywordPieceType {
   int type;
   union {
-    char                                  c;      /* LITERALCHAR */
-    const char                           *str;    /* LITERALSTR */
+    char c;                                       /* LITERALCHAR */
+    const char *str;                              /* LITERALSTR */
     const struct XSParseKeywordPieceType *pieces; /* SCOPEs */
-    void                                (*callback)(pTHX_ void *hookdata); /* 
SETUP */
+    void (*callback)(pTHX_ void *hookdata);       /* SETUP, ANONSUB 
PREPARE+START */
+
+    OP *(*op_wrap_callback)(pTHX_ OP *o, void *hookdata);
   } u;
 };
 
@@ -46,6 +48,11 @@
 
   XS_PARSE_KEYWORD_SETUP = 0x70,      /* invokes callback, emits nothing */
 
+  XS_PARSE_KEYWORD_ANONSUB_PREPARE,   /* invokes callback, emits nothing */
+  XS_PARSE_KEYWORD_ANONSUB_START,     /* invokes callback, emits nothing */
+  XS_PARSE_KEYWORD_ANONSUB_END,       /* invokes op_wrap_callback, emits 
nothing */
+  XS_PARSE_KEYWORD_ANONSUB_WRAP,      /* invokes op_wrap_callback, emits 
nothing */
+
   XS_PARSE_KEYWORD_SEQUENCE = 0x80,   /* contained */
   XS_PARSE_KEYWORD_REPEATED,          /* i, contained */
   XS_PARSE_KEYWORD_CHOICE,            /* i, contained */
@@ -95,6 +102,14 @@
 
 #define XPK_ANONSUB {.type = XS_PARSE_KEYWORD_ANONSUB}
 
+#define XPK_ANONSUB_PREPARE(func)  {.type = XS_PARSE_KEYWORD_ANONSUB_PREPARE, 
.u.callback = func}
+#define XPK_ANONSUB_START(func)    {.type = XS_PARSE_KEYWORD_ANONSUB_START, 
.u.callback = func}
+#define XPK_ANONSUB_END(func)      {.type = XS_PARSE_KEYWORD_ANONSUB_END, 
.u.op_wrap_callback = func}
+#define XPK_ANONSUB_WRAP(func)     {.type = XS_PARSE_KEYWORD_ANONSUB_WRAP, 
.u.op_wrap_callback = func}
+
+#define XPK_STAGED_ANONSUB(...) \
+  {.type = XS_PARSE_KEYWORD_ANONSUB, .u.pieces = (const struct 
XSParseKeywordPieceType []){ __VA_ARGS__, {0} }}
+
 #define XPK_ARITHEXPR_flags(flags) {.type = XS_PARSE_KEYWORD_ARITHEXPR|(flags)}
 #define XPK_ARITHEXPR              XPK_ARITHEXPR_flags(0)
 #define XPK_ARITHEXPR_VOIDCTX      XPK_ARITHEXPR_flags(XPK_TYPEFLAG_G_VOID)
@@ -107,6 +122,10 @@
 #define XPK_LISTEXPR              XPK_LISTEXPR_flags(0)
 #define XPK_LISTEXPR_LISTCTX      XPK_LISTEXPR_flags(XPK_TYPEFLAG_G_LIST)
 
+#define XPK_PREFIXED_TERMEXPR_flags(flags,...) \
+  {.type = XS_PARSE_KEYWORD_TERMEXPR|(flags), .u.pieces = (const struct 
XSParseKeywordPieceType []){ __VA_ARGS__, {0} }}
+#define XPK_PREFIXED_TERMEXPR_ENTERLEAVE(...) 
XPK_PREFIXED_TERMEXPR_flags(XPK_TYPEFLAG_ENTERLEAVE, __VA_ARGS__)
+
 #define XPK_IDENT           {.type = XS_PARSE_KEYWORD_IDENT                    
   }
 #define XPK_IDENT_OPT       {.type = XS_PARSE_KEYWORD_IDENT      
|XPK_TYPEFLAG_OPT}
 #define XPK_PACKAGENAME     {.type = XS_PARSE_KEYWORD_PACKAGENAME              
   }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/lib/XS/Parse/Infix/Builder.pm 
new/XS-Parse-Keyword-0.30/lib/XS/Parse/Infix/Builder.pm
--- old/XS-Parse-Keyword-0.27/lib/XS/Parse/Infix/Builder.pm     2022-10-31 
23:09:16.000000000 +0100
+++ new/XS-Parse-Keyword-0.30/lib/XS/Parse/Infix/Builder.pm     2022-12-03 
15:51:44.000000000 +0100
@@ -3,7 +3,7 @@
 #
 #  (C) Paul Evans, 2021 -- leon...@leonerd.org.uk
 
-package XS::Parse::Infix::Builder 0.27;
+package XS::Parse::Infix::Builder 0.30;
 
 use v5.14;
 use warnings;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/XS-Parse-Keyword-0.27/lib/XS/Parse/Infix/Builder_data.pm.PL 
new/XS-Parse-Keyword-0.30/lib/XS/Parse/Infix/Builder_data.pm.PL
--- old/XS-Parse-Keyword-0.27/lib/XS/Parse/Infix/Builder_data.pm.PL     
2022-10-31 23:09:16.000000000 +0100
+++ new/XS-Parse-Keyword-0.30/lib/XS/Parse/Infix/Builder_data.pm.PL     
2022-12-03 15:51:44.000000000 +0100
@@ -28,7 +28,7 @@
    <$in_h> } );
 
 __DATA__
-package XS::Parse::Infix::Builder_data 0.27;
+package XS::Parse::Infix::Builder_data 0.30;
 
 use v5.14;
 use warnings;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/lib/XS/Parse/Infix.pm 
new/XS-Parse-Keyword-0.30/lib/XS/Parse/Infix.pm
--- old/XS-Parse-Keyword-0.27/lib/XS/Parse/Infix.pm     2022-10-31 
23:09:16.000000000 +0100
+++ new/XS-Parse-Keyword-0.30/lib/XS/Parse/Infix.pm     2022-12-03 
15:51:44.000000000 +0100
@@ -3,7 +3,7 @@
 #
 #  (C) Paul Evans, 2021-2022 -- leon...@leonerd.org.uk
 
-package XS::Parse::Infix 0.27;
+package XS::Parse::Infix 0.30;
 
 use v5.14;
 use warnings;
@@ -72,6 +72,8 @@
 
    bool parse_infix(enum XSParseInfixSelection select, struct XSParseInfixInfo 
**infop);
 
+I<Since version 0.27.>
+
 This function attempts to parse syntax for an infix operator from the current
 parser position. If it is successful, it fills in the variable pointed to by
 I<infop> with a pointer to the actual information structure and returns
@@ -109,6 +111,8 @@
 
       struct XSParseInfixHooks *hooks;
       void                     *hookdata;
+
+      enum XSParseInfixClassification cls;  /* since version 0.28 */
    };
 
 If the operator name contains any non-ASCII characters they are presumed to be
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword/Builder.pm 
new/XS-Parse-Keyword-0.30/lib/XS/Parse/Keyword/Builder.pm
--- old/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword/Builder.pm   2022-10-31 
23:09:16.000000000 +0100
+++ new/XS-Parse-Keyword-0.30/lib/XS/Parse/Keyword/Builder.pm   2022-12-03 
15:51:44.000000000 +0100
@@ -3,7 +3,7 @@
 #
 #  (C) Paul Evans, 2021 -- leon...@leonerd.org.uk
 
-package XS::Parse::Keyword::Builder 0.27;
+package XS::Parse::Keyword::Builder 0.30;
 
 use v5.14;
 use warnings;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword/Builder_data.pm.PL 
new/XS-Parse-Keyword-0.30/lib/XS/Parse/Keyword/Builder_data.pm.PL
--- old/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword/Builder_data.pm.PL   
2022-10-31 23:09:16.000000000 +0100
+++ new/XS-Parse-Keyword-0.30/lib/XS/Parse/Keyword/Builder_data.pm.PL   
2022-12-03 15:51:44.000000000 +0100
@@ -28,7 +28,7 @@
    <$in_h> } );
 
 __DATA__
-package XS::Parse::Keyword::Builder_data 0.27;
+package XS::Parse::Keyword::Builder_data 0.30;
 
 use v5.14;
 use warnings;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword.pm 
new/XS-Parse-Keyword-0.30/lib/XS/Parse/Keyword.pm
--- old/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword.pm   2022-10-31 
23:09:16.000000000 +0100
+++ new/XS-Parse-Keyword-0.30/lib/XS/Parse/Keyword.pm   2022-12-03 
15:51:44.000000000 +0100
@@ -3,7 +3,7 @@
 #
 #  (C) Paul Evans, 2021-2022 -- leon...@leonerd.org.uk
 
-package XS::Parse::Keyword 0.27;
+package XS::Parse::Keyword 0.30;
 
 use v5.14;
 use warnings;
@@ -277,12 +277,71 @@
 
 =head2 XPK_ANONSUB
 
-I<atomic, emits op.>
+I<atomic, emits cv.>
 
 A brace-delimited block of code is expected, and assembled into the body of a
 new anonymous subroutine. This will be passed as a protosub CV in the I<cv>
 field.
 
+=head2 XPK_STAGED_ANONSUB
+
+   XPK_STAGED_ANONSUB(stages ...)
+
+I<structural, emits cv.>
+
+A variant of C<XPK_ANONSUB> which accepts additional function pointers to be
+invoked at various points during parsing and compilation. These can be used to
+interrupt the normal parsing in a manner similar to L<XS::Parse::Sublike>,
+though currently somewhat less flexibly.
+
+The I<stages> list may contain elements of the following types. Not every
+stage must be present, but any that are present must be in the following
+order. Multiple copies of each stage are permitted; they are invoked in the
+written order, with parser code happening inbetween.
+
+=over 4
+
+=item XPK_ANONSUB_PREPARE
+
+   XPK_ANONSUB_PREPARE(&callback)
+
+I<atomic, emits nothing.>
+
+Invokes the callback before C<start_subparse()>.
+
+=item XPK_ANONSUB_START
+
+   XPK_ANONSUB_START(&callback)
+
+I<atomic, emits nothing.>
+
+Invokes the callback after C<block_start()> but before parsing the actual
+block contents.
+
+=item XPK_ANONSUB_END
+
+   OP *op_wrapper_callback(pTHX_ OP *o, void *hookdata);
+
+   XPK_ANONSUB_END(&op_wrapper_callback)
+
+I<atomic, emits nothing.>
+
+Invokes the callback after parsing the block contents but before calling
+C<block_end()>. The callback may modify the optree if required and return a
+new one.
+
+=item XPK_ANONSUB_WRAP
+
+   XPK_ANONSUB_WRAP(&op_wrapper_callback)
+
+I<atomic, emits nothing.>
+
+Invokes the callback after C<block_end()> but before passing the optree to
+C<newATTRSUB()>. The callback may modify the optree if required and return a
+new one.
+
+=back
+
 =head2 XPK_ARITHEXPR
 
 I<atomic, emits op.>
@@ -309,6 +368,18 @@
 
 Variants of C<XPK_TERMEXPR> which puts the expression in void or scalar 
context.
 
+=head2 XPK_PREFIXED_TERMEXPR_ENTERLEAVE
+
+   XPK_PREFIXED_TERMEXPR_ENTERLEAVE(pieces ...)
+
+A variant of C<XPK_TERMEXPR> which expects a sequence pieces first before it
+parses a term expression, similar to how C<XPK_PREFIXED_BLOCK_ENTERLEAVE>
+works. The entire operation is wrapped in an C<ENTER>/C<LEAVE> pair.
+
+This is intended just for use of C<XPK_SETUP> pieces as prefixes. Any other
+pieces which actually parse real input are likely to cause overly-complex,
+subtle, or outright ambiguous grammars, and should be avoided.
+
 =head2 XPK_LISTEXPR
 
 I<atomic, emits op.>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword.xs 
new/XS-Parse-Keyword-0.30/lib/XS/Parse/Keyword.xs
--- old/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword.xs   2022-10-31 
23:09:16.000000000 +0100
+++ new/XS-Parse-Keyword-0.30/lib/XS/Parse/Keyword.xs   2022-12-03 
15:51:44.000000000 +0100
@@ -16,39 +16,6 @@
 #include "keyword.h"
 #include "infix.h"
 
-/* v0 hooks lacked wrapper_func_name */
-struct XSParseInfixHooks_v0 {
-  U32 flags;
-  enum XSParseInfixClassification cls;
-
-  const char *permit_hintkey;
-  bool (*permit) (pTHX_ void *hookdata);
-
-  OP *(*new_op)(pTHX_ U32 flags, OP *lhs, OP *rhs, void *hookdata);
-  OP *(*ppaddr)(pTHX);
-};
-
-static void XSParseInfix_register_v0(pTHX_ const char *opname, const struct 
XSParseInfixHooks_v0 *hooks_v0, void *hookdata)
-{
-  warn("XSParseInfix ABI version 0 is deprecated and will soon be removed");
-
-  struct XSParseInfixHooks *hooks;
-  Newx(hooks, 1, struct XSParseInfixHooks);
-
-  hooks->flags = hooks_v0->flags | (1<<15); /* NO_PARSEDATA */
-  hooks->cls   = hooks_v0->cls;
-
-  hooks->wrapper_func_name = NULL;
-
-  hooks->permit_hintkey = hooks_v0->permit_hintkey;
-  hooks->permit         = hooks_v0->permit;
-  hooks->new_op         = (OP *(*)(pTHX_ U32, OP *, OP *, SV **, void 
*))hooks_v0->new_op;
-  hooks->ppaddr         = hooks_v0->ppaddr;
-  hooks->parse          = NULL;
-
-  XSParseInfix_register(aTHX_ opname, hooks, hookdata);
-}
-
 /* v1 hooks.newop did not pass parsedata */
 struct XSParseInfixHooks_v1 {
   U16 flags;
@@ -108,12 +75,11 @@
   XSParseKeyword_boot(aTHX);
 
 
-  sv_setiv(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/ABIVERSION_MIN", 1), 0);
+  sv_setiv(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/ABIVERSION_MIN", 1), 1);
   sv_setiv(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/ABIVERSION_MAX", 1), 
XSPARSEINFIX_ABI_VERSION);
 
   sv_setuv(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/parse()@2", 1), 
PTR2UV(&XSParseInfix_parse));
   sv_setuv(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/new_op()@0", 1), 
PTR2UV(&XSParseInfix_new_op));
-  sv_setuv(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/register()@0", 1), 
PTR2UV(&XSParseInfix_register_v0));
   sv_setuv(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/register()@1", 1), 
PTR2UV(&XSParseInfix_register_v1));
   sv_setuv(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/register()@2", 1), 
PTR2UV(&XSParseInfix_register));
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/src/infix.c 
new/XS-Parse-Keyword-0.30/src/infix.c
--- old/XS-Parse-Keyword-0.27/src/infix.c       2022-10-31 23:09:16.000000000 
+0100
+++ new/XS-Parse-Keyword-0.30/src/infix.c       2022-12-03 15:51:44.000000000 
+0100
@@ -136,13 +136,13 @@
   struct XSParseInfixInfo info;
 
   STRLEN      oplen;
-  enum XSParseInfixClassification cls;
 
   struct HooksAndData hd;
 
   STRLEN permit_hintkey_len;
 
   int opname_is_WIDE : 1;
+  int opname_is_ident : 1;
 };
 
 static struct Registration *registrations;
@@ -345,8 +345,11 @@
       continue;
     if(!strnEQ(buf, reg->info.opname, reg->oplen))
       continue;
-
-    if(!(selection & (1 << reg->cls)))
+    /* If the operator name is an identifer then we don't want to capture a
+     * longer identifier from the incoming source of which this is just a
+     * prefix
+     */
+    if(reg->opname_is_ident && isIDCONT_utf8_safe(buf + reg->oplen, 
PL_parser->bufend))
       continue;
 
     if(reg->hd.hooks && reg->hd.hooks->permit_hintkey &&
@@ -357,6 +360,12 @@
       !(*reg->hd.hooks->permit)(aTHX_ reg->hd.data))
       continue;
 
+    /* At this point we're committed to this being the best match of operator.
+     * Is it selected by the filter?
+     */
+    if(!(selection & (1 << reg->info.cls)))
+      return FALSE;
+
     *infop = &reg->info;
 
     lex_read_to(PL_parser->bufptr + reg->oplen);
@@ -636,9 +645,9 @@
   reg->info.opname = savepv(opname);
   reg->info.opcode = opcode;
   reg->info.hooks  = NULL;
+  reg->info.cls    = cls;
 
   reg->oplen  = strlen(opname);
-  reg->cls    = cls;
 
   reg->hd.hooks = NULL;
   reg->hd.data  = NULL;
@@ -653,6 +662,27 @@
 
 void XSParseInfix_register(pTHX_ const char *opname, const struct 
XSParseInfixHooks *hooks, void *hookdata)
 {
+  STRLEN oplen = strlen(opname);
+  const char *opname_end = opname + oplen;
+  bool opname_is_ident = isIDFIRST_utf8_safe(opname, opname_end);
+
+  {
+    const char *s = opname;
+    s += UTF8SKIP(s);
+
+    while(s < opname_end) {
+      if(opname_is_ident) {
+        if(!isIDCONT_utf8_safe(s, opname_end))
+          croak("Infix operator name that starts with an identifier may not 
have non-identifier characters in it");
+      }
+      else {
+        if(isIDFIRST_utf8_safe(s, opname_end))
+          croak("Infix operator name that does not start with an identifer may 
not have identifier characters in it");
+      }
+      s += UTF8SKIP(s);
+    }
+  }
+
   switch(hooks->flags) {
     case (1<<15):
       /* undocumented internal flag to indicate v1-compatible ->new_op hook 
function */
@@ -730,9 +760,10 @@
   reg->info.opcode = OP_CUSTOM;
   reg->info.hooks    = hooks;
   reg->info.hookdata = hookdata;
+  reg->info.cls      = hooks->cls;
 
-  reg->oplen  = strlen(opname);
-  reg->cls    = hooks->cls;
+  reg->oplen           = oplen;
+  reg->opname_is_ident = opname_is_ident;
 
   reg->hd.hooks = hooks;
   reg->hd.data  = hookdata;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/src/keyword.c 
new/XS-Parse-Keyword-0.30/src/keyword.c
--- old/XS-Parse-Keyword-0.27/src/keyword.c     2022-10-31 23:09:16.000000000 
+0100
+++ new/XS-Parse-Keyword-0.30/src/keyword.c     2022-12-03 15:51:44.000000000 
+0100
@@ -342,15 +342,36 @@
   croak("TODO: probe_piece on type=%d\n", type);
 }
 
+static void parse_prefix_pieces(pTHX_ SV *argsv, size_t *argidx, const struct 
XSParseKeywordPieceType *pieces, void *hookdata)
+{
+  while(pieces->type) {
+    if(pieces->type == XS_PARSE_KEYWORD_SETUP)
+      (pieces->u.callback)(aTHX_ hookdata);
+    else {
+      parse_piece(aTHX_ argsv, argidx, pieces, hookdata);
+      lex_read_space(0);
+    }
+
+    pieces++;
+  }
+
+  intro_my();  /* in case any of the pieces was XPK_LEXVAR_MY */
+}
+
 static void parse_piece(pTHX_ SV *argsv, size_t *argidx, const struct 
XSParseKeywordPieceType *piece, void *hookdata)
 {
   int argi = *argidx;
 
-  if(argi >= (SvLEN(argsv) / sizeof(XSParseKeywordPiece)))
-    SvGROW(argsv, SvLEN(argsv) * 2);
+#define CHECK_GROW_ARGSV  \
+  do {                                                       \
+    if(argi >= (SvLEN(argsv) / sizeof(XSParseKeywordPiece))) \
+      SvGROW(argsv, SvLEN(argsv) * 2);                       \
+  } while(0)
 
 #define THISARG ((XSParseKeywordPiece *)SvPVX(argsv))[argi]
 
+  CHECK_GROW_ARGSV;
+
   THISARG.line = 
 #if HAVE_PERL_VERSION(5, 20, 0)
     /* on perl 5.20 onwards, CopLINE(PL_curcop) is only set at runtime; during
@@ -399,27 +420,11 @@
       I32 save_ix = block_start(1);
 
       if(piece->u.pieces) {
-        /* The prefix pieces */
-        const struct XSParseKeywordPieceType *pieces = piece->u.pieces;
-
-        while(pieces->type) {
-          if(pieces->type == XS_PARSE_KEYWORD_SETUP)
-            (pieces->u.callback)(aTHX_ hookdata);
-          else {
-            parse_piece(aTHX_ argsv, argidx, pieces, hookdata);
-            lex_read_space(0);
-          }
-
-          pieces++;
-        }
+        parse_prefix_pieces(aTHX_ argsv, argidx, piece->u.pieces, hookdata);
 
         if(*argidx > argi) {
           argi = *argidx;
-
-          if(argi >= (SvLEN(argsv) / sizeof(XSParseKeywordPiece)))
-            SvGROW(argsv, SvLEN(argsv) * 2);
-
-          intro_my();  /* in case any of the pieces was XPK_LEXVAR_MY */
+          CHECK_GROW_ARGSV;
         }
       }
 
@@ -448,16 +453,39 @@
 
     case XS_PARSE_KEYWORD_ANONSUB:
     {
+      const struct XSParseKeywordPieceType *stages = piece->u.pieces;
+
+      while(stages && stages->type == XS_PARSE_KEYWORD_ANONSUB_PREPARE) {
+        (*stages->u.callback)(aTHX_ hookdata);
+        stages++;
+      }
+
       I32 floor_ix = start_subparse(FALSE, CVf_ANON);
       SAVEFREESV(PL_compcv);
 
       I32 save_ix = block_start(0);
+
+      while(stages && stages->type == XS_PARSE_KEYWORD_ANONSUB_START) {
+        (*stages->u.callback)(aTHX_ hookdata);
+        stages++;
+      }
+
       OP *body = parse_block(0);
       CHECK_PARSEFAIL;
 
+      while(stages && stages->type == XS_PARSE_KEYWORD_ANONSUB_END) {
+        body = (*stages->u.op_wrap_callback)(aTHX_ body, hookdata);
+        stages++;
+      }
+
       SvREFCNT_inc(PL_compcv);
       body = block_end(save_ix, body);
 
+      while(stages && stages->type == XS_PARSE_KEYWORD_ANONSUB_WRAP) {
+        body = (*stages->u.op_wrap_callback)(aTHX_ body, hookdata);
+        stages++;
+      }
+
       THISARG.cv = newATTRSUB(floor_ix, NULL, NULL, NULL, body);
       (*argidx)++;
       return;
@@ -465,6 +493,19 @@
 
     case XS_PARSE_KEYWORD_ARITHEXPR:
     case XS_PARSE_KEYWORD_TERMEXPR:
+    {
+      if(is_enterleave)
+        ENTER;
+
+      if(piece->u.pieces) {
+        parse_prefix_pieces(aTHX_ argsv, argidx, piece->u.pieces, hookdata);
+
+        if(*argidx > argi) {
+          argi = *argidx;
+          CHECK_GROW_ARGSV;
+        }
+      }
+
       /* TODO: This auto-parens behaviour ought to be tuneable, depend on how
        * many args, open at i=0 and close at i=MAX, etc...
        */
@@ -495,7 +536,12 @@
         THISARG.op = op_contextualize(THISARG.op, want);
 
       (*argidx)++;
+
+      if(is_enterleave)
+        LEAVE;
+
       return;
+    }
 
     case XS_PARSE_KEYWORD_LISTEXPR:
       THISARG.op = parse_listexpr(0);
@@ -787,9 +833,13 @@
   if(hooks->build) {
     /* build function takes an array of pointers to piece structs, so we can
      * add new fields to the end of them without breaking back-compat. */
-    SV *ptrssv = newSV(argidx * sizeof(XSParseKeywordPiece *));
-    XSParseKeywordPiece **argptrs = (XSParseKeywordPiece **)SvPVX(ptrssv);
-    SAVEFREESV(ptrssv);
+    XSParseKeywordPiece **argptrs = NULL;
+    if(argidx) {
+      SV *ptrssv = newSV(argidx * sizeof(XSParseKeywordPiece *));
+      SAVEFREESV(ptrssv);
+
+      argptrs = (XSParseKeywordPiece **)SvPVX(ptrssv);
+    }
 
     int i;
     for(i = 0; i < argidx; i++)
@@ -813,11 +863,13 @@
       if(ret && (ret != KEYWORD_PLUGIN_EXPR))
         yycroakf("Expected parse function for '%s' keyword to return 
KEYWORD_PLUGIN_EXPR but it did not",
           reg->kwname);
+      break;
 
     case XPK_FLAG_STMT:
       if(ret && (ret != KEYWORD_PLUGIN_STMT))
         yycroakf("Expected parse function for '%s' keyword to return 
KEYWORD_PLUGIN_STMT but it did not",
           reg->kwname);
+      break;
   }
 
   return ret;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/t/32pieces-anonsub.t 
new/XS-Parse-Keyword-0.30/t/32pieces-anonsub.t
--- old/XS-Parse-Keyword-0.27/t/32pieces-anonsub.t      2022-10-31 
23:09:16.000000000 +0100
+++ new/XS-Parse-Keyword-0.30/t/32pieces-anonsub.t      2022-12-03 
15:51:44.000000000 +0100
@@ -16,4 +16,13 @@
    is( $ret->(), "sub value", 'result of invoking' );
 }
 
+{
+   my $ret = piecestagedanonsub { return "$VAR, world" };
+
+   is( ref $ret, "CODE", 'result of piecestagedanonsub is CODE reference' );
+   is( $ret->(), "Hello, world", 'result of invoking' );
+
+   is( $::STAGES, "PREPARE,START,END,WRAP", 'All ANONSUB stages were invoked' 
);
+}
+
 done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/t/33pieces-termexpr.t 
new/XS-Parse-Keyword-0.30/t/33pieces-termexpr.t
--- old/XS-Parse-Keyword-0.27/t/33pieces-termexpr.t     2022-10-31 
23:09:16.000000000 +0100
+++ new/XS-Parse-Keyword-0.30/t/33pieces-termexpr.t     2022-12-03 
15:51:44.000000000 +0100
@@ -35,4 +35,9 @@
    is( $ret, "(x)y", 'termexpr treats (PARENS) as entire expression' );
 }
 
+{
+   $ret = pieceprefixedtermexpr_VAR $VAR . ", world!";
+   is( $ret, "(Hello, world!)", 'result of pieceprefixedtermexpr_VAR' );
+}
+
 done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.27/t/pieces.xs 
new/XS-Parse-Keyword-0.30/t/pieces.xs
--- old/XS-Parse-Keyword-0.27/t/pieces.xs       2022-10-31 23:09:16.000000000 
+0100
+++ new/XS-Parse-Keyword-0.30/t/pieces.xs       2022-12-03 15:51:44.000000000 
+0100
@@ -134,6 +134,40 @@
   sv_setpvs(PAD_SVl(padix), "Hello");
 }
 
+static void callback_catpv_stages(pTHX_ const char *pv)
+{
+  SV *sv = get_sv("main::STAGES", GV_ADD);
+  if(!SvPOK(sv))
+    sv_setpvs(sv, "");
+
+  if(SvCUR(sv))
+    sv_catpvs(sv, ",");
+
+  sv_catpv(sv, pv);
+}
+
+static void callback_PREPARE(pTHX_ void *hookdata)
+{
+  callback_catpv_stages(aTHX_ "PREPARE");
+}
+
+static void callback_START(pTHX_ void *hookdata)
+{
+  callback_catpv_stages(aTHX_ "START");
+}
+
+static OP *callback_END(pTHX_ OP *o, void *hookdata)
+{
+  callback_catpv_stages(aTHX_ "END");
+  return o;
+}
+
+static OP *callback_WRAP(pTHX_ OP *o, void *hookdata)
+{
+  callback_catpv_stages(aTHX_ "WRAP");
+  return o;
+}
+
 static const struct XSParseKeywordHooks hooks_block = {
   .permit_hintkey = hintkey,
 
@@ -177,6 +211,19 @@
   .build1 = &build_anonsub,
 };
 
+static const struct XSParseKeywordHooks hooks_stagedanonsub = {
+  .permit_hintkey = hintkey,
+
+  .piece1 = XPK_STAGED_ANONSUB(
+    XPK_ANONSUB_PREPARE(&callback_PREPARE),
+    XPK_ANONSUB_START(&callback_START),
+    XPK_ANONSUB_START(&setup_block_VAR),
+    XPK_ANONSUB_END(&callback_END),
+    XPK_ANONSUB_WRAP(&callback_WRAP)
+  ),
+  .build1 = &build_anonsub,
+};
+
 static const struct XSParseKeywordHooks hooks_arithexpr = {
   .permit_hintkey = hintkey,
 
@@ -191,6 +238,13 @@
   .build1 = &build_expr,
 };
 
+static const struct XSParseKeywordHooks hooks_prefixedtermexpr_VAR = {
+  .permit_hintkey = hintkey,
+
+  .piece1 = XPK_PREFIXED_TERMEXPR_ENTERLEAVE( XPK_SETUP(&setup_block_VAR) ),
+  .build1 = &build_expr,
+};
+
 static const struct XSParseKeywordHooks hooks_listexpr = {
   .permit_hintkey = hintkey,
 
@@ -312,10 +366,15 @@
   register_xs_parse_keyword("pieceprefixedblock_VAR", 
&hooks_prefixedblock_VAR, "$VAR");
 
   register_xs_parse_keyword("pieceanonsub", &hooks_anonsub, NULL);
+
+  register_xs_parse_keyword("piecestagedanonsub", &hooks_stagedanonsub, 
"$VAR");
+
   register_xs_parse_keyword("piecearithexpr", &hooks_arithexpr, NULL);
   register_xs_parse_keyword("piecetermexpr", &hooks_termexpr, NULL);
   register_xs_parse_keyword("piecelistexpr", &hooks_listexpr, NULL);
 
+  register_xs_parse_keyword("pieceprefixedtermexpr_VAR", 
&hooks_prefixedtermexpr_VAR, "$VAR");
+
   register_xs_parse_keyword("pieceident", &hooks_ident, NULL);
   register_xs_parse_keyword("pieceident_opt", &hooks_ident_opt, NULL);
   register_xs_parse_keyword("piecepkg", &hooks_packagename, NULL);

Reply via email to