Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a perl sub by specifying its parse tree?

Tags:

bytecode

perl

Given a CODE ref, is it possible to:

  1. Access the parse tree of that CODE ref
  2. Create a new CODE ref by specifying the parse tree of the CODE ref which can contain elements of the parse tree returned in 1

Normally we create subroutines in perl by specifying source code which is then parsed and converted into a parse tree.

I would like to write a perl function which can create a subroutine by specifying its parse tree, and that parse tree could be derived from another parse tree of some other subroutine.

Possible?

like image 925
ErikR Avatar asked Sep 08 '12 15:09

ErikR


2 Answers

I don't know the full answer to your question, but I know that Data::Dumper can deparse a code reference. Looking at its documentation, I see that it uses B::Deparse to do the heavy lifting (the B:: modules are the ones that interact with the compiler). Unfortunately it seems that this only results in a textual representation of the coderef.

Instead I searched for Op on metacpan and got many more interesting possibilities. Since I am now far out of my depth in the deepest Perl magic, I will leave it to you to look over those results. Perhaps something will be useful.

like image 126
Joel Berger Avatar answered Nov 17 '22 21:11

Joel Berger


This has nothing to do with opcodes, but it does enclose the same two variables in three different closures. The variables are enclosed within subroutines reminiscent of class get/set routines, and those closed vars are then shared by other closures via their access routine.

This is a response to the comment: I'm sure it will be necessary to access the underlying nodes in the parse tree so that I can create new closures which are closed over the same variables.

use strict;
use warnings;
use v5.14;

# create closed vars
my $v1 = access_closure(6);
my $v2 = access_closure(42);

# play with them
say "v1 ", &$v1;
say "v2 ", &$v2;
say "v1 ", &$v1(5);
say "v2 ", &$v2(43);
say "v1 ", &$v1;
say "v2 ", &$v2;

# create silly closures that use them
my $test1 = test_closure(2);
my $test2 = test_closure(17);
my $test3 = test_closure(50);

# play with those
&$test1;
&$test2;
&$test3;

# create the get/set routine for a closed var
sub access_closure {
    my $val = shift;
    return sub {
        $val = shift if @_;
        return $val;
    }
}

# create a silly closure that encloses a control var and uses the two other vars
sub test_closure {
    my $val = shift;
    return sub {
        say "\nval is $val";
        printf "v1 is %2d, v2 is %2d\n",
            &$v1, &$v2;
        if (&$v1 < $val) {
            say "Increment v1";
            &$v1(&$v1+1);
        }
        if (&$v2 > $val) {
            say "Decrement v2";
            &$v2(&$v2-1);
        }
        printf "v1 is %2d, v2 is %2d\n",
            &$v1, &$v2;
    }
}
like image 44
Bill Ruppert Avatar answered Nov 17 '22 22:11

Bill Ruppert