<div dir="ltr"><div>Hi folks,<br><br>I told some of you at the last .pm that I wanted to write a code generator that converts a Perl script into source code in my GPIR language, simply by running the script. For example:<br>
<br>use GPRM; <br>use GPRM::DocFilter; <br><br>my @dfs = map {new GPRM::DocFilter($_)} 1..8;<br>my $df2 = new GPRM::DocFilter(9);<br><br>    {<br>        my @vals;<br>        for my $i (1..8) {<br>            push @vals, $dfs[$i-1]->score($i)<br>
        }<br>        $df2->aggregate(@vals);<br>    }<br><br>What this does is generate code that will score a document collection using 8 threads and aggregate the results. The score and aggregate methods are assumed to be provided by the DocFilter class.<br>
The 'use GPRM' does the heavy lifting: it reads the source in the GPRM.pm module, transforms it, and then uses exec() to call perl on the new code. The GPRM::DocFilter module does not exist, a stub is created to keep perl happy.<br>
What happens is that a call like $df2->aggregate() uses AUTOLOAD to generate the code in my GPIR language. The result is something like this:<br><br>; docfilter.yml<br>(label L_1 (c1.DocFilter.DocFilter.score '1))<br>
(label L_2 (c2.DocFilter.DocFilter.score '2))<br>(label L_3 (c3.DocFilter.DocFilter.score '3))<br>(label L_4 (c4.DocFilter.DocFilter.score '4))<br>(label L_5 (c5.DocFilter.DocFilter.score '5))<br>(label L_6 (c6.DocFilter.DocFilter.score '6))<br>
(label L_7 (c7.DocFilter.DocFilter.score '7))<br>(label L_8 (c8.DocFilter.DocFilter.score '8))<br>(label L_9 (c0.Ctrl.Ctrl.begin ))<br>(label L_10 (c9.DocFilter.DocFilter.aggregate L_1 L_2 L_3 L_4 L_5 L_6 L_7 L_8))<br>
(label L_11 (c0.Ctrl.Ctrl.begin L_10))<br><br></div>This gets compiled into bytecode and runs on my GPRM VM.<br><div><div><br>At the last .pm meeting, I got a number of interesting suggestions.<br>In the end it turned out I had to do a lot more parsing and analysis for the transformations than I thought, so I ended up using PPI. It's not pretty but it works.<br>
<br>You can find it on GitHub: <br><a href="https://github.com/wimvanderbauwhede/Perl-GPIR-Generator">https://github.com/wimvanderbauwhede/Perl-GPIR-Generator</a><br><br>I created two modules, PPI::Visitors and PPI::Generators, which are general-purpose. The first provides a tree walker that you can provide with your own node transformations and context. The second provides a number of functions to generate PPI nodes and often-used compounds like method calls. <br>
<br>The actual code transformations are in GPRM::Transformer<br>The code generation is in GPRM<br><br>I would really value some feedback on this. It's still buggy but I've uploaded it anyway. So if you can spare a moment, have a look.<br>
<br>Thanks!<br><br>Wim <br clear="all"><br><br></div></div></div>