NAME

Text::Xslate::PP::Booster - Text::Xslate code generator for pure Perl

SYNOPSIS

# If you want to check created codes, you can use it directly.
use Text::Xslate::PP;
use Text::Xslate::PP::Booster;

my $tx      = Text::Xslate->new();
my $booster = Text::Xslate::PP::Booster->new();

my $optext  = q{<: $value :>};
my $code    = $booster->opcode_to_perlcode_string( $tx->compile( $optext ) );
my $coderef = $booster->opcode_to_perlcode( $tx->compile( $optext ) );
# $coderef takes a Text::Xslate::PP::State object

DESCRIPTION

This module is a pure Perl engine, which is much faster than Text::Xslate::PP::Opcode, but might be less stable.

The motivation to implement this engine is the performance. You know the default pure Perl engine was really slow. For example:

$ XSLATE=pp=opcode perl -Mblib benchmark/others.pl
Perl/5.10.1 i686-linux
Text::Xslate/0.1025
Text::MicroTemplate/0.11
Template/2.22
Text::ClearSilver/0.10.5.4
HTML::Template::Pro/0.94
...
Benchmarks with 'list' (datasize=100)
         Rate Xslate     TT     MT    TCS     HT
Xslate  155/s     --   -52%   -83%   -94%   -95%
TT      324/s   109%     --   -64%   -88%   -90%
MT      906/s   486%   180%     --   -66%   -73%
TCS    2634/s  1604%   713%   191%     --   -21%
HT     3326/s  2051%   927%   267%    26%     --

All right, it is slower than Template-Toolkit! But now Text::Xslate::PP::Booster is available, and is as fast as Text::MicroTemplate:

$ XSLATE=pp perl -Mblib benchmark/others.pl
...
Benchmarks with 'list' (datasize=100)
         Rate     TT Xslate     MT    TCS     HT
TT      330/s     --   -63%   -65%   -87%   -90%
Xslate  896/s   172%     --    -5%   -65%   -73%
MT      941/s   185%     5%     --   -63%   -72%
TCS    2543/s   671%   184%   170%     --   -24%
HT     3338/s   912%   272%   255%    31%     --

Text::Xslate::PP becomes much faster than the default pure Perl engine!

The engine is enabled with $ENV{ENV}='pp=booster'.

APIs

new

Constructor.

$booster = Text::Xslate::PP::Booster->new();

opcode_to_perlcode

Takes a virtual machine code created by Text::Xslate::Compiler, and returns a code reference.

$coderef = $booster->opcode_to_perlcode( $ops );

The code reference takes Text::Xslate::PP::State object in Xslate runtime processes. Don't execute this code reference directly.

opcode_to_perlcode_string

Takes a virtual machine code created by Text::Xslate::Compiler, and returns a perl subroutine code text.

$str = $booster->opcode_to_perlcode_string( $ops );

ABOUT BOOST CODE

Text::Xslate::PP::Booster creates a code reference from a virtual machine code.

$tx->render_string( <<'CODE', {} );
: macro foo -> $arg {
    Hello <:= $arg :>!
: }
: foo($value)
CODE

Firstly the template data is converted to opcodes:

pushmark
fetch_s "value"
push
macro "foo"
macrocall
print
end
macro_begin "foo"
print_raw_s "    Hello "
fetch_lvar 0
print
print_raw_s "!\n"
macro_end

And the booster converted them into a perl subroutine code (you can get that code by XSLATE=dump=pp).

sub {
    no warnings 'recursion';
    my ( $st ) = @_;
    my ( $sv, $pad, %macro, $depth );
    my $output = q{};
    my $vars   = $st->{ vars };

    $st->{pad} = $pad = [ [ ] ];

    # macro

    $macro{"foo"} = $st->{ booster_macro }->{"foo"} ||= sub {
        my ( $st, $pad, $f_l ) = @_;
        my $vars = $st->{ vars };
        my $mobj = $st->symbol->{ "foo" };
        my $output = q{};

        if ( @{$pad->[-1]} != $mobj->nargs ) {
            $st->error( $f_l, _macro_args_error( $mobj, $pad ) );
            return '';
        }

        if ( my $outer = $mobj->outer ) {
            my @temp = @{$pad->[-1]};
            @{$pad->[-1]}[ 0 .. $outer - 1 ] = @{$pad->[-2]}[ 0 .. $outer - 1 ];
            @{$pad->[-1]}[ $outer .. $outer + $mobj->nargs ] = @temp;
        }

        Carp::croak('Macro call is too deep (> 100) on "foo"') if ++$depth > 100;

        # print_raw_s
        $output .= "    Hello ";

        # print
        $sv = $pad->[ -1 ]->[ 0 ];
        if ( ref($sv) eq 'Text::Xslate::Type::Raw' ) {
            if(defined ${$sv}) {
                $output .= $sv;
            }
            else {
                $st->warn( ["foo", 13], "Use of nil to print" );
            }
        }
        elsif ( defined $sv ) {
            $sv =~ s/($html_metachars)/$html_escape{$1}/xmsgeo;
            $output .= $sv;
        }
        else {
            $st->warn( ["foo", 13], "Use of nil to print" );
        }

        # print_raw_s
        $output .= "!\n";

        $depth--;
        pop( @$pad );

        return mark_raw($output);
    };


    # process start

    # print
    $sv = $macro{ "foo" }->( $st, push_pad( $pad, [ $vars->{ "value" } ] ), [ "main", 5 ] );
    if ( ref($sv) eq 'Text::Xslate::Type::Raw' ) {
        if(defined ${$sv}) {
            $output .= $sv;
        }
        else {
            $st->warn( ["main", 6], "Use of nil to print" );
        }
    }
    elsif ( defined $sv ) {
        $sv =~ s/($html_metachars)/$html_escape{$1}/xmsgeo;
        $output .= $sv;
    }
    else {
        $st->warn( ["main", 6], "Use of nil to print" );
    }

    # process end

    return $output;
}

So it makes the runtime speed much faster. Of course, its initial converting process costs time and memory.

SEE ALSO

Text::Xslate::PP

AUTHOR

Makamaka Hannyaharamitu <makamaka at cpan.org>

LICENSE AND COPYRIGHT

Copyright (c) 2010 by Makamaka Hannyaharamitu (makamaka).

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.