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-11-09 12:56:30
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/perl-XS-Parse-Keyword (Old)
 and      /work/SRC/openSUSE:Factory/.perl-XS-Parse-Keyword.new.1597 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "perl-XS-Parse-Keyword"

Wed Nov  9 12:56:30 2022 rev:9 rq:1034531 version:0.27

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/perl-XS-Parse-Keyword/perl-XS-Parse-Keyword.changes  
    2022-08-17 18:23:04.175168450 +0200
+++ 
/work/SRC/openSUSE:Factory/.perl-XS-Parse-Keyword.new.1597/perl-XS-Parse-Keyword.changes
    2022-11-09 12:56:40.200089005 +0100
@@ -1,0 +2,24 @@
+Tue Nov  1 03:08:08 UTC 2022 - Tina M??ller <timueller+p...@suse.de>
+
+- updated to 0.27
+   see /usr/share/doc/packages/perl-XS-Parse-Keyword/Changes
+
+  0.27    2022-10-31
+          [CHANGES]
+           * Updates to XS::Parse::Infix for latest `infix-plugin` perl5 branch
+              + parsedata field is now an SV **, not an ANY *
+           * Expose parse_infix() as a real ABI function, allowing infix
+             operators to be hyper-operators and parse other operator names
+
+  0.26    2022-10-24
+          [CHANGES]
+           * Updates to XS::Parse::Infix for latest `infix-plugin` perl5 branch
+              + Requires classification to set the operator precedence
+              + No longer need XPI_OPERAND_ARITH or XPI_OPERAND_TERM; most of
+                .lhs_flags and .rhs_flags are redundant now
+              + No longer support XPI_OPERAND_CUSTOM
+              + Optional `parse` phase for parametric/hyper-operators
+           * Bump XS::Parse::Infix ABI version to 2
+           * Declare XPI ABI v0 as deprecated, soon to be removed
+
+-------------------------------------------------------------------

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

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

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

Other differences:
------------------
++++++ perl-XS-Parse-Keyword.spec ++++++
--- /var/tmp/diff_new_pack.S8cUwP/_old  2022-11-09 12:56:40.784092297 +0100
+++ /var/tmp/diff_new_pack.S8cUwP/_new  2022-11-09 12:56:40.788092320 +0100
@@ -18,7 +18,7 @@
 
 %define cpan_name XS-Parse-Keyword
 Name:           perl-XS-Parse-Keyword
-Version:        0.25
+Version:        0.27
 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.25.tar.gz -> XS-Parse-Keyword-0.27.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/Build.PL 
new/XS-Parse-Keyword-0.27/Build.PL
--- old/XS-Parse-Keyword-0.25/Build.PL  2022-07-26 00:36:23.000000000 +0200
+++ new/XS-Parse-Keyword-0.27/Build.PL  2022-10-31 23:09:16.000000000 +0100
@@ -54,7 +54,12 @@
 #include "perl.h"
 #include "XSUB.h"
 
-int main(void) { struct Perl_custom_infix def; return 0; }
+int main(void) {
+   struct Perl_custom_infix def;
+   def.prec = INFIX_PREC_LOW;
+   def.build_op = NULL;
+   return 0;
+}
 EOF
    ) if $] >= 5.037000; # maybe I'll start this in 5.37...
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/Changes 
new/XS-Parse-Keyword-0.27/Changes
--- old/XS-Parse-Keyword-0.25/Changes   2022-07-26 00:36:23.000000000 +0200
+++ new/XS-Parse-Keyword-0.27/Changes   2022-10-31 23:09:16.000000000 +0100
@@ -1,5 +1,23 @@
 Revision history for XS-Parse-Keyword
 
+0.27    2022-10-31
+        [CHANGES]
+         * Updates to XS::Parse::Infix for latest `infix-plugin` perl5 branch
+            + parsedata field is now an SV **, not an ANY *
+         * Expose parse_infix() as a real ABI function, allowing infix
+           operators to be hyper-operators and parse other operator names
+
+0.26    2022-10-24
+        [CHANGES]
+         * Updates to XS::Parse::Infix for latest `infix-plugin` perl5 branch
+            + Requires classification to set the operator precedence
+            + No longer need XPI_OPERAND_ARITH or XPI_OPERAND_TERM; most of
+              .lhs_flags and .rhs_flags are redundant now
+            + No longer support XPI_OPERAND_CUSTOM
+            + Optional `parse` phase for parametric/hyper-operators
+         * Bump XS::Parse::Infix ABI version to 2
+         * Declare XPI ABI v0 as deprecated, soon to be removed
+
 0.25    2022-07-25
         [CHANGES]
          * Permit infix operators to consume fewer than all the available
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/MANIFEST 
new/XS-Parse-Keyword-0.27/MANIFEST
--- old/XS-Parse-Keyword-0.25/MANIFEST  2022-07-26 00:36:23.000000000 +0200
+++ new/XS-Parse-Keyword-0.27/MANIFEST  2022-10-31 23:09:16.000000000 +0100
@@ -6,6 +6,7 @@
 hax/make_argcheck_ops.c.inc
 hax/newOP_CUSTOM.c.inc
 hax/op_sibling_splice.c.inc
+hax/optree-additions.c.inc
 hax/perl-backcompat.c.inc
 hax/wrap_keyword_plugin.c.inc
 inc/Module/Build/with/XSTests.pm
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/META.json 
new/XS-Parse-Keyword-0.27/META.json
--- old/XS-Parse-Keyword-0.25/META.json 2022-07-26 00:36:23.000000000 +0200
+++ new/XS-Parse-Keyword-0.27/META.json 2022-10-31 23:09:16.000000000 +0100
@@ -40,19 +40,19 @@
    "provides" : {
       "XS::Parse::Infix" : {
          "file" : "lib/XS/Parse/Infix.pm",
-         "version" : "0.25"
+         "version" : "0.27"
       },
       "XS::Parse::Infix::Builder" : {
          "file" : "lib/XS/Parse/Infix/Builder.pm",
-         "version" : "0.25"
+         "version" : "0.27"
       },
       "XS::Parse::Keyword" : {
          "file" : "lib/XS/Parse/Keyword.pm",
-         "version" : "0.25"
+         "version" : "0.27"
       },
       "XS::Parse::Keyword::Builder" : {
          "file" : "lib/XS/Parse/Keyword/Builder.pm",
-         "version" : "0.25"
+         "version" : "0.27"
       }
    },
    "release_status" : "stable",
@@ -61,6 +61,6 @@
          "http://dev.perl.org/licenses/";
       ]
    },
-   "version" : "0.25",
+   "version" : "0.27",
    "x_serialization_backend" : "JSON::PP version 4.06"
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/META.yml 
new/XS-Parse-Keyword-0.27/META.yml
--- old/XS-Parse-Keyword-0.25/META.yml  2022-07-26 00:36:23.000000000 +0200
+++ new/XS-Parse-Keyword-0.27/META.yml  2022-10-31 23:09:16.000000000 +0100
@@ -19,19 +19,19 @@
 provides:
   XS::Parse::Infix:
     file: lib/XS/Parse/Infix.pm
-    version: '0.25'
+    version: '0.27'
   XS::Parse::Infix::Builder:
     file: lib/XS/Parse/Infix/Builder.pm
-    version: '0.25'
+    version: '0.27'
   XS::Parse::Keyword:
     file: lib/XS/Parse/Keyword.pm
-    version: '0.25'
+    version: '0.27'
   XS::Parse::Keyword::Builder:
     file: lib/XS/Parse/Keyword/Builder.pm
-    version: '0.25'
+    version: '0.27'
 requires:
   perl: '5.014'
 resources:
   license: http://dev.perl.org/licenses/
-version: '0.25'
+version: '0.27'
 x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/XSParseInfix.h 
new/XS-Parse-Keyword-0.27/XSParseInfix.h
--- old/XS-Parse-Keyword-0.25/XSParseInfix.h    2022-07-26 00:36:23.000000000 
+0200
+++ new/XS-Parse-Keyword-0.27/XSParseInfix.h    2022-10-31 23:09:16.000000000 
+0100
@@ -1,7 +1,7 @@
 #ifndef __XS_PARSE_INFIX_H__
 #define __XS_PARSE_INFIX_H__
 
-#define XSPARSEINFIX_ABI_VERSION 1
+#define XSPARSEINFIX_ABI_VERSION 2
 
 /* Infix operator classifications */
 /* No built-in operators use the _MISC categories, but they are provided for
@@ -16,6 +16,10 @@
   XPI_CLS_ISA,         /*  ... the predicate instance of (isa) */
   XPI_CLS_MATCH_MISC,  /*  ... any other match-like predicate */
   XPI_CLS_ORDERING,    /* cmp or <=> */
+
+  XPI_CLS_ADD_MISC,    /* an operator at addition-like precedence */
+  XPI_CLS_MUL_MISC,    /* an operator at multiplication-like precedence */
+  XPI_CLS_POW_MISC,    /* an operator at power exponentiation-like precedence 
*/
 };
 
 enum XSParseInfixSelection {
@@ -31,16 +35,16 @@
 
 /* lhs_flags, rhs_flags */
 enum {
-  /* other space reserved for other scalar types */
-  XPI_OPERAND_ARITH     = 2,
-  XPI_OPERAND_TERM      = 4,
   XPI_OPERAND_TERM_LIST = 6, /* term in list context */
   XPI_OPERAND_LIST      = 7, /* list in list context */
 
   /* Other bitflags */
   XPI_OPERAND_ONLY_LOOK = (1<<3),
-  XPI_OPERAND_CUSTOM    = (1<<7), /* rhs_flags only */
 };
+// No longer used
+#define XPI_OPERAND_ARITH 0
+#define XPI_OPERAND_TERM  0
+#define XPI_OPERAND_CUSTOM (1<<7)
 
 struct XSParseInfixHooks {
   U16 flags;
@@ -54,11 +58,11 @@
   bool (*permit) (pTHX_ void *hookdata);
 
   /* These hooks are alternatives; the first one defined is used */
-  OP *(*new_op)(pTHX_ U32 flags, OP *lhs, OP *rhs, void *hookdata);
+  OP *(*new_op)(pTHX_ U32 flags, OP *lhs, OP *rhs, SV **parsedata, void 
*hookdata);
   OP *(*ppaddr)(pTHX); /* A pp func used directly in newBINOP_custom() */
 
-  /* Used if rhs_flags & XPI_OPERAND_CUSTOM */
-  OP *(*parse_rhs)(pTHX_ void *hookdata);
+  /* optional */
+  void (*parse)(pTHX_ U32 flags, SV **parsedata, void *hookdata);
 };
 
 struct XSParseInfixInfo {
@@ -69,6 +73,18 @@
   void *hookdata;
 };
 
+static bool (*parse_infix_func)(pTHX_ enum XSParseInfixSelection select, 
struct XSParseInfixInfo **infop);
+#define parse_infix(select, infop) S_parse_infix(aTHX_ select, infop)
+static bool S_parse_infix(pTHX_ enum XSParseInfixSelection select, struct 
XSParseInfixInfo **infop)
+{
+  if(!parse_infix_func)
+    croak("Must call boot_xs_parse_infix() first");
+
+  struct XSParseInfixInfo *infocopy;
+
+  return (*parse_infix_func)(aTHX_ select, infop);
+}
+
 static OP *(*xs_parse_infix_new_op_func)(pTHX_ const struct XSParseInfixInfo 
*info, U32 flags, OP *lhs, OP *rhs);
 #define xs_parse_infix_new_op(info, flags, lhs, rhs)  
S_xs_parse_infix_new_op(aTHX_ info, flags, lhs, rhs)
 static OP *S_xs_parse_infix_new_op(pTHX_ const struct XSParseInfixInfo *info, 
U32 flags, OP *lhs, OP *rhs)
@@ -111,10 +127,12 @@
     croak("XS::Parse::Infix ABI version mismatch - library supports <= %d, 
compiled for %d",
         abi_ver, XSPARSEINFIX_ABI_VERSION);
 
+  parse_infix_func = INT2PTR(bool (*)(pTHX_ enum XSParseInfixSelection, struct 
XSParseInfixInfo **),
+      SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/parse()@2", 0)));
   xs_parse_infix_new_op_func = INT2PTR(OP *(*)(pTHX_ const struct 
XSParseInfixInfo *, U32, OP *, OP *),
       SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/new_op()@0", 0)));
   register_xs_parse_infix_func = INT2PTR(void (*)(pTHX_ const char *, const 
struct XSParseInfixHooks *, void *),
-      SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/register()@1", 0)));
+      SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/register()@2", 0)));
 }
 
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/hax/optree-additions.c.inc 
new/XS-Parse-Keyword-0.27/hax/optree-additions.c.inc
--- old/XS-Parse-Keyword-0.25/hax/optree-additions.c.inc        1970-01-01 
01:00:00.000000000 +0100
+++ new/XS-Parse-Keyword-0.27/hax/optree-additions.c.inc        2022-10-31 
23:09:16.000000000 +0100
@@ -0,0 +1,92 @@
+/* vi: set ft=c : */
+
+#define newAELEMOP(flags, first, key)  S_newAELEMOP(aTHX_ flags, first, key)
+static OP *S_newAELEMOP(pTHX_ U32 flags, OP *first, I32 key)
+{
+#if HAVE_PERL_VERSION(5, 16, 0)
+  if(key >= -128 && key < 128 && first->op_type == OP_PADAV) {
+    OP *o = newOP(OP_AELEMFAST_LEX, flags);
+    o->op_private = (I8)key;
+    o->op_targ = first->op_targ;
+    op_free(first);
+    return o;
+  }
+#endif
+
+  return newBINOP(OP_AELEM, flags, first, newSVOP(OP_CONST, 0, newSViv(key)));
+}
+
+#define newPADxVOP(type, flags, padix)  S_newPADxVOP(aTHX_ type, flags, padix)
+static OP *S_newPADxVOP(pTHX_ I32 type, I32 flags, PADOFFSET padix)
+{
+  OP *op = newOP(type, flags);
+  op->op_targ = padix;
+  return op;
+}
+
+#if HAVE_PERL_VERSION(5, 22, 0)
+#  define HAVE_UNOP_AUX
+#endif
+
+#ifndef HAVE_UNOP_AUX
+typedef struct UNOP_with_IV {
+  UNOP baseop;
+  IV   iv;
+} UNOP_with_IV;
+
+#define newUNOP_with_IV(type, flags, first, iv)  S_newUNOP_with_IV(aTHX_ type, 
flags, first, iv)
+static OP *S_newUNOP_with_IV(pTHX_ I32 type, I32 flags, OP *first, IV iv)
+{
+  /* Cargoculted from perl's op.c:Perl_newUNOP()
+   */
+  UNOP_with_IV *op = PerlMemShared_malloc(sizeof(UNOP_with_IV) * 1);
+  NewOp(1101, op, 1, UNOP_with_IV);
+
+  if(!first)
+    first = newOP(OP_STUB, 0);
+  UNOP *unop = (UNOP *)op;
+  unop->op_type = (OPCODE)type;
+  unop->op_first = first;
+  unop->op_ppaddr = NULL;
+  unop->op_flags = (U8)flags | OPf_KIDS;
+  unop->op_private = (U8)(1 | (flags >> 8));
+
+  op->iv = iv;
+
+  return (OP *)op;
+}
+#endif
+
+#define newMETHOD_REDIR_OP(rclass, methname, flags)  
S_newMETHOD_REDIR_OP(aTHX_ rclass, methname, flags)
+static OP *S_newMETHOD_REDIR_OP(pTHX_ SV *rclass, SV *methname, I32 flags)
+{
+#if HAVE_PERL_VERSION(5, 22, 0)
+  OP *op = newMETHOP_named(OP_METHOD_REDIR, flags, methname);
+#  ifdef USE_ITHREADS
+  {
+    /* cargoculted from S_op_relocate_sv() */
+    PADOFFSET ix = pad_alloc(OP_CONST, SVf_READONLY);
+    PAD_SETSV(ix, rclass);
+    cMETHOPx(op)->op_rclass_targ = ix;
+  }
+#  else
+  cMETHOPx(op)->op_rclass_sv = rclass;
+#  endif
+#else
+  OP *op = newUNOP(OP_METHOD, flags,
+    newSVOP(OP_CONST, 0, newSVpvf("%" SVf "::%" SVf, rclass, methname)));
+#endif
+
+  return op;
+}
+
+/* If `@_` is called "snail", then elements of it can be called "slugs"; i.e.
+ * snails without their container
+ */
+#define newSLUGOP(idx)  S_newSLUGOP(aTHX_ idx)
+static OP *S_newSLUGOP(pTHX_ int idx)
+{
+  OP *op = newGVOP(OP_AELEMFAST, 0, PL_defgv);
+  op->op_private = idx;
+  return op;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/hax/perl-backcompat.c.inc 
new/XS-Parse-Keyword-0.27/hax/perl-backcompat.c.inc
--- old/XS-Parse-Keyword-0.25/hax/perl-backcompat.c.inc 2022-07-26 
00:36:23.000000000 +0200
+++ new/XS-Parse-Keyword-0.27/hax/perl-backcompat.c.inc 2022-10-31 
23:09:16.000000000 +0100
@@ -34,6 +34,16 @@
 
 #if !HAVE_PERL_VERSION(5, 22, 0)
 #  define CvPADLIST_set(cv, padlist)  (CvPADLIST(cv) = padlist)
+#  define newPADNAMEpvn(p,n)      S_newPADNAMEpvn(aTHX_ p,n)
+static PADNAME *S_newPADNAMEpvn(pTHX_ const char *pv, STRLEN n)
+{
+  PADNAME *pn = newSVpvn(pv, n);
+  /* PADNAMEs need to be at least SVt_PVNV in order to store the COP_SEQ_*
+   * fields */
+  sv_upgrade(pn, SVt_PVNV);
+  return pn;
+}
+#  define PadnameREFCNT_dec(pn)   SvREFCNT_dec(pn)
 #endif
 
 #ifndef av_count
@@ -149,3 +159,32 @@
 #  define isIDFIRST_utf8_safe(s, e)  (PERL_UNUSED_ARG(e), isIDFIRST_utf8(s))
 #  define isIDCONT_utf8_safe(s, e)   (PERL_UNUSED_ARG(e), isIDCONT_utf8(s))
 #endif
+
+#if !HAVE_PERL_VERSION(5, 26, 0)
+#  define sv_set_undef(sv)  sv_setsv(sv, &PL_sv_undef)
+#endif
+
+#ifndef newAVav
+#  define newAVav(av)  S_newAVav(aTHX_ av)
+static AV *S_newAVav(pTHX_ AV *av)
+{
+  AV *ret = newAV();
+  U32 count = av_count(av);
+  U32 i;
+  for(i = 0; i < count; i++)
+    av_push(ret, newSVsv(AvARRAY(av)[i]));
+  return ret;
+}
+#endif
+
+#if !defined(sv_derived_from_hv) && HAVE_PERL_VERSION(5, 16, 0)
+#  define sv_derived_from_hv(sv, hv)  MY_sv_derived_from_hv(aTHX_ sv, hv)
+static bool MY_sv_derived_from_hv(pTHX_ SV *sv, HV *hv)
+{
+  char *hvname = HvNAME(hv);
+  if(!hvname)
+    return FALSE;
+
+  return sv_derived_from_pvn(sv, hvname, HvNAMELEN(hv), HvNAMEUTF8(hv) ? 
SVf_UTF8 : 0);
+}
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/lib/XS/Parse/Infix/Builder.pm 
new/XS-Parse-Keyword-0.27/lib/XS/Parse/Infix/Builder.pm
--- old/XS-Parse-Keyword-0.25/lib/XS/Parse/Infix/Builder.pm     2022-07-26 
00:36:23.000000000 +0200
+++ new/XS-Parse-Keyword-0.27/lib/XS/Parse/Infix/Builder.pm     2022-10-31 
23:09:16.000000000 +0100
@@ -3,7 +3,7 @@
 #
 #  (C) Paul Evans, 2021 -- leon...@leonerd.org.uk
 
-package XS::Parse::Infix::Builder 0.25;
+package XS::Parse::Infix::Builder 0.27;
 
 use v5.14;
 use warnings;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/XS-Parse-Keyword-0.25/lib/XS/Parse/Infix/Builder_data.pm.PL 
new/XS-Parse-Keyword-0.27/lib/XS/Parse/Infix/Builder_data.pm.PL
--- old/XS-Parse-Keyword-0.25/lib/XS/Parse/Infix/Builder_data.pm.PL     
2022-07-26 00:36:23.000000000 +0200
+++ new/XS-Parse-Keyword-0.27/lib/XS/Parse/Infix/Builder_data.pm.PL     
2022-10-31 23:09:16.000000000 +0100
@@ -28,7 +28,7 @@
    <$in_h> } );
 
 __DATA__
-package XS::Parse::Infix::Builder_data 0.25;
+package XS::Parse::Infix::Builder_data 0.27;
 
 use v5.14;
 use warnings;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/lib/XS/Parse/Infix.pm 
new/XS-Parse-Keyword-0.27/lib/XS/Parse/Infix.pm
--- old/XS-Parse-Keyword-0.25/lib/XS/Parse/Infix.pm     2022-07-26 
00:36:23.000000000 +0200
+++ new/XS-Parse-Keyword-0.27/lib/XS/Parse/Infix.pm     2022-10-31 
23:09:16.000000000 +0100
@@ -1,9 +1,9 @@
 #  You may distribute under the terms of either the GNU General Public License
 #  or the Artistic License (the same terms as Perl itself)
 #
-#  (C) Paul Evans, 2021 -- leon...@leonerd.org.uk
+#  (C) Paul Evans, 2021-2022 -- leon...@leonerd.org.uk
 
-package XS::Parse::Infix 0.25;
+package XS::Parse::Infix 0.27;
 
 use v5.14;
 use warnings;
@@ -68,6 +68,15 @@
 
    boot_xs_parse_infix(0.14);
 
+=head2 parse_infix
+
+   bool parse_infix(enum XSParseInfixSelection select, struct XSParseInfixInfo 
**infop);
+
+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
+C<true>. If no suitable operator is found, returns C<false>.
+
 =head2 xs_parse_infix_new_op
 
    OP *xs_parse_infix_new_op(const struct XSParseInfixInfo *info, U32 flags,
@@ -79,7 +88,7 @@
 
 The C<info> structure pointer would be obtained from the C<infix> field of the
 result of invoking the various C<XPK_INFIX_*> token types from
-C<XS::Parse::Keyword>.
+C<XS::Parse::Keyword>, or by calling L</parse_infix> directly.
 
 =head2 register_xs_parse_infix
 
@@ -88,8 +97,8 @@
 
 This function installs a set of parsing hooks to be associated with the given
 operator name. This new operator will then be available via
-L<XS::Parse::Keyword> by the various C<XPK_INFIX_*> token types, or to core
-perl's C<PL_infix_plugin> if availble.
+L<XS::Parse::Keyword> by the various C<XPK_INFIX_*> token types,
+L</parse_infix>, or to core perl's C<PL_infix_plugin> if available.
 
 These tokens will all yield an info structure, with the following fields:
 
@@ -123,8 +132,11 @@
       const char *permit_hintkey;
       bool (*permit)(pTHX_ void *hookdata);
 
-      OP *(*new_op)(pTHX_ U32 flags, OP *lhs, OP *rhs, void *hookdata);
+      OP *(*new_op)(pTHX_ U32 flags, OP *lhs, OP *rhs, ANY *parsedata, void 
*hookdata);
       OP *(*ppaddr)(pTHX);
+
+      /* optional */
+      void (*parse)(pTHX_ U32 flags, ANY *parsedata, void *hookdata);
    };
 
 =head2 Flags
@@ -132,32 +144,30 @@
 The C<flags> field is currently ignored. It is defined simply to reserve the
 space in case used in a later version. It should be set to zero.
 
-The C<rhs_flags> field gives details on how to parse and handle the right-hand
-side of the operator syntax. It should be set to one of the following 
constants:
+The C<lhs_flags> and C<rhs_flags> fields give details on how to handle the
+left- and right-hand side operands, respectively.
 
-=over 4
+It should be set to one of the following constants, or left as zero:
 
-=item XPI_OPERAND_ARITH
-
-The operand is an arithmetic expression.
-
-=item XPI_OPERAND_TERM
-
-The operand is a term expression.
+=over 4
 
 =item XPI_OPERAND_TERM_LIST
 
-The operand is a term expression. It will be foced into list context,
-preserving the C<OP_PUSHMARK> at the beginning. This means that the ppfunc for
-this infix operator will have to C<POPMARK> to find that.
+The operand will be foced into list context, preserving the C<OP_PUSHMARK> at
+the beginning. This means that the ppfunc for this infix operator will have to
+C<POPMARK> to find that.
 
 =item XPI_OPERAND_LIST
 
-The operand is a list expression. It will be forced into list context, the
-same as above.
+The same as above.
 
 =back
 
+Older versions used to provide constants named C<XPI_OPERAND_ARITH> and
+C<XPI_OPERAND_TERM> but they related to an older version of the core perl
+branch. These names are now aliases for zero, and can be removed from new
+code.
+
 In addition the following extra bitflags are defined:
 
 =over 4
@@ -183,12 +193,6 @@
 
 =back
 
-The C<lhs_flags> field gives details on how to handle the left-hand side of
-the operator syntax. It takes similar values to C<rhs_flags>, except that it
-does not accept the C<XPI_OPERAND_LIST> value. Parsing always happens on just
-a term expression, though it may be placed into list context (which therefore
-still permits things like parenthesized lists, or array variables).
-
 =head2 The Selection Stage
 
 The C<cls> field gives a "classification" of the operator, suggesting what
@@ -214,6 +218,18 @@
 If neither is present then the keyword is always permitted - which is likely
 not what you wanted to do.
 
+=head2 The C<parse> Stage
+
+If the optional C<parse> hook function is present, it is called immediately
+after the parser has recognised the presence of the named operator itself but
+before it attempts to consume the right-hand side term. This hook function can
+attempt further parsing, in order to implement more complex syntax such as
+hyper-operators.
+
+When invoked, it is passed a pointer to an C<ANY>-typed storage variable. It
+is free to use whichever field of this variable it desires to store a result,
+which will then later be made available to the C<new_op> function.
+
 =head2 The Op Generation Stage
 
 If the infix operator is going to be used, then one of the C<new_op> or the
@@ -221,8 +237,14 @@
 
 If C<new_op> is defined then it will be used, and is expected to return an
 optree fragment that consumes the LHS and RHS arguments to implement the
-semantics of the operator. If this is not present, then the C<ppaddr> will be
-used instead to construct a new BINOP of the C<OP_CUSTOM> type.
+semantics of the operator. If the optional C<parse> stage had been present
+earlier, the C<ANY> pointer passed here will point to the same storage that
+C<parse> had previously had access to, so it can retrieve the results.
+
+If C<new_op> is not present, then the C<ppaddr> will be used instead to
+construct a new BINOP of the C<OP_CUSTOM> type. If an earlier C<parse> stage
+had stored additional results into the C<ANY> variable these will be lost
+here.
 
 =head2 The Wrapper Function
 
@@ -322,6 +344,11 @@
 The first registration will create the wrapper function; the subsequent one
 will skip it because it would otherwise be identical.
 
+Note that when generating an optree for a wrapper function call, the C<new_op>
+hook function will be invoked with a C<NULL> pointer for the C<ANY>-typed
+parse data storage, as there won't be an opporunity for the C<parse> hook to
+run in this case.
+
 =cut
 
 =head1 DEPARSE
@@ -423,6 +450,12 @@
 anon-array argument forms (C<WRAPPERFUNC( \@lhs, \@rhs )> or
 C<WRAPPERFUNC( [LHS], [RHS] )>).
 
+=item *
+
+Further thoughts about how infix operators with C<parse> hooks will work with
+automatic deparse, and also how to integrate them with L<XS::Parse::Keyword>'s
+grammar piece.
+
 =back
 
 =cut
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/XS-Parse-Keyword-0.25/lib/XS/Parse/Keyword/Builder.pm 
new/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword/Builder.pm
--- old/XS-Parse-Keyword-0.25/lib/XS/Parse/Keyword/Builder.pm   2022-07-26 
00:36:23.000000000 +0200
+++ new/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword/Builder.pm   2022-10-31 
23:09:16.000000000 +0100
@@ -3,7 +3,7 @@
 #
 #  (C) Paul Evans, 2021 -- leon...@leonerd.org.uk
 
-package XS::Parse::Keyword::Builder 0.25;
+package XS::Parse::Keyword::Builder 0.27;
 
 use v5.14;
 use warnings;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/XS-Parse-Keyword-0.25/lib/XS/Parse/Keyword/Builder_data.pm.PL 
new/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword/Builder_data.pm.PL
--- old/XS-Parse-Keyword-0.25/lib/XS/Parse/Keyword/Builder_data.pm.PL   
2022-07-26 00:36:23.000000000 +0200
+++ new/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword/Builder_data.pm.PL   
2022-10-31 23:09:16.000000000 +0100
@@ -28,7 +28,7 @@
    <$in_h> } );
 
 __DATA__
-package XS::Parse::Keyword::Builder_data 0.25;
+package XS::Parse::Keyword::Builder_data 0.27;
 
 use v5.14;
 use warnings;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/lib/XS/Parse/Keyword.pm 
new/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword.pm
--- old/XS-Parse-Keyword-0.25/lib/XS/Parse/Keyword.pm   2022-07-26 
00:36:23.000000000 +0200
+++ new/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword.pm   2022-10-31 
23:09:16.000000000 +0100
@@ -3,7 +3,7 @@
 #
 #  (C) Paul Evans, 2021-2022 -- leon...@leonerd.org.uk
 
-package XS::Parse::Keyword 0.25;
+package XS::Parse::Keyword 0.27;
 
 use v5.14;
 use warnings;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/lib/XS/Parse/Keyword.xs 
new/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword.xs
--- old/XS-Parse-Keyword-0.25/lib/XS/Parse/Keyword.xs   2022-07-26 
00:36:23.000000000 +0200
+++ new/XS-Parse-Keyword-0.27/lib/XS/Parse/Keyword.xs   2022-10-31 
23:09:16.000000000 +0100
@@ -30,18 +30,64 @@
 
 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;
+  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         = hooks_v0->new_op;
+  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;
+  U8 lhs_flags, rhs_flags;
+  enum XSParseInfixClassification cls;
+
+  const char *wrapper_func_name;
+
+  const char *permit_hintkey;
+  bool (*permit) (pTHX_ void *hookdata);
+
+  OP *(*new_op)(pTHX_ U32 flags, OP *lhs, OP *rhs, void *hookdata);
+  OP *(*ppaddr)(pTHX);
+
+  OP *(*parse_rhs)(pTHX_ void *hookdata);
+};
+
+static void XSParseInfix_register_v1(pTHX_ const char *opname, const struct 
XSParseInfixHooks_v1 *hooks_v1, void *hookdata)
+{
+  if(hooks_v1->rhs_flags & XPI_OPERAND_CUSTOM)
+    croak("XPI_OPERAND_CUSTOM is no longer supported");
+  if(hooks_v1->parse_rhs)
+    croak("XSParseInfixHooks.parse_rhs is no longer supported");
+
+  struct XSParseInfixHooks *hooks;
+  Newx(hooks, 1, struct XSParseInfixHooks);
+
+  hooks->flags     = hooks_v1->flags | (1<<15) /* NO_PARSEDATA */;
+  hooks->lhs_flags = hooks_v1->lhs_flags;
+  hooks->rhs_flags = hooks_v1->rhs_flags;
+  hooks->cls       = hooks_v1->cls;
+
+  hooks->wrapper_func_name = hooks_v1->wrapper_func_name;
+
+  hooks->permit_hintkey = hooks_v1->permit_hintkey;
+  hooks->permit         = hooks_v1->permit;
+  hooks->new_op         = (OP *(*)(pTHX_ U32, OP *, OP *, SV **, void 
*))hooks_v1->new_op;
+  hooks->ppaddr         = hooks_v1->ppaddr;
+  hooks->parse          = NULL;
 
   XSParseInfix_register(aTHX_ opname, hooks, hookdata);
 }
@@ -65,8 +111,10 @@
   sv_setiv(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/ABIVERSION_MIN", 1), 0);
   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));
+  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));
 
   XSParseInfix_boot(aTHX);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/src/infix.c 
new/XS-Parse-Keyword-0.27/src/infix.c
--- old/XS-Parse-Keyword-0.25/src/infix.c       2022-07-26 00:36:23.000000000 
+0200
+++ new/XS-Parse-Keyword-0.27/src/infix.c       2022-10-31 23:09:16.000000000 
+0100
@@ -13,6 +13,7 @@
 #include "infix.h"
 
 #include "perl-backcompat.c.inc"
+#include "optree-additions.c.inc"
 
 #include "force_list_keeping_pushmark.c.inc"
 #include "make_argcheck_ops.c.inc"
@@ -75,9 +76,7 @@
 {
   U8 lhs_gimme;
   switch(hd->hooks->lhs_flags & 0x07) {
-    case 0: /* back-compat */
-    case XPI_OPERAND_ARITH:
-    case XPI_OPERAND_TERM:
+    case 0:
       lhs_gimme = G_SCALAR;
       break;
 
@@ -93,9 +92,7 @@
 
   U8 rhs_gimme;
   switch(hd->hooks->rhs_flags & 0x07) {
-    case 0: /* back-compat */
-    case XPI_OPERAND_ARITH:
-    case XPI_OPERAND_TERM:
+    case 0:
       rhs_gimme = G_SCALAR;
       break;
 
@@ -150,10 +147,16 @@
 
 static struct Registration *registrations;
 
-static OP *new_op(pTHX_ const struct HooksAndData hd, U32 flags, OP *lhs, OP 
*rhs)
+static OP *new_op(pTHX_ const struct HooksAndData hd, U32 flags, OP *lhs, OP 
*rhs, SV **parsedata)
 {
-  if(hd.hooks->new_op)
-    return (*hd.hooks->new_op)(aTHX_ flags, lhs, rhs, hd.data);
+  if(hd.hooks->new_op) {
+    if(hd.hooks->flags & (1<<15)) {
+      OP *(*new_op_v1)(pTHX_ U32, OP *, OP *, void *) = (OP *(*)(pTHX_ U32, OP 
*, OP *, void *))hd.hooks->new_op;
+      return (*new_op_v1)(aTHX_ flags, lhs, rhs, hd.data); /* no parsedata */
+    }
+
+    return (*hd.hooks->new_op)(aTHX_ flags, lhs, rhs, parsedata, hd.data);
+  }
 
   OP *ret = newBINOP_CUSTOM(hd.hooks->ppaddr, flags, lhs, rhs);
 
@@ -231,51 +234,40 @@
 
 #ifdef HAVE_PL_INFIX_PLUGIN
 
-OP *parse(pTHX_ OP *lhs, struct Perl_custom_infix *def)
+void parse(pTHX_ SV **parsedata, struct Perl_custom_infix *def)
+{
+  struct Registration *reg = (struct Registration *)def;
+
+  (*reg->hd.hooks->parse)(aTHX_ 0, parsedata, reg->hd.data);
+}
+
+OP *build_op(pTHX_ SV **parsedata, OP *lhs, OP *rhs, struct Perl_custom_infix 
*def)
 {
   struct Registration *reg = (struct Registration *)def;
 
   switch(reg->hd.hooks->lhs_flags & 0x07) {
-    case XPI_OPERAND_TERM:
+    case 0:
       break;
 
     case XPI_OPERAND_TERM_LIST:
+    case XPI_OPERAND_LIST:
       lhs = force_list_keeping_pushmark(lhs);
       break;
   }
 
   /* TODO: maybe operator has a 'parse' hook? */
 
-  lex_read_space(0);
-  OP *rhs = NULL;
-
-  switch(reg->hd.hooks->rhs_flags & 0x87) {
-    case XPI_OPERAND_ARITH:
-      rhs = parse_arithexpr(0);
-      break;
-
-    case 0: /* back-compat */
-    case XPI_OPERAND_TERM:
-      rhs = parse_termexpr(0);
+  switch(reg->hd.hooks->rhs_flags & 0x07) {
+    case 0:
       break;
 
     case XPI_OPERAND_TERM_LIST:
-      rhs = force_list_keeping_pushmark(parse_termexpr(0));
-      break;
-
     case XPI_OPERAND_LIST:
-      rhs = force_list_keeping_pushmark(parse_listexpr(0));
-      break;
-
-    case XPI_OPERAND_CUSTOM:
-      rhs = (*reg->hd.hooks->parse_rhs)(aTHX_ reg->hd.data);
+      rhs = force_list_keeping_pushmark(rhs);
       break;
-
-    default:
-      croak("hooks->rhs_flags did not provide a valid RHS type");
   }
 
-  return new_op(aTHX_ reg->hd, 0, lhs, rhs);
+  return new_op(aTHX_ reg->hd, 0, lhs, rhs, parsedata);
 }
 
 static STRLEN (*next_infix_plugin)(pTHX_ char *, STRLEN, struct 
Perl_custom_infix **);
@@ -380,7 +372,7 @@
     return new_op(aTHX_ (struct HooksAndData) {
         .hooks = info->hooks,
         .data  = info->hookdata,
-      }, flags, lhs, rhs);
+      }, flags, lhs, rhs, NULL);
 
   return newBINOP(info->opcode, flags, lhs, rhs);
 }
@@ -470,7 +462,7 @@
   if(!extract_wrapper2_args(aTHX_ op, &left, &right))
     return op;
 
-  return new_op(aTHX_ *hd, 0, left, right);
+  return new_op(aTHX_ *hd, 0, left, right, NULL);
 }
 
 static OP *ckcall_wrapper_func_listlist(pTHX_ OP *op, GV *namegv, SV *ckobj)
@@ -483,21 +475,16 @@
 
   return new_op(aTHX_ *hd, 0,
       unwrap_list(left,  hd->hooks->lhs_flags & XPI_OPERAND_ONLY_LOOK),
-      unwrap_list(right, hd->hooks->rhs_flags & XPI_OPERAND_ONLY_LOOK));
-}
-
-#define newSLUGOP(idx)  S_newSLUGOP(aTHX_ idx)
-static OP *S_newSLUGOP(pTHX_ int idx)
-{
-  OP *op = newGVOP(OP_AELEMFAST, 0, PL_defgv);
-  op->op_private = idx;
-  return op;
+      unwrap_list(right, hd->hooks->rhs_flags & XPI_OPERAND_ONLY_LOOK),
+      NULL);
 }
 
 static void make_wrapper_func(pTHX_ const struct HooksAndData *hd)
 {
   SV *funcname = newSVpvn(hd->hooks->wrapper_func_name, 
strlen(hd->hooks->wrapper_func_name));
-  if(gv_fetchsv(funcname, 0, 0)) {
+
+  GV *gv;
+  if((gv = gv_fetchsv(funcname, 0, 0)) && GvCV(gv)) {
     /* The wrapper function already exists. We presume this is due to a 
duplicate
      * registration of identical hooks under a different name and just skip
      */
@@ -523,7 +510,7 @@
 
       /* Body of the function is just  $_[0] OP $_[1] */
       body = op_append_list(OP_LINESEQ, body,
-          new_op(aTHX_ *hd, 0, newSLUGOP(0), newSLUGOP(1)));
+          new_op(aTHX_ *hd, 0, newSLUGOP(0), newSLUGOP(1), NULL));
 
       ckcall = &ckcall_wrapper_func_scalarscalar;
       break;
@@ -539,7 +526,8 @@
       body = op_append_list(OP_LINESEQ, body,
           new_op(aTHX_ *hd, 0,
             newOP(OP_SHIFT, 0),
-            force_list_keeping_pushmark(newUNOP(OP_RV2AV, OPf_WANT_LIST, 
newGVOP(OP_GV, 0, PL_defgv)))));
+            force_list_keeping_pushmark(newUNOP(OP_RV2AV, OPf_WANT_LIST, 
newGVOP(OP_GV, 0, PL_defgv))),
+            NULL));
 
       /* no ckcall */
       break;
@@ -555,7 +543,8 @@
       body = op_append_list(OP_LINESEQ, body,
           new_op(aTHX_ *hd, 0,
             force_list_keeping_pushmark(newUNOP(OP_RV2AV, 0, newSLUGOP(0))),
-            force_list_keeping_pushmark(newUNOP(OP_RV2AV, 0, newSLUGOP(1)))));
+            force_list_keeping_pushmark(newUNOP(OP_RV2AV, 0, newSLUGOP(1))),
+            NULL));
 
       ckcall = &ckcall_wrapper_func_listlist;
       break;
@@ -665,6 +654,8 @@
 void XSParseInfix_register(pTHX_ const char *opname, const struct 
XSParseInfixHooks *hooks, void *hookdata)
 {
   switch(hooks->flags) {
+    case (1<<15):
+      /* undocumented internal flag to indicate v1-compatible ->new_op hook 
function */
     case 0:
       break;
     default:
@@ -673,10 +664,8 @@
 
   switch(hooks->lhs_flags & ~(XPI_OPERAND_ONLY_LOOK)) {
     case 0:
-      //warn("No .lhs_flags specified for XSParseInfixHooks; defaulting to 
XPI_OPERAND_TERM");
-      /* FALLTHROUGH */
-    case XPI_OPERAND_TERM:
     case XPI_OPERAND_TERM_LIST:
+    case XPI_OPERAND_LIST:
       break;
     default:
       croak("Unrecognised XSParseInfixHooks.lhs_flags value 0x%X", 
hooks->lhs_flags);
@@ -684,23 +673,57 @@
 
   switch(hooks->rhs_flags & ~(XPI_OPERAND_ONLY_LOOK)) {
     case 0:
-      //warn("No .rhs_flags specified for XSParseInfixHooks; defaulting to 
XPI_OPERAND_TERM");
-      /* FALLTHROUGH */
-    case XPI_OPERAND_ARITH:
-    case XPI_OPERAND_TERM:
     case XPI_OPERAND_TERM_LIST:
     case XPI_OPERAND_LIST:
-    case XPI_OPERAND_CUSTOM:
       break;
     default:
       croak("Unrecognised XSParseInfixHooks.rhs_flags value 0x%X", 
hooks->rhs_flags);
+
+    case XPI_OPERAND_CUSTOM:
+      croak("TODO: Currently XPI_OPERAND_CUSTOM is not supported");
+  }
+
+#ifdef HAVE_PL_INFIX_PLUGIN
+  enum Perl_custom_infix_precedence prec = 0;
+
+  switch(hooks->cls) {
+    case 0:
+      warn("Unspecified operator classification for %s; treating it as 
RELATION for precedence", opname);
+    case XPI_CLS_RELATION:
+    case XPI_CLS_EQUALITY:
+    case XPI_CLS_MATCH_MISC:
+      prec = INFIX_PREC_REL;
+      break;
+
+    case XPI_CLS_ADD_MISC:
+      prec = INFIX_PREC_ADD;
+      break;
+
+    case XPI_CLS_MUL_MISC:
+      prec = INFIX_PREC_MUL;
+      break;
+
+    case XPI_CLS_POW_MISC:
+      prec = INFIX_PREC_POW;
+      break;
+
+    /* TODO: Add classifications for the HIGH and LOW also? */
+
+    default:
+      croak("TODO: need to write code for hooks->cls == %d\n", hooks->cls);
   }
+#endif
 
   struct Registration *reg;
   Newx(reg, 1, struct Registration);
 
 #ifdef HAVE_PL_INFIX_PLUGIN
-  reg->def.parse = &parse;
+  reg->def.prec  = prec;
+  if(hooks->parse)
+    reg->def.parse = &parse;
+  else
+    reg->def.parse = NULL;
+  reg->def.build_op = &build_op;
 #endif
 
   reg->info.opname = savepv(opname);
@@ -815,11 +838,6 @@
   ));
 
 #ifdef HAVE_PL_INFIX_PLUGIN
-  OP_CHECK_MUTEX_LOCK;
-  if(!next_infix_plugin) {
-    next_infix_plugin = PL_infix_plugin;
-    PL_infix_plugin = &my_infix_plugin;
-  }
-  OP_CHECK_MUTEX_UNLOCK;
+  wrap_infix_plugin(&my_infix_plugin, &next_infix_plugin);
 #endif
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/t/70infix.t 
new/XS-Parse-Keyword-0.27/t/70infix.t
--- old/XS-Parse-Keyword-0.25/t/70infix.t       2022-07-26 00:36:23.000000000 
+0200
+++ new/XS-Parse-Keyword-0.27/t/70infix.t       2022-10-31 23:09:16.000000000 
+0100
@@ -87,9 +87,30 @@
       "infix_add_0xXXX[aelemfast, aelemfast]",
       'optree of call to infix operator';
 
+   # Check precedence of operator parsing by observing the following precedence
+   # ordering:
+   #   <--High      Low-->
+   #      **  *  +  &&
+
    is_optree sub { $_[0] * $_[1] add $_[2] * $_[3] },
       "infix_add_0xXXX[multiply[aelemfast, aelemfast], multiply[aelemfast, 
aelemfast]]",
-      'optree of call to infix operator at default precedence';
+      'optree binds add lower than *';
+   is_optree sub { $_[0] + $_[1] add $_[2] + $_[3] },
+      "add[infix_add_0xXXX[add[aelemfast, aelemfast], aelemfast], aelemfast]",
+      'optree binds add equal to +';
+   is_optree sub { $_[0] && $_[1] add $_[2] && $_[3] },
+      "and[and[aelemfast, infix_add_0xXXX[aelemfast, aelemfast]], aelemfast]",
+      'optree binds add higher than &&';
+
+   is_optree sub { $_[0] ** $_[1] mul $_[2] ** $_[3] },
+      "infix_mul_0xXXX[pow[aelemfast, aelemfast], pow[aelemfast, aelemfast]]",
+      'optree binds mul lower than **';
+   is_optree sub { $_[0] * $_[1] mul $_[2] * $_[3] },
+      "multiply[infix_mul_0xXXX[multiply[aelemfast, aelemfast], aelemfast], 
aelemfast]",
+      'optree binds mul equal to *';
+   is_optree sub { $_[0] + $_[1] mul $_[2] + $_[3] },
+      "add[add[aelemfast, infix_mul_0xXXX[aelemfast, aelemfast]], aelemfast]",
+      'optree binds mul higher than +';
 
    is_optree sub { $_[0] * ($_[1] add $_[2]) * $_[3] },
       "multiply[multiply[aelemfast, infix_add_0xXXX[aelemfast, aelemfast]], 
aelemfast]",
@@ -116,11 +137,11 @@
 {
    is_deparsed sub { $_[0] add $_[1] },
       '$_[0] add $_[1];',
-      'deparsed call to infix operator';
+      'deparsed call to infix add operator';
 
    is_deparsed sub { $_[0] * $_[1] add $_[2] * $_[3] },
       '($_[0] * $_[1]) add ($_[2] * $_[3]);',
-      'deparsed call to infix operator at default precedence';
+      'deparsed call to infix add operator at default precedence';
 
    is_deparsed sub { $_[0] ??? $_[1] },
       '$_[0] ??? $_[1];',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/XS-Parse-Keyword-0.25/t/infix.xs 
new/XS-Parse-Keyword-0.27/t/infix.xs
--- old/XS-Parse-Keyword-0.25/t/infix.xs        2022-07-26 00:36:23.000000000 
+0200
+++ new/XS-Parse-Keyword-0.27/t/infix.xs        2022-10-31 23:09:16.000000000 
+0100
@@ -26,16 +26,26 @@
 }
 
 static const struct XSParseInfixHooks hooks_add = {
-  .lhs_flags = XPI_OPERAND_TERM,
-  .rhs_flags = XPI_OPERAND_TERM,
+  .cls = XPI_CLS_ADD_MISC,
   .permit_hintkey = hintkey,
-  .cls = 0,
 
   .wrapper_func_name = "t::infix::addfunc",
 
   .ppaddr = &pp_add,
 };
 
+OP *pp_mul(pTHX)
+{
+  croak("TODO"); /* We never actually call code with this so it doesn't matter 
*/
+}
+
+static const struct XSParseInfixHooks hooks_mul = {
+  .cls = XPI_CLS_MUL_MISC,
+  .permit_hintkey = hintkey,
+
+  .ppaddr = &pp_mul,
+};
+
 OP *pp_xor(pTHX)
 {
   dSP;
@@ -46,10 +56,8 @@
 }
 
 static const struct XSParseInfixHooks hooks_xor = {
-  .lhs_flags = XPI_OPERAND_TERM,
-  .rhs_flags = XPI_OPERAND_TERM,
+  .cls = XPI_CLS_ADD_MISC,
   .permit_hintkey = hintkey,
-  .cls = 0,
 
   .ppaddr = &pp_xor,
 };
@@ -86,10 +94,9 @@
 }
 
 static const struct XSParseInfixHooks hooks_intersperse = {
-  .lhs_flags = XPI_OPERAND_TERM,
+  .cls = XPI_CLS_ADD_MISC,
   .rhs_flags = XPI_OPERAND_LIST,
   .permit_hintkey = hintkey,
-  .cls = 0,
 
   .wrapper_func_name = "t::infix::interspersefunc",
 
@@ -124,10 +131,10 @@
 }
 
 static const struct XSParseInfixHooks hooks_addpairs = {
-  .lhs_flags = XPI_OPERAND_TERM_LIST,
-  .rhs_flags = XPI_OPERAND_TERM_LIST|XPI_OPERAND_ONLY_LOOK, /* only on RHS so 
we can test the logic */
+  .cls = XPI_CLS_ADD_MISC,
+  .lhs_flags = XPI_OPERAND_LIST,
+  .rhs_flags = XPI_OPERAND_LIST|XPI_OPERAND_ONLY_LOOK, /* only on RHS so we 
can test the logic */
   .permit_hintkey = hintkey,
-  .cls = 0,
 
   .wrapper_func_name = "t::infix::addpairsfunc",
 
@@ -140,6 +147,7 @@
   boot_xs_parse_infix(0);
 
   register_xs_parse_infix("add", &hooks_add, NULL);
+  register_xs_parse_infix("mul", &hooks_mul, NULL);
 
   register_xs_parse_infix("???", &hooks_xor, NULL);
 

Reply via email to