HTML-Template-JIT

 view release on metacpan or  search on metacpan

JIT/Compiler.pm  view on Meta::CPAN

package HTML::Template::JIT::Compiler;

use 5.006;
use strict;
use warnings;

our $VERSION = '0.01';

use HTML::Template;
use Carp qw(croak confess);
use File::Path qw(mkpath rmtree);

sub compile {
  my %args = @_;
  my $self = bless({});

  # parse the template as usual
  $self->{template} = HTML::Template->new(%args);
  
  # setup state
  $self->{jit_path}          = $args{jit_path};
  $self->{package}           = $args{package};
  $self->{package_dir}       = $args{package_dir};
  $self->{package_path}      = $args{package_path};
  $self->{jit_pool}          = [];
  $self->{jit_sym}           = 0;
  $self->{jit_debug}         = $args{jit_debug};
  $self->{text_size}         = 0;
  $self->{loop_context_vars} = $args{loop_context_vars};
  $self->{max_depth}         = 0;
  $self->{global_vars}       = $args{global_vars};
  $self->{print_to_stdout}   = $args{print_to_stdout};
  $self->{case_sensitive}    = $args{case_sensitive};

  # compile internal representation into a chunk of C code

  # get code for param function
  my @code = $self->_output();

  if ($self->{jit_debug}) {
    print STDERR "###################### CODE START ######################\n\n";
    open(INDENT, "| indent -kr > code.tmp");
    print INDENT join("\n", @code);
    close INDENT;
    open(CODE, 'code.tmp');
    print STDERR join('', <CODE>);
    close(CODE);
    unlink('code.tmp');    
    print STDERR "\n\n###################### CODE END ######################\n\n";
  }

  $self->_write_module(\@code);

  # try to load the module and return package handle if successful
  my $result;
  eval { $result = require $self->{package_path}; };
  return 1 if $result;

  # don't leave failed compiles lying around unless we're debuging
  rmtree($self->{package_dir}, 0, 0) unless $self->{jit_debug};
  die $@ if $@;
  return 0;
}

# writes out the module file
sub _write_module {
  my ($self, $code) = @_;

  # make directory
  mkpath($self->{package_dir}, 0, 0700);
  
  # open module file
  open(MODULE, ">$self->{package_path}") or die "Unable to open $self->{package_path} for output : $!";
  
  my $inline_debug = "";
  my $optimize = "-O3";
  if ($self->{jit_debug}) {
    $inline_debug = ", CLEAN_AFTER_BUILD => 0";
    $optimize = "-g";
  }

  # print out preamble
  print MODULE <<END;
package $self->{package};
use base 'HTML::Template::JIT::Base';

use Inline C => Config => OPTIMIZE => "$optimize", DIRECTORY => "$self->{package_dir}" $inline_debug;
use Inline C => <<'CODE_END';

END

  # print out code
  print MODULE join("\n", @$code), "\nCODE_END\n";

  # output the param hash
  print MODULE "our \%param_hash = (\n", join(',', $self->_param_hash([])), ");\n";
  
  # empty param map
  print MODULE "our \%param_map;\n";

  # note case sensitivity
  print MODULE "our \$case_sensitive = $self->{case_sensitive};\n";

  print MODULE "\n1;\n";

  # all done
  close MODULE;
}

# construct the output function
sub _output {
  my $self = shift;
  my $template = $self->{template};

  # construct body of output
  my @code = $self->_output_template($template, 0);



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