CodeGen-Cpppp
view release on metacpan or search on metacpan
lib/CodeGen/Cpppp/Template.pm view on Meta::CPAN
my $pos= $fh->tell;
local $/= undef;
$cpppp= <$fh>;
# now find out what line __DATA__ started on
eval {
$fh->seek(0,0);
$/= \$pos;
$line= 1 + scalar(()= <$fh> =~ /\n/g);
} or Carp::carp("Can't determine line number of __DATA__");
close $fh;
}
}
Carp::croak("compile_cppp argument should either be '__DATA__' or lines of cpppp code ending with '\\n'")
unless defined $cpppp;
Carp::croak("cpppp source cannot be empty")
unless length $cpppp;
my $parse= CodeGen::Cpppp->new->parse_cpppp(\$cpppp, $filename, $line);
$pkg->_init_parse_data($parse);
$pkg->_build_BUILD_method(
$pkg->cpppp_version, $parse->{code}, $filename, $line);
}
sub format_commandline {
require CodeGen::Cpppp::Platform;
CodeGen::Cpppp::Platform::format_commandline(@_);
}
sub format_timestamp {
my @t= gmtime;
sprintf "%04d-%02d-%02dT%02d:%02d:%02dZ", $t[5]+1900, @t[4,3,2,1,0]
}
}
sub _tag_for_version($ver) {
return ':v0';
}
sub import {
my $class= $_[0];
my $caller= caller;
for (my $i= 1; $i < @_; $i++) {
if ($_[$i] eq '-setup') {
my $ver= version->parse($_[$i+1]);
splice(@_, $i, 2, _tag_for_version($ver));
$class->_setup_derived_package($caller, $ver);
}
}
splice(@_, 0, 1, 'CodeGen::Cpppp::Template::Exports');
goto \&Exporter::import;
}
our $_next_pkg= 1;
sub _create_derived_package($class, $cpppp_ver, $parse_data) {
my $pkg= 'CodeGen::Cpppp::Template::_'.$_next_pkg++;
no strict 'refs';
@{"${pkg}::ISA"}= ( $class );
${"${pkg}::cpppp_version"}= $cpppp_ver;
$pkg->_init_parse_data($parse_data);
}
sub _setup_derived_package($class, $pkg, $cpppp_ver) {
strict->import;
warnings->import;
utf8->import;
experimental->import(qw( lexical_subs signatures postderef ));
no strict 'refs';
@{"${pkg}::ISA"}= ( $class ) unless @{"${pkg}::ISA"};
${"${pkg}::cpppp_version"}= $cpppp_ver;
}
sub _init_parse_data($class, $parse_data) {
no strict 'refs';
${"${class}::_parse_data"}= $parse_data;
# Create accessors for all of the attributes declared in the template.
for (keys $parse_data->{template_parameter}->%*) {
my $name= $_;
*{"${class}::$name"}= sub { $_[0]{$name} };
}
# Expose all of the functions declared in the template
for (keys $parse_data->{template_method}->%*) {
my $name= $_;
*{"${class}::$name"}= sub {
my $m= shift->{template_method}{$name}
or croak "Template execution did not define method '$name'";
goto $m;
};
}
$class;
}
sub cpppp_version($class) {
no strict 'refs';
${"${class}::cpppp_version"} // __PACKAGE__->VERSION
}
sub _gen_perl_scope_functions($class, $cpppp_ver) {
return (
'# line '. (__LINE__+1) . ' "' . __FILE__ . '"',
'my sub param { unshift @_, $self; goto $self->can("_init_param") }',
'my sub define { unshift @_, $self; goto $self->can("define_template_macro") }',
'my sub section { unshift @_, $self; goto $self->can("current_output_section") }',
'my sub template { unshift @_, $self->context; goto $self->context->can("new_template") }',
'my $trim_comma= CodeGen::Cpppp::AntiCharacter->new(qr/,/, qr/\s*/);',
'my $trim_ws= CodeGen::Cpppp::AntiCharacter->new(qr/\s*/);',
);
}
sub _gen_BUILD_method($class, $cpppp_ver, $perl, $src_filename, $src_lineno) {
return
"sub ${class}::BUILD(\$self, \$constructor_parameters=undef) {",
" Scalar::Util::weaken(\$self);",
# Inject all the lexical functions that need to be in scope
$class->_gen_perl_scope_functions($cpppp_ver),
qq{# line $src_lineno "$src_filename"},
$perl,
"}",
}
sub _build_BUILD_method($class, $version, $perl, $src_filename, $src_lineno) {
{
no strict 'refs';
( run in 1.584 second using v1.01-cache-2.11-cpan-39bf76dae61 )