ExtUtils-XSpp
view release on metacpan or search on metacpan
lib/ExtUtils/XSpp/Node/Function.pm view on Meta::CPAN
my $state = shift;
my $out = '';
my $fname = $this->perl_function_name;
my $args = $this->arguments;
my $ret_type = $this->ret_type;
my $ret_typemap = $this->{TYPEMAPS}{RET_TYPE};
my $aliases = $this->{ALIAS} || {};
my $has_aliases = scalar(keys %$aliases);
$out .= '#if ' . $this->emit_condition . "\n" if $this->emit_condition;
my( $init, $arg_list, $call_arg_list, $code, $output, $cleanup,
$postcall, $precall, $alias ) = ( ('') x 9 );
# compute the precall code, XS argument list and C++ argument list using
# the typemap information
if( $args && @$args ) {
my $has_self = $this->is_method ? 1 : 0;
my( @arg_list, @call_arg_list );
foreach my $i ( 0 .. $#$args ) {
my $arg = ${$args}[$i];
my $t = $this->{TYPEMAPS}{ARGUMENTS}[$i];
my $pc = $t->precall_code( sprintf( 'ST(%d)', $i + $has_self ),
$arg->name );
push @arg_list, $t->cpp_type . ' ' . $arg->name .
( $arg->has_default ? ' = ' . $arg->default : '' );
my $call_code = $t->call_parameter_code( $arg->name );
push @call_arg_list, defined( $call_code ) ? $call_code : $arg->name;
$precall .= $pc . ";\n" if $pc
}
$arg_list = ' ' . join( ', ', @arg_list ) . ' ';
$call_arg_list = ' ' . join( ', ', @call_arg_list ) . ' ';
}
# If there's %alias{foo = 123} definitions, generate ALIAS section
if ($has_aliases) {
# order by ordinal for consistent hash-order-independent output
my @alias_list = map " $_ = $aliases->{$_}\n",
sort {$aliases->{$a} <=> $aliases->{$b}}
keys %$aliases;
$alias = " ALIAS:\n" . join("", @alias_list);
}
my $retstr = $ret_typemap ? $ret_typemap->cpp_type : 'void';
# special case: constructors with name different from 'new'
# need to be declared 'static' in XS
if( $this->isa( 'ExtUtils::XSpp::Node::Constructor' ) &&
$this->perl_name ne $this->cpp_name ) {
$retstr = "static $retstr";
}
my $has_ret = $ret_typemap && !$ret_typemap->type->is_void;
my $ppcode = $has_ret && $ret_typemap->output_list( '' ) ? 1 : 0;
my $code_type = $ppcode ? "PPCODE" : "CODE";
my $ccode = $this->_call_code( $call_arg_list );
if ($this->{CALL_CODE}) {
$ccode = join( "\n", @{$this->{CALL_CODE}} );
} elsif ($this->isa('ExtUtils::XSpp::Node::Destructor')) {
$ccode = 'delete THIS';
$has_ret = 0;
} elsif( $has_ret && defined $ret_typemap->call_function_code( '', '' ) ) {
$ccode = $ret_typemap->call_function_code( $ccode, 'RETVAL' );
} elsif( $has_ret ) {
if ($has_aliases) {
$ccode = $this->_generate_alias_conditionals($call_arg_list, 1); # 1 == use RETVAL
} else {
$ccode = "RETVAL = $ccode";
}
} elsif( $has_aliases ) { # aliases but no RETVAL
$ccode = $this->_generate_alias_conditionals($call_arg_list, 0); # 0 == no RETVAL
}
my @catchers = @{$this->{EXCEPTIONS}};
$code .= " $code_type:\n";
$code .= " try {\n" if @catchers;
if ($precall) {
$code .= ' ' . $precall;
}
$code .= (@catchers ? ' ' : '') . ' ' . $ccode . ";\n";
if( $has_ret && defined $ret_typemap->output_code( '', '' ) ) {
my $retcode = $ret_typemap->output_code( 'ST(0)', 'RETVAL' );
$code .= ' ' . $retcode . ";\n";
}
if( $has_ret && defined $ret_typemap->output_list( '' ) ) {
my $retcode = $ret_typemap->output_list( 'RETVAL' );
$code .= ' ' . $retcode . ";\n";
}
$code .= " }\n" if @catchers;
foreach my $exception_handler (@catchers) {
my $handler_code = $exception_handler->handler_code;
$code .= $handler_code;
}
$output = " OUTPUT: RETVAL\n" if $has_ret;
if( $has_ret && defined $ret_typemap->cleanup_code( '', '' ) ) {
$cleanup .= " CLEANUP:\n";
my $cleanupcode = $ret_typemap->cleanup_code( 'ST(0)', 'RETVAL' );
$cleanup .= ' ' . $cleanupcode . ";\n";
}
if( $this->code ) {
$code = " $code_type:\n " . join( "\n", @{$this->code} ) . "\n";
$output = " OUTPUT: RETVAL\n" if $code =~ m/\bRETVAL\b/;
}
if( $this->postcall ) {
$postcall = " POSTCALL:\n " . join( "\n", @{$this->postcall} ) . "\n";
$output ||= " OUTPUT: RETVAL\n" if $has_ret;
}
if( $this->cleanup ) {
$cleanup ||= " CLEANUP:\n";
my $clcode = join( "\n", @{$this->cleanup} );
$cleanup .= " $clcode\n";
}
( run in 3.463 seconds using v1.01-cache-2.11-cpan-71847e10f99 )