/*
 * This file was generated automatically by ExtUtils::ParseXS version 3.63 from the
 * contents of Try.xs. Do not edit this file, edit Try.xs instead.
 *
 *    ANY CHANGES MADE HERE WILL BE LOST!
 *
 */

#line 1 "lib/Syntax/Keyword/Try.xs"
/*  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, 2016-2021 -- leonerd@leonerd.org.uk
 */
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "XSParseKeyword.h"

#include "perl-backcompat.c.inc"

#if HAVE_PERL_VERSION(5,32,0)
#  define HAVE_OP_ISA
#endif

#if HAVE_PERL_VERSION(5,26,0)
#  define HAVE_OP_SIBPARENT
#endif

#if HAVE_PERL_VERSION(5,19,4)
typedef SSize_t array_ix_t;
#else /* <5.19.4 */
typedef I32 array_ix_t;
#endif /* <5.19.4 */

#include "perl-additions.c.inc"
#include "optree-additions.c.inc"
#include "op_sibling_splice.c.inc"
#include "newOP_CUSTOM.c.inc"
#include "cop_warnings.c.inc"

static OP *pp_entertrycatch(pTHX);
static OP *pp_catch(pTHX);

/*
 * A modified version of pp_return for returning from inside a try block.
 * To do this, we unwind the context stack to just past the CXt_EVAL and then
 * chain to the regular OP_RETURN func
 */
static OP *pp_returnintry(pTHX)
{
  I32 cxix;

  for (cxix = cxstack_ix; cxix; cxix--) {
    if(CxTYPE(&cxstack[cxix]) == CXt_SUB)
      break;

    if(CxTYPE(&cxstack[cxix]) == CXt_EVAL && CxTRYBLOCK(&cxstack[cxix])) {
      /* If this CXt_EVAL frame came from our own ENTERTRYCATCH, then the
       * retop should point at an OP_CUSTOM and its first grand-child will be
       * our custom modified ENTERTRY. We can skip over it and continue in
       * this case.
       */
      OP *retop = cxstack[cxix].blk_eval.retop;
      OP *leave, *enter;
      if(retop->op_type == OP_CUSTOM && retop->op_ppaddr == &pp_catch &&
         (leave = cLOGOPx(retop)->op_first) && leave->op_type == OP_LEAVETRY &&
         (enter = cLOGOPx(leave)->op_first) && enter->op_type == OP_ENTERTRY &&
         enter->op_ppaddr == &pp_entertrycatch) {
        continue;
      }
      /* We have to stop at any other kind of CXt_EVAL */
      break;
    }
  }
  if(!cxix)
    croak("Unable to find an CXt_SUB to pop back to");

  I32 gimme = cxstack[cxix].blk_gimme;
  SV *retval;

  /* chunks of this code inspired by
   *   ZEFRAM/Scope-Escape-0.005/lib/Scope/Escape.xs
   */
  switch(gimme) {
    case G_VOID:
      (void)POPMARK;
      break;

    case G_SCALAR: {
      dSP;
      dMARK;
      retval = (MARK == SP) ? &PL_sv_undef : TOPs;
      SvREFCNT_inc(retval);
      sv_2mortal(retval);
      break;
    }

    case G_LIST: {
      dSP;
      dMARK;
      SV **retvals = MARK+1;
      array_ix_t retcount = SP-MARK;
      array_ix_t i;
      AV *retav = newAV();
      retval = (SV *)retav;
      sv_2mortal(retval);
      av_fill(retav, retcount-1);
      Copy(retvals, AvARRAY(retav), retcount, SV *);
      for(i = 0; i < retcount; i++)
        SvREFCNT_inc(retvals[i]);
      break;
    }
  }

  dounwind(cxix);

  /* Now put the value back */
  switch(gimme) {
    case G_VOID: {
      dSP;
      PUSHMARK(SP);
      break;
    }

    case G_SCALAR: {
      dSP;
      PUSHMARK(SP);
      XPUSHs(retval);
      PUTBACK;
      break;
    }

    case G_LIST: {
      dSP;
      PUSHMARK(SP);
      AV *retav = (AV *)retval;
      array_ix_t retcount = av_len(retav) + 1; /* because av_len means top index */
      EXTEND(SP, retcount);
      Copy(AvARRAY(retav), SP+1, retcount, SV *);
      SP += retcount;
      PUTBACK;
      break;
    }
  }

  return PL_ppaddr[OP_RETURN](aTHX);
}

/*
 * A custom SVOP that takes a CV and arranges for it to be invoked on scope
 * leave
 */
static XOP xop_pushfinally;

static void invoke_finally(pTHX_ void *arg)
{
  CV *finally = arg;
  dSP;

  PUSHMARK(SP);
  call_sv((SV *)finally, G_DISCARD|G_EVAL|G_KEEPERR);

  SvREFCNT_dec(finally);
}

static OP *pp_pushfinally(pTHX)
{
  CV *finally = (CV *)cSVOP->op_sv;

  /* finally is a closure protosub; we have to clone it into a real sub.
   * If we do this now then captured lexicals still work even around
   * Future::AsyncAwait (see RT122796)
   * */
  SAVEDESTRUCTOR_X(&invoke_finally, (SV *)cv_clone(finally));
  return PL_op->op_next;
}

#define newLOCALISEOP(gv)  MY_newLOCALISEOP(aTHX_ gv)
static OP *MY_newLOCALISEOP(pTHX_ GV *gv)
{
  OP *op = newGVOP(OP_GVSV, 0, gv);
  op->op_private |= OPpLVAL_INTRO;
  return op;
}

#define newSTATEOP_nowarnings()  MY_newSTATEOP_nowarnings(aTHX)
static OP *MY_newSTATEOP_nowarnings(pTHX)
{
  OP *op = newSTATEOP(0, NULL, NULL);
  cop_disable_warning((COP *)op, WARN_EXITING);
  return op;
}

static void rethread_op(OP *op, OP *old, OP *new)
{
  if(op->op_next == old)
    op->op_next = new;

  switch(OP_CLASS(op)) {
    case OA_LOGOP:
      if(cLOGOPx(op)->op_other == old)
        cLOGOPx(op)->op_other = new;
      break;

    case OA_LISTOP:
      if(cLISTOPx(op)->op_last == old)
        cLISTOPx(op)->op_last = new;
      break;
  }

  if(op->op_flags & OPf_KIDS) {
    OP *kid;
    for(kid = cUNOPx(op)->op_first; kid; kid = OpSIBLING(kid))
      rethread_op(kid, old, new);
  }
}

#define walk_optree_try_in_eval(op_ptr, root)  MY_walk_optree_try_in_eval(aTHX_ op_ptr, root)
static void MY_walk_optree_try_in_eval(pTHX_ OP **op_ptr, OP *root);
static void MY_walk_optree_try_in_eval(pTHX_ OP **op_ptr, OP *root)
{
  OP *op = *op_ptr;

  switch(op->op_type) {
    /* Fix 'return' to unwind the CXt_EVAL block that implements try{} first */
    case OP_RETURN:
      op->op_ppaddr = &pp_returnintry;
      break;

    /* wrap  no warnings 'exiting' around loop controls */
    case OP_NEXT:
    case OP_LAST:
    case OP_REDO:
      {
#ifdef HAVE_OP_SIBPARENT
        OP *parent = OpHAS_SIBLING(op) ? NULL : op->op_sibparent;
#endif

        OP *stateop = newSTATEOP_nowarnings();

        OP *scope = newLISTOP(OP_SCOPE, 0,
          stateop, op);
#ifdef HAVE_OP_SIBPARENT
        if(parent)
          OpLASTSIB_set(scope, parent);
        else
          OpLASTSIB_set(scope, NULL);
#else
        op->op_sibling = NULL;
#endif

        /* Rethread */
        scope->op_next = stateop;
        stateop->op_next = op;

        *op_ptr = scope;
      }
      break;

    /* Don't enter inside nested eval{} blocks */
    case OP_LEAVETRY:
      return;
  }

  if(op->op_flags & OPf_KIDS) {
    OP *kid, *next, *prev = NULL;
    for(kid = cUNOPx(op)->op_first; kid; kid = next) {
      OP *newkid = kid;
      next = OpSIBLING(kid);

      walk_optree_try_in_eval(&newkid, root);

      if(newkid != kid) {
        rethread_op(root, kid, newkid);

        if(prev) {
          OpMORESIB_set(prev, newkid);
        }
        else
          cUNOPx(op)->op_first = newkid;

        if(next)
          OpMORESIB_set(newkid, next);
      }

      prev = kid;
    }
  }
}

static OP *pp_entertrycatch(pTHX)
{
  /* Localise the errgv */
  save_scalar(PL_errgv);

  return PL_ppaddr[OP_ENTERTRY](aTHX);
}

static XOP xop_catch;

static OP *pp_catch(pTHX)
{
  /* If an error didn't happen, then ERRSV will be both not true and not a
   * reference. If it's a reference, then an error definitely happened
   */
  if(SvROK(ERRSV) || SvTRUE(ERRSV))
    return cLOGOP->op_other;
  else
    return cLOGOP->op_next;
}

#define newENTERTRYCATCHOP(flags, try, catch)  MY_newENTERTRYCATCHOP(aTHX_ flags, try, catch)
static OP *MY_newENTERTRYCATCHOP(pTHX_ U32 flags, OP *try, OP *catch)
{
  OP *enter, *entertry, *ret;

  /* Walk the block for OP_RETURN ops, so we can apply a hack to them to
   * make
   *   try { return }
   * return from the containing sub, not just the eval block
   */
  walk_optree_try_in_eval(&try, try);

  enter = newUNOP(OP_ENTERTRY, 0, try);
  /* despite calling newUNOP(OP_ENTERTRY,...) the returned root node is the
   * OP_LEAVETRY, whose first child is the ENTERTRY we wanted
   */
  entertry = ((UNOP *)enter)->op_first;
  entertry->op_ppaddr = &pp_entertrycatch;

  /* If we call newLOGOP_CUSTOM it will op_contextualize the enter block into
   * G_SCALAR. This is not what we want
   */
  {
    LOGOP *logop;

    OP *first = enter, *other = newLISTOP(OP_SCOPE, 0, catch, NULL);

    NewOp(1101, logop, 1, LOGOP);

    logop->op_type = OP_CUSTOM;
    logop->op_ppaddr = &pp_catch;
    logop->op_first = first;
    logop->op_flags = OPf_KIDS;
    logop->op_other = LINKLIST(other);

    logop->op_next = LINKLIST(first);
    enter->op_next = (OP *)logop;
#if HAVE_PERL_VERSION(5, 22, 0)
    op_sibling_splice((OP *)logop, first, 0, other);
#else
    first->op_sibling = other;
#endif

    ret = newUNOP(OP_NULL, 0, (OP *)logop);
    other->op_next = ret;
  }

  return ret;
}

#ifndef HAVE_OP_ISA
static XOP xop_isa;

/* Totally stolen from perl 5.32.0's pp.c */
#define sv_isa_sv(sv, namesv)  S_sv_isa_sv(aTHX_ sv, namesv)
static bool S_sv_isa_sv(pTHX_ SV *sv, SV *namesv)
{
  if(!SvROK(sv) || !SvOBJECT(SvRV(sv)))
    return FALSE;

  /* TODO: ->isa invocation */

#if HAVE_PERL_VERSION(5,16,0)
  return sv_derived_from_sv(sv, namesv, 0);
#else
  return sv_derived_from(sv, SvPV_nolen(namesv));
#endif
}

static OP *pp_isa(pTHX)
{
  dSP;

  SV *left, *right;

  right = POPs;
  left  = TOPs;

  SETs(boolSV(sv_isa_sv(left, right)));
  RETURN;
}
#endif

static int build_try(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata)
{
  U32 argi = 0;

  OP *try = args[argi++]->op;

  OP *ret = NULL;
  HV *hints = GvHV(PL_hintgv);

  bool require_catch = hints && hv_fetchs(hints, "Syntax::Keyword::Try/require_catch", 0);
  bool require_var   = hints && hv_fetchs(hints, "Syntax::Keyword::Try/require_var", 0);

  U32 ncatches = args[argi++]->i;

  AV *condcatch = NULL;
  OP *catch = NULL;
  while(ncatches--) {
    bool has_catchvar = args[argi++]->i;
    PADOFFSET catchvar = has_catchvar ? args[argi++]->padix : 0;
    int catchtype = has_catchvar ? args[argi++]->i : -1;

    bool warned = FALSE;

    OP *condop = NULL;

    switch(catchtype) {
      case -1: /* no type */
        break;

      case 0: /* isa */
      {
        OP *type = args[argi++]->op;
#ifdef HAVE_OP_ISA
        condop = newBINOP(OP_ISA, 0,
          newPADxVOP(OP_PADSV, 0, catchvar), type);
#else
        /* Allow a bareword on RHS of `isa` */
        if(type->op_type == OP_CONST)
          type->op_private &= ~(OPpCONST_BARE|OPpCONST_STRICT);

        condop = newBINOP_CUSTOM(&pp_isa, 0,
          newPADxVOP(OP_PADSV, 0, catchvar), type);
#endif
        break;
      }

      case 1: /* =~ */
      {
        OP *regexp = args[argi++]->op;

        if(regexp->op_type != OP_MATCH || cPMOPx(regexp)->op_first)
          croak("Expected a regexp match");
#if HAVE_PERL_VERSION(5,22,0)
        /* Perl 5.22+ uses op_targ on OP_MATCH directly */
        regexp->op_targ = catchvar;
#else
        /* Older perls need a stacked OP_PADSV op */
        cPMOPx(regexp)->op_first = newPADxVOP(OP_PADSV, 0, catchvar);
        regexp->op_flags |= OPf_KIDS|OPf_STACKED;
#endif
        condop = regexp;
        break;
      }

      default:
        croak("TODO\n");
    }

#ifdef WARN_EXPERIMENTAL
    if(condop && !warned &&
      (!hints || !hv_fetchs(hints, "Syntax::Keyword::Try/experimental(typed)", 0))) {
      warned = true;
      Perl_ck_warner(aTHX_ packWARN(WARN_EXPERIMENTAL),
        "typed catch syntax is experimental and may be changed or removed without notice");
    }
#endif

    OP *body = args[argi++]->op;

    if(require_var && !has_catchvar)
      croak("Expected (VAR) for catch");

    if(catch)
      croak("Already have a default catch {} block");

    OP *assignop = NULL;
    if(catchvar) {
      /* my $var = $@ */
      assignop = newBINOP(OP_SASSIGN, 0,
        newGVOP(OP_GVSV, 0, PL_errgv), newPADxVOP(OP_PADSV, OPf_MOD | OPpLVAL_INTRO << 8, catchvar));
    }

    if(condop) {
      if(!condcatch)
        condcatch = newAV();

      av_push(condcatch, (SV *)op_append_elem(OP_LINESEQ, assignop, condop));
      av_push(condcatch, (SV *)body);
      /* catch remains NULL for now */
    }
    else if(assignop) {
      catch = op_prepend_elem(OP_LINESEQ,
        assignop, body);
    }
    else
      catch = body;
  }

  if(condcatch) {
    I32 i;

    if(!catch)
      /* A default fallthrough */
      /*   die $@ */
      catch = newLISTOP(OP_DIE, 0,
        newOP(OP_PUSHMARK, 0), newGVOP(OP_GVSV, 0, PL_errgv));

    for(i = AvFILL(condcatch)-1; i >= 0; i -= 2) {
      OP *body   = (OP *)av_pop(condcatch),
         *condop = (OP *)av_pop(condcatch);

      catch = newCONDOP(0, condop, op_scope(body), catch);
    }

    SvREFCNT_dec(condcatch);
  }

  if(require_catch && !catch)
    croak("Expected a catch {} block");

  bool no_finally = hints && hv_fetchs(hints, "Syntax::Keyword::Try/no_finally", 0);

  U32 has_finally = args[argi++]->i;
  CV *finally = has_finally ? args[argi++]->cv : NULL;

  if(no_finally && finally)
    croak("finally {} is not permitted here");

  if(!catch && !finally) {
    op_free(try);
    croak(no_finally
      ? "Expected try {} to be followed by catch {}"
      : "Expected try {} to be followed by either catch {} or finally {}");
  }

  ret = try;

  if(catch) {
    ret = newENTERTRYCATCHOP(0, try, catch);
  }

  /* If there's a finally, make
   *   $RET = OP_PUSHFINALLY($FINALLY); $RET
   */
  if(finally) {
    ret = op_prepend_elem(OP_LINESEQ,
      newSVOP_CUSTOM(&pp_pushfinally, 0, (SV *)finally),
      ret);
  }

  ret = op_append_list(OP_LEAVE,
    newOP(OP_ENTER, 0),
    ret);

  *out = ret;
  return KEYWORD_PLUGIN_STMT;
}

static struct XSParseKeywordHooks hooks_try = {
  .permit_hintkey = "Syntax::Keyword::Try/try",

  .pieces = (const struct XSParseKeywordPieceType []){
    XPK_BLOCK,
    XPK_REPEATED(
      XPK_LITERAL("catch"),
      XPK_PREFIXED_BLOCK(
        /* optionally ($var), ($var isa Type) or ($var =~ m/.../) */
        XPK_PARENS_OPT(
          XPK_LEXVAR_MY(XPK_LEXVAR_SCALAR),
          XPK_CHOICE(
            XPK_SEQUENCE(XPK_LITERAL("isa"), XPK_TERMEXPR),
            XPK_SEQUENCE(XPK_LITERAL("=~"), XPK_TERMEXPR)
          )
        )
      )
    ),
    XPK_OPTIONAL(
      XPK_LITERAL("finally"), XPK_ANONSUB
    ),
    {0},
  },
  .build = &build_try,
};

#line 592 "lib/Syntax/Keyword/Try.c"
#ifndef PERL_UNUSED_VAR
#  define PERL_UNUSED_VAR(var) if (0) var = var
#endif

#ifndef dVAR
#  define dVAR		dNOOP
#endif


/* This stuff is not part of the API! You have been warned. */
#ifndef PERL_VERSION_DECIMAL
#  define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
#endif
#ifndef PERL_DECIMAL_VERSION
#  define PERL_DECIMAL_VERSION \
	  PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
#endif
#ifndef PERL_VERSION_GE
#  define PERL_VERSION_GE(r,v,s) \
	  (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
#endif
#ifndef PERL_VERSION_LE
#  define PERL_VERSION_LE(r,v,s) \
	  (PERL_DECIMAL_VERSION <= PERL_VERSION_DECIMAL(r,v,s))
#endif

/* XS_INTERNAL is the explicit static-linkage variant of the default
 * XS macro.
 *
 * XS_EXTERNAL is the same as XS_INTERNAL except it does not include
 * "static", ie. it exports XSUB symbols. You probably don't want that
 * for anything but the BOOT XSUB.
 *
 * See XSUB.h in core!
 */


/* TODO: This might be compatible further back than 5.10.0. */
#if PERL_VERSION_GE(5, 10, 0) && PERL_VERSION_LE(5, 15, 1)
#  undef XS_EXTERNAL
#  undef XS_INTERNAL
#  if defined(__CYGWIN__) && defined(USE_DYNAMIC_LOADING)
#    define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name)
#    define XS_INTERNAL(name) static XSPROTO(name)
#  endif
#  if defined(__SYMBIAN32__)
#    define XS_EXTERNAL(name) EXPORT_C XSPROTO(name)
#    define XS_INTERNAL(name) EXPORT_C static XSPROTO(name)
#  endif
#  ifndef XS_EXTERNAL
#    if defined(HASATTRIBUTE_UNUSED) && !defined(__cplusplus)
#      define XS_EXTERNAL(name) void name(pTHX_ CV* cv __attribute__unused__)
#      define XS_INTERNAL(name) static void name(pTHX_ CV* cv __attribute__unused__)
#    else
#      ifdef __cplusplus
#        define XS_EXTERNAL(name) extern "C" XSPROTO(name)
#        define XS_INTERNAL(name) static XSPROTO(name)
#      else
#        define XS_EXTERNAL(name) XSPROTO(name)
#        define XS_INTERNAL(name) static XSPROTO(name)
#      endif
#    endif
#  endif
#endif

/* perl >= 5.10.0 && perl <= 5.15.1 */


/* The XS_EXTERNAL macro is used for functions that must not be static
 * like the boot XSUB of a module. If perl didn't have an XS_EXTERNAL
 * macro defined, the best we can do is assume XS is the same.
 * Dito for XS_INTERNAL.
 */
#ifndef XS_EXTERNAL
#  define XS_EXTERNAL(name) XS(name)
#endif
#ifndef XS_INTERNAL
#  define XS_INTERNAL(name) XS(name)
#endif

/* Now, finally, after all this mess, we want an ExtUtils::ParseXS
 * internal macro that we're free to redefine for varying linkage due
 * to the EXPORT_XSUB_SYMBOLS XS keyword. This is internal, use
 * XS_EXTERNAL(name) or XS_INTERNAL(name) in your code if you need to!
 */

#undef XS_EUPXS
#if defined(PERL_EUPXS_ALWAYS_EXPORT)
#  define XS_EUPXS(name) XS_EXTERNAL(name)
#else
   /* default to internal */
#  define XS_EUPXS(name) XS_INTERNAL(name)
#endif

#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)

/* prototype to pass -Wmissing-prototypes */
static void
S_croak_xs_usage(const CV *const cv, const char *const params);

static void
S_croak_xs_usage(const CV *const cv, const char *const params)
{
    const GV *const gv = CvGV(cv);

    PERL_ARGS_ASSERT_CROAK_XS_USAGE;

    if (gv) {
        const char *const gvname = GvNAME(gv);
        const HV *const stash = GvSTASH(gv);
        const char *const hvname = stash ? HvNAME(stash) : NULL;

        if (hvname)
	    Perl_croak_nocontext("Usage: %s::%s(%s)", hvname, gvname, params);
        else
	    Perl_croak_nocontext("Usage: %s(%s)", gvname, params);
    } else {
        /* Pants. I don't think that it should be possible to get here. */
	Perl_croak_nocontext("Usage: CODE(0x%" UVxf ")(%s)", PTR2UV(cv), params);
    }
}
#undef  PERL_ARGS_ASSERT_CROAK_XS_USAGE

#define croak_xs_usage        S_croak_xs_usage

#endif

/* NOTE: the prototype of newXSproto() is different in versions of perls,
 * so we define a portable version of newXSproto()
 */
#ifdef newXS_flags
#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0)
#else
#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv)
#endif /* !defined(newXS_flags) */

#if PERL_VERSION_LE(5, 21, 5)
#  define newXS_deffile(a,b) Perl_newXS(aTHX_ a,b,file)
#else
#  define newXS_deffile(a,b) Perl_newXS_deffile(aTHX_ a,b)
#endif

/* simple backcompat versions of the TARGx() macros with no optimisation */
#ifndef TARGi
#  define TARGi(iv, do_taint) sv_setiv_mg(TARG, iv)
#  define TARGu(uv, do_taint) sv_setuv_mg(TARG, uv)
#  define TARGn(nv, do_taint) sv_setnv_mg(TARG, nv)
#endif

#line 743 "lib/Syntax/Keyword/Try.c"
#ifdef __cplusplus
extern "C" {
#endif
XS_EXTERNAL(boot_Syntax__Keyword__Try); /* prototype to pass -Wmissing-prototypes */
XS_EXTERNAL(boot_Syntax__Keyword__Try)
{
#if PERL_VERSION_LE(5, 21, 5)
    dVAR; dXSARGS;
#else
    dVAR; dXSBOOTARGSXSAPIVERCHK;
#endif

    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
#if PERL_VERSION_LE(5, 21, 5)
    XS_VERSION_BOOTCHECK;
#  ifdef XS_APIVERSION_BOOTCHECK
    XS_APIVERSION_BOOTCHECK;
#  endif
#endif


    /* Initialisation Section */

#line 585 "lib/Syntax/Keyword/Try.xs"
  XopENTRY_set(&xop_catch, xop_name, "catch");
  XopENTRY_set(&xop_catch, xop_desc,
    "optionally invoke the catch block if required");
  XopENTRY_set(&xop_catch, xop_class, OA_LOGOP);
  Perl_custom_op_register(aTHX_ &pp_catch, &xop_catch);

  XopENTRY_set(&xop_pushfinally, xop_name, "pushfinally");
  XopENTRY_set(&xop_pushfinally, xop_desc,
    "arrange for a CV to be invoked at scope exit");
  XopENTRY_set(&xop_pushfinally, xop_class, OA_SVOP);
  Perl_custom_op_register(aTHX_ &pp_pushfinally, &xop_pushfinally);
#ifndef HAVE_OP_ISA
  XopENTRY_set(&xop_isa, xop_name, "isa");
  XopENTRY_set(&xop_isa, xop_desc,
    "check if a value is an object of the given class");
  XopENTRY_set(&xop_isa, xop_class, OA_BINOP);
  Perl_custom_op_register(aTHX_ &pp_isa, &xop_isa);
#endif

  boot_xs_parse_keyword(0.35);

  register_xs_parse_keyword("try", &hooks_try, NULL);

#line 792 "lib/Syntax/Keyword/Try.c"

    /* End of Initialisation Section */

#if PERL_VERSION_LE(5, 21, 5)
#  if PERL_VERSION_GE(5, 9, 0)
    if (PL_unitcheckav)
        call_list(PL_scopestack_ix, PL_unitcheckav);
#  endif
    XSRETURN_YES;
#else
    Perl_xs_boot_epilog(aTHX_ ax);
#endif
}

#ifdef __cplusplus
}
#endif
