Object-Pad

 view release on metacpan or  search on metacpan

src/class.c  view on Meta::CPAN

      ops = op_append_list(OP_LINESEQ, ops,
        methstartop = newMETHSTARTOP(OPf_STACKED | opflags_if_role | (meta->repr << 8))
      );
    else
      ops = op_append_list(OP_LINESEQ, ops,
        methstartop = newCOMMONMETHSTARTOP(OPf_STACKED | (meta->repr << 8)));
  }

  if(!is_common) {
    AV *fieldmap = newAV();
    U32 fieldcount = 0, max_fieldix = 0;

    SAVEFREESV((SV *)fieldmap);

    PADNAME **padnames = PadnamelistARRAY(PadlistNAMES(CvPADLIST(PL_compcv)));
    U32 cop_seq_low = COP_SEQ_RANGE_LOW(padnames[PADIX_SELF]);

    int i;
    for(i = 0; i < nfields; i++) {
      FieldMeta *fieldmeta = MUST_FIELDMETA(AvARRAY(fields)[i]);

      if(snames) {
        PADNAME *fieldname = snames[i + 1];

        if(!fieldname || PadnameREFCNT(fieldname) < 2)
            continue;
      }

      /* TODO: Find a better test for initfields so it doesn't think we capture
       * every field declared up til now. */
      FIELDOFFSET fieldix = fieldmeta->fieldix;
      PADOFFSET padix = outerscope ? find_padix_for_field(fieldmeta)
                                   : pad_findmy_pv(SvPVX(fieldmeta->name), 0);

      if(padix == NOT_IN_PAD)
        continue;

      U8 private = 0;
      switch(SvPV_nolen(fieldmeta->name)[0]) {
        case '$': private = OPpFIELDPAD_SV; break;
        case '@': private = OPpFIELDPAD_AV; break;
        case '%': private = OPpFIELDPAD_HV; break;
      }

      PERL_UNUSED_VAR(opflags_if_role);
      assert((fieldix & ~FIELDIX_MASK) == 0);
      av_store(fieldmap, padix, newSVuv(((UV)private << FIELDIX_TYPE_SHIFT) | fieldix));
      fieldcount++;
      if(fieldix > max_fieldix)
        max_fieldix = fieldix;

      if(snames) {
        PADNAME *fieldname = snames[i + 1];

        /* Unshare the padname so the one in the methodscope pad returns to refcount 1 */
        PADNAME *newpadname = newPADNAMEpvn(PadnamePV(fieldname), PadnameLEN(fieldname));
        PadnameREFCNT_dec(padnames[padix]);
        padnames[padix] = newpadname;

        /* Turn off OUTER and set a valid COP sequence range, so the lexical is
         * visible to eval(), PadWalker, perldb, etc.. */
        PadnameOUTER_off(newpadname);
        COP_SEQ_RANGE_LOW(newpadname) = cop_seq_low;
        COP_SEQ_RANGE_HIGH(newpadname) = PL_cop_seqmax;
      }
    }

    if(fieldcount) {
      UNOP_AUX_item *aux;
      Newx(aux, 2 + fieldcount*2, UNOP_AUX_item);
      cUNOP_AUXx(methstartop)->op_aux = aux;

      (aux++)->uv = fieldcount;
      (aux++)->uv = max_fieldix;

      for(Size_t i = 0; i < av_count(fieldmap); i++) {
        if(!AvARRAY(fieldmap)[i] || !SvOK(AvARRAY(fieldmap)[i]))
          continue;

        (aux++)->uv = i;
        (aux++)->uv = SvUV(AvARRAY(fieldmap)[i]);
      }
    }
  }

  return op_append_list(OP_LINESEQ, ops, body);
}

OP *ObjectPad__finish_method_parse(pTHX_ ClassMeta *meta, bool is_common, OP *body)
{
  assert(meta->methodscope && SvTYPE(meta->methodscope) == SVt_PVCV);

  /* If we have no body that means this was a bodyless method
   * declaration; a required method for a role
   */
  if(body && !is_common) {
    {
      ENTER;
      SAVEVPTR(PL_curcop);

      PADNAME **padnames = PadnamelistARRAY(PadlistNAMES(CvPADLIST(PL_compcv)));

      /* See https://rt.cpan.org/Ticket/Display.html?id=132428
       *   https://github.com/Perl/perl5/issues/17754
       */
      PADOFFSET padix;
      for(padix = PADIX_SELF + 1; padix <= PadnamelistMAX(PadlistNAMES(CvPADLIST(PL_compcv))); padix++) {
        PADNAME *pn = padnames[padix];

        if(PadnameIsNULL(pn) || !PadnameLEN(pn))
          continue;

        const char *pv = PadnamePV(pn);
        if(!pv || !strEQ(pv, "$self"))
          continue;

        COP *padcop = NULL;
        if(find_cop_for_lvintro(padix, body, &padcop))
          PL_curcop = padcop;
        warn("\"my\" variable $self masks earlier declaration in same scope");
      }



( run in 1.068 second using v1.01-cache-2.11-cpan-39bf76dae61 )