Как назначить резюме на пакет со списком кодов операций? - PullRequest
4 голосов
/ 29 декабря 2010

Я играл с новой функцией parse_block в bleadperl,

Я могу разобрать несколько операторов в листопе, который сгенерирует дерево ниже:

LISTOP (0x1002a00c0) leave [1] 
    OP (0x1002d6220) enter 
    COP (0x1002a0b80) nextstate 
    OP (0x10028c0f0) null 
    LISTOP (0x1002a0170) print 
        OP (0x1002b1a90) pushmark 
        SVOP (0x100327ee0) const  PV (0x100826ec0) "hello\n" 
    COP (0x1002a0c50) nextstate 
    LISTOP (0x100324ee0) print 
        OP (0x100327880) pushmark 
        SVOP (0x100324eb0) const  PV (0x100897688) "world\n"

Мне нужно вернуть указатель на структуру optree из моего плагина ключевых слов, который в данный момент содержит только пустой список операций. Я хочу обернуть эти операции внутри подпрограммы и назначить ее символу в тайнике.

Итак, я думаю, я хочу сделать что-то вроде этого:

$ perl  -MO=Terse -e "*foo = sub { print 'my listops here' }"

LISTOP (0x10022b5e0) leave [1] 
    OP (0x10022b620) enter 
    COP (0x10022b590) nextstate 
    BINOP (0x100202090) sassign 
        UNOP (0x1002083d0) refgen 
            UNOP (0x100208360) null [146] 
                OP (0x1002083a0) pushmark 
                SVOP (0x100208330) anoncode [1] CV (0x100826d40) 
        UNOP (0x1002085a0) rv2gv 
            SVOP (0x100208550) gv  GV (0x100826d28) *foo 

Предположительно, мне нужно добавить entersub, leavesub в начале и конце моих listops, но я не уверен, как бы я это сделал в XS? Также я не знаю, как превратить полученное optree в CV?

Я могу найти примеры создания резюме для xsubs, но не из optrees.

Спасибо за вашу помощь.

1 Ответ

0 голосов
/ 09 мая 2011

Я бы посмотрел на то, что eval делает внутри, поскольку это по сути то, что он делает. В частности, op.c и Perl_newPROG (OP * o) могут быть хорошим местом для начала:

void
Perl_newPROG(pTHX_ OP *o)
{
    ...
    PL_eval_root = newUNOP(OP_LEAVEEVAL,
                   ((PL_in_eval & EVAL_KEEPERR)
                ? OPf_SPECIAL : 0), o);
    PL_eval_start = op_linklist(PL_eval_root);
    PL_eval_root->op_private |= OPpREFCOUNTED;
    OpREFCNT_set(PL_eval_root, 1);
    PL_eval_root->op_next = 0;
    CALL_PEEP(PL_eval_start);
    ...
...