Mac-Carbon
view release on metacpan or search on metacpan
xsubpps/xsubpp-5.6.1 view on Meta::CPAN
if (/^TYPEMAP\s*$/) { $mode = 'Typemap'; $current = \$junk; next; }
if ($mode eq 'Typemap') {
chomp;
my $line = $_ ;
TrimWhitespace($_) ;
# skip blank lines and comment lines
next if /^$/ or /^#/ ;
my($type,$kind, $proto) = /^\s*(.*?\S)\s+(\S+)\s*($proto_re*)\s*$/ or
warn("Warning: File '$typemap' Line $. '$line' TYPEMAP entry needs 2 or 3 columns\n"), next;
$type = TidyType($type) ;
$type_kind{$type} = $kind ;
# prototype defaults to '$'
$proto = "\$" unless $proto ;
warn("Warning: File '$typemap' Line $. '$line' Invalid prototype '$proto'\n")
unless ValidProtoString($proto) ;
$proto_letter{$type} = C_string($proto) ;
}
elsif (/^\s/) {
$$current .= $_;
}
elsif ($mode eq 'Input') {
s/\s+$//;
$input_expr{$_} = '';
$current = \$input_expr{$_};
}
else {
s/\s+$//;
$output_expr{$_} = '';
$current = \$output_expr{$_};
}
}
close(TYPEMAP);
}
foreach $key (keys %input_expr) {
$input_expr{$key} =~ s/\n+$//;
}
$bal = qr[(?:(?>[^()]+)|\((??{ $bal })\))*]; # ()-balanced
$cast = qr[(?:\(\s*SV\s*\*\s*\)\s*)?]; # Optional (SV*) cast
$size = qr[,\s* (??{ $bal }) ]x; # Third arg (to setpvn)
foreach $key (keys %output_expr) {
use re 'eval';
my ($t, $with_size, $arg, $sarg) =
($output_expr{$key} =~
m[^ \s+ sv_set ( [iunp] ) v (n)? # Type, is_setpvn
\s* \( \s* $cast \$arg \s* ,
\s* ( (??{ $bal }) ) # Set from
( (??{ $size }) )? # Possible sizeof set-from
\) \s* ; \s* $
]x);
$targetable{$key} = [$t, $with_size, $arg, $sarg] if $t;
}
$END = "!End!\n\n"; # "impossible" keyword (multiple newline)
# Match an XS keyword
$BLOCK_re= '\s*(' . join('|', qw(
REQUIRE BOOT CASE PREINIT INPUT INIT CODE PPCODE OUTPUT
CLEANUP ALIAS ATTRS PROTOTYPES PROTOTYPE VERSIONCHECK INCLUDE
SCOPE INTERFACE INTERFACE_MACRO C_ARGS POSTCALL
)) . "|$END)\\s*:";
# Input: ($_, @line) == unparsed input.
# Output: ($_, @line) == (rest of line, following lines).
# Return: the matched keyword if found, otherwise 0
sub check_keyword {
$_ = shift(@line) while !/\S/ && @line;
s/^(\s*)($_[0])\s*:\s*(?:#.*)?/$1/s && $2;
}
my ($C_group_rex, $C_arg);
# Group in C (no support for comments or literals)
$C_group_rex = qr/ [({\[]
(?: (?> [^()\[\]{}]+ ) | (??{ $C_group_rex }) )*
[)}\]] /x ;
# Chunk in C without comma at toplevel (no comments):
$C_arg = qr/ (?: (?> [^()\[\]{},"']+ )
| (??{ $C_group_rex })
| " (?: (?> [^\\"]+ )
| \\.
)* " # String literal
| ' (?: (?> [^\\']+ ) | \\. )* ' # Char literal
)* /xs;
if ($WantLineNumbers) {
{
package xsubpp::counter;
sub TIEHANDLE {
my ($class, $cfile) = @_;
my $buf = "";
$SECTION_END_MARKER = "#line --- \"$cfile\"";
$line_no = 1;
bless \$buf;
}
sub PRINT {
my $self = shift;
for (@_) {
$$self .= $_;
while ($$self =~ s/^([^\n]*\n)//) {
my $line = $1;
++ $line_no;
$line =~ s|^\#line\s+---(?=\s)|#line $line_no|;
print STDOUT $line;
}
}
}
sub PRINTF {
my $self = shift;
my $fmt = shift;
$self->PRINT(sprintf($fmt, @_));
}
sub DESTROY {
# Not necessary if we're careful to end with a "\n"
my $self = shift;
print STDOUT $$self;
xsubpps/xsubpp-5.6.1 view on Meta::CPAN
@args = split(/\s*,\s*/, $orig_args);
Warn("Warning: cannot parse argument list '$orig_args', fallback to split");
}
} else {
@args = split(/\s*,\s*/, $orig_args);
for (@args) {
if ($process_inout and s/^(IN|IN_OUTLIST|OUTLIST|IN_OUT|OUT)\s+//) {
my $out_type = $1;
next if $out_type eq 'IN';
$only_outlist{$_} = 1 if $out_type eq "OUTLIST";
push @outlist, $name if $out_type =~ /OUTLIST$/;
$in_out{$_} = $out_type;
}
}
}
if (defined($class)) {
my $arg0 = ((defined($static) or $func_name eq 'new')
? "CLASS" : "THIS");
unshift(@args, $arg0);
($report_args = "$arg0, $report_args") =~ s/^\w+, $/$arg0/;
}
my $extra_args = 0;
@args_num = ();
$num_args = 0;
my $report_args = '';
foreach $i (0 .. $#args) {
if ($args[$i] =~ s/\.\.\.//) {
$elipsis = 1;
if ($args[$i] eq '' && $i == $#args) {
$report_args .= ", ...";
pop(@args);
last;
}
}
if ($only_outlist{$args[$i]}) {
push @args_num, undef;
} else {
push @args_num, ++$num_args;
$report_args .= ", $args[$i]";
}
if ($args[$i] =~ /^([^=]*[^\s=])\s*=\s*(.*)/s) {
$extra_args++;
$args[$i] = $1;
$defaults{$args[$i]} = $2;
$defaults{$args[$i]} =~ s/"/\\"/g;
}
$proto_arg[$i+1] = "\$" ;
}
$min_args = $num_args - $extra_args;
$report_args =~ s/"/\\"/g;
$report_args =~ s/^,\s+//;
my @func_args = @args;
shift @func_args if defined($class);
for (@func_args) {
s/^/&/ if $in_out{$_};
}
$func_args = join(", ", @func_args);
@args_match{@args} = @args_num;
$PPCODE = grep(/^\s*PPCODE\s*:/, @line);
$CODE = grep(/^\s*CODE\s*:/, @line);
# Detect CODE: blocks which use ST(n)= or XST_m*(n,v)
# to set explicit return values.
$EXPLICIT_RETURN = ($CODE &&
("@line" =~ /(\bST\s*\([^;]*=) | (\bXST_m\w+\s*\()/x ));
$ALIAS = grep(/^\s*ALIAS\s*:/, @line);
$INTERFACE = grep(/^\s*INTERFACE\s*:/, @line);
$xsreturn = 1 if $EXPLICIT_RETURN;
# print function header
print Q<<"EOF";
#XS(XS_${Full_func_name})
#[[
# dXSARGS;
EOF
print Q<<"EOF" if $ALIAS ;
# dXSI32;
EOF
print Q<<"EOF" if $INTERFACE ;
# dXSFUNCTION($ret_type);
EOF
if ($elipsis) {
$cond = ($min_args ? qq(items < $min_args) : 0);
}
elsif ($min_args == $num_args) {
$cond = qq(items != $min_args);
}
else {
$cond = qq(items < $min_args || items > $num_args);
}
print Q<<"EOF" if $except;
# char errbuf[1024];
# *errbuf = '\0';
EOF
if ($ALIAS)
{ print Q<<"EOF" if $cond }
# if ($cond)
# Perl_croak(aTHX_ "Usage: %s($report_args)", GvNAME(CvGV(cv)));
EOF
else
{ print Q<<"EOF" if $cond }
# if ($cond)
# Perl_croak(aTHX_ "Usage: $pname($report_args)");
EOF
print Q<<"EOF" if $PPCODE;
# SP -= items;
EOF
# Now do a block of some sort.
$condnum = 0;
$cond = ''; # last CASE: condidional
push(@line, "$END:");
push(@line_no, $line_no[-1]);
$_ = '';
&check_cpp;
while (@line) {
&CASE_handler if check_keyword("CASE");
print Q<<"EOF";
# $except [[
EOF
# do initialization of input variables
$thisdone = 0;
$retvaldone = 0;
$deferred = "";
%arg_list = () ;
$gotRETVAL = 0;
INPUT_handler() ;
process_keyword("INPUT|PREINIT|INTERFACE_MACRO|C_ARGS|ALIAS|ATTRS|PROTOTYPE|SCOPE") ;
print Q<<"EOF" if $ScopeThisXSUB;
# ENTER;
# [[
EOF
if (!$thisdone && defined($class)) {
if (defined($static) or $func_name eq 'new') {
print "\tchar *";
$var_types{"CLASS"} = "char *";
&generate_init("char *", 1, "CLASS");
}
else {
print "\t$class *";
$var_types{"THIS"} = "$class *";
&generate_init("$class *", 1, "THIS");
}
}
# do code
if (/^\s*NOT_IMPLEMENTED_YET/) {
print "\n\tPerl_croak(aTHX_ \"$pname: not implemented yet\");\n";
$_ = '' ;
} else {
if ($ret_type ne "void") {
print "\t" . &map_type($ret_type, 'RETVAL') . ";\n"
if !$retvaldone;
$args_match{"RETVAL"} = 0;
$var_types{"RETVAL"} = $ret_type;
print "\tdXSTARG;\n"
if $WantOptimize and $targetable{$type_kind{$ret_type}};
}
if (@arg_with_types) {
unshift @line, @arg_with_types, $_;
$_ = "";
$processing_arg_with_types = 1;
INPUT_handler() ;
}
XS_process($deferred);
process_keyword("INIT|ALIAS|ATTRS|PROTOTYPE|INTERFACE_MACRO|INTERFACE|C_ARGS") ;
if (check_keyword("PPCODE")) {
print_section();
death ("PPCODE must be last thing") if @line;
print "\tLEAVE;\n" if $ScopeThisXSUB;
print "\tPUTBACK;\n\treturn;\n";
} elsif (check_keyword("CODE")) {
print_section() ;
} elsif (defined($class) and $func_name eq "DESTROY") {
print "\n\t";
print "delete THIS;\n";
} else {
print "\n\t";
if ($ret_type ne "void") {
print "RETVAL = ";
$wantRETVAL = 1;
}
if (defined($static)) {
if ($func_name eq 'new') {
$func_name = "$class";
} else {
print "${class}::";
}
} elsif (defined($class)) {
if ($func_name eq 'new') {
$func_name .= " $class";
} else {
print "THIS->";
}
}
$func_name =~ s/^($spat)//
if defined($spat);
$func_name = 'XSFUNCTION' if $interface;
print "$func_name($func_args);\n";
}
}
# do output variables
$gotRETVAL = 0; # 1 if RETVAL seen in OUTPUT section;
undef $RETVAL_code ; # code to set RETVAL (from OUTPUT section);
# $wantRETVAL set if 'RETVAL =' autogenerated
($wantRETVAL, $ret_type) = (0, 'void') if $RETVAL_no_return;
undef %outargs ;
process_keyword("POSTCALL|OUTPUT|ALIAS|ATTRS|PROTOTYPE");
&generate_output($var_types{$_}, $args_match{$_}, $_, $DoSetMagic)
for grep $in_out{$_} =~ /OUT$/, keys %in_out;
# all OUTPUT done, so now push the return value on the stack
if ($gotRETVAL && $RETVAL_code) {
XS_process("\t$RETVAL_code\n");
} elsif ($gotRETVAL || $wantRETVAL) {
my $t = $WantOptimize && $targetable{$type_kind{$ret_type}};
my $var = 'RETVAL';
my $type = $ret_type;
# 0: type, 1: with_size, 2: how, 3: how_size
if ($t and not $t->[1] and $t->[0] eq 'p') {
# PUSHp corresponds to setpvn. Treate setpv directly
my $what = eval qq("$t->[2]");
warn $@ if $@;
print "\tsv_setpv(TARG, $what); XSprePUSH; PUSHTARG;\n";
$prepush_done = 1;
}
elsif ($t) {
my $what = eval qq("$t->[2]");
warn $@ if $@;
my $size = $t->[3];
$size = '' unless defined $size;
$size = eval qq("$size");
warn $@ if $@;
print "\tXSprePUSH; PUSH$t->[0]($what$size);\n";
$prepush_done = 1;
}
else {
# RETVAL almost never needs SvSETMAGIC()
&generate_output($ret_type, 0, 'RETVAL', 0);
}
}
$xsreturn = 1 if $ret_type ne "void";
my $num = $xsreturn;
my $c = @outlist;
print "\tXSprePUSH;" if $c and not $prepush_done;
print "\tEXTEND(SP,$c);\n" if $c;
$xsreturn += $c;
generate_output($var_types{$_}, $num++, $_, 0, 1) for @outlist;
# do cleanup
process_keyword("CLEANUP|ALIAS|ATTRS|PROTOTYPE") ;
print Q<<"EOF" if $ScopeThisXSUB;
# ]]
EOF
print Q<<"EOF" if $ScopeThisXSUB and not $PPCODE;
# LEAVE;
EOF
# print function trailer
print Q<<EOF;
# ]]
EOF
print Q<<EOF if $except;
# BEGHANDLERS
# CATCHALL
# sprintf(errbuf, "%s: %s\\tpropagated", Xname, Xreason);
# ENDHANDLERS
EOF
if (check_keyword("CASE")) {
blurt ("Error: No `CASE:' at top of function")
unless $condnum;
$_ = "CASE: $_"; # Restore CASE: label
next;
}
last if $_ eq "$END:";
death(/^$BLOCK_re/o ? "Misplaced `$1:'" : "Junk at end of function");
}
print Q<<EOF if $except;
# if (errbuf[0])
# Perl_croak(aTHX_ errbuf);
EOF
if ($xsreturn) {
print Q<<EOF unless $PPCODE;
# XSRETURN($xsreturn);
EOF
} else {
print Q<<EOF unless $PPCODE;
# XSRETURN_EMPTY;
EOF
}
print Q<<EOF;
#]]
#
EOF
my $newXS = "newXS" ;
my $proto = "" ;
# Build the prototype string for the xsub
if ($ProtoThisXSUB) {
$newXS = "newXSproto";
if ($ProtoThisXSUB eq 2) {
# User has specified empty prototype
$proto = ', ""' ;
}
elsif ($ProtoThisXSUB ne 1) {
# User has specified a prototype
$proto = ', "' . $ProtoThisXSUB . '"';
}
else {
my $s = ';';
if ($min_args < $num_args) {
$s = '';
$proto_arg[$min_args] .= ";" ;
}
push @proto_arg, "$s\@"
if $elipsis ;
$proto = ', "' . join ("", @proto_arg) . '"';
}
}
if (%XsubAliases) {
$XsubAliases{$pname} = 0
unless defined $XsubAliases{$pname} ;
while ( ($name, $value) = each %XsubAliases) {
push(@InitFileCode, Q<<"EOF");
# cv = newXS(\"$name\", XS_$Full_func_name, file);
# XSANY.any_i32 = $value ;
EOF
push(@InitFileCode, Q<<"EOF") if $proto;
# sv_setpv((SV*)cv$proto) ;
EOF
}
}
elsif (@Attributes) {
push(@InitFileCode, Q<<"EOF");
# cv = newXS(\"$pname\", XS_$Full_func_name, file);
# apply_attrs_string("$Package", cv, "@Attributes", 0);
EOF
}
elsif ($interface) {
while ( ($name, $value) = each %Interfaces) {
$name = "$Package\::$name" unless $name =~ /::/;
push(@InitFileCode, Q<<"EOF");
( run in 0.411 second using v1.01-cache-2.11-cpan-5511b514fd6 )