File Coverage

blib/lib/ExtUtils/Constant/XS.pm
Criterion Covered Total %
statement 93 98 94.9
branch 42 50 84.0
condition 6 9 66.6
subroutine 21 21 100.0
pod 4 17 23.5
total 166 195 85.1


line stmt bran cond sub pod time code
1             package ExtUtils::Constant::XS;
2              
3 1     1   8 use strict;
  1         12  
  1         37  
4 1     1   5 use vars qw($VERSION %XS_Constant %XS_TypeSet @ISA @EXPORT_OK $is_perl56);
  1         2  
  1         64  
5 1     1   4 use Carp;
  1         3  
  1         45  
6 1     1   5 use ExtUtils::Constant::Utils 'perl_stringify';
  1         2  
  1         1134  
7             require ExtUtils::Constant::Base;
8              
9              
10             @ISA = qw(ExtUtils::Constant::Base Exporter);
11             @EXPORT_OK = qw(%XS_Constant %XS_TypeSet);
12              
13             $VERSION = '0.03';
14              
15             $is_perl56 = ($] < 5.007 && $] > 5.005_50);
16              
17             =head1 NAME
18              
19             ExtUtils::Constant::XS - generate C code for XS modules' constants.
20              
21             =head1 SYNOPSIS
22              
23             require ExtUtils::Constant::XS;
24              
25             =head1 DESCRIPTION
26              
27             ExtUtils::Constant::XS overrides ExtUtils::Constant::Base to generate C
28             code for XS modules' constants.
29              
30             =head1 BUGS
31              
32             Nothing is documented.
33              
34             Probably others.
35              
36             =head1 AUTHOR
37              
38             Nicholas Clark based on the code in C by Larry Wall and
39             others
40              
41             =cut
42              
43             # '' is used as a flag to indicate non-ascii macro names, and hence the need
44             # to pass in the utf8 on/off flag.
45             %XS_Constant = (
46             '' => '',
47             IV => 'PUSHi(iv)',
48             UV => 'PUSHu((UV)iv)',
49             NV => 'PUSHn(nv)',
50             PV => 'PUSHp(pv, strlen(pv))',
51             PVN => 'PUSHp(pv, iv)',
52             SV => 'PUSHs(sv)',
53             YES => 'PUSHs(&PL_sv_yes)',
54             NO => 'PUSHs(&PL_sv_no)',
55             UNDEF => '', # implicit undef
56             );
57              
58             %XS_TypeSet = (
59             IV => '*iv_return = ',
60             UV => '*iv_return = (IV)',
61             NV => '*nv_return = ',
62             PV => '*pv_return = ',
63             PVN => ['*pv_return = ', '*iv_return = (IV)'],
64             SV => '*sv_return = ',
65             YES => undef,
66             NO => undef,
67             UNDEF => undef,
68             );
69              
70             sub header {
71 7     7 1 26 my $start = 1;
72 7         16 my @lines;
73 7         41 push @lines, "#define PERL_constant_NOTFOUND\t$start\n"; $start++;
  7         26  
74 7         37 push @lines, "#define PERL_constant_NOTDEF\t$start\n"; $start++;
  7         30  
75 7         154 foreach (sort keys %XS_Constant) {
76 70 100       161 next if $_ eq '';
77 63         177 push @lines, "#define PERL_constant_IS$_\t$start\n"; $start++;
  63         119  
78             }
79 7         42 push @lines, << 'EOT';
80              
81             #ifndef NVTYPE
82             typedef double NV; /* 5.6 and later define NVTYPE, and typedef NV to it. */
83             #endif
84             #ifndef aTHX_
85             #define aTHX_ /* 5.6 or later define this for threading support. */
86             #endif
87             #ifndef pTHX_
88             #define pTHX_ /* 5.6 or later define this for threading support. */
89             #endif
90             EOT
91              
92 7         101 return join '', @lines;
93             }
94              
95             sub valid_type {
96 165     165 0 390 my ($self, $type) = @_;
97 165         616 return exists $XS_TypeSet{$type};
98             }
99              
100             # This might actually be a return statement
101             sub assignment_clause_for_type {
102 74     74 0 153 my $self = shift;
103 74         121 my $args = shift;
104 74         148 my $type = $args->{type};
105 74         170 my $typeset = $XS_TypeSet{$type};
106 74 100       208 if (ref $typeset) {
    100          
107 1 50       4 die "Type $type is aggregate, but only single value given"
108             if @_ == 1;
109 1         5 return map {"$typeset->[$_]$_[$_];"} 0 .. $#$typeset;
  2         14  
110             } elsif (defined $typeset) {
111 70 50       167 confess "Aggregate value given for type $type"
112             if @_ > 1;
113 70         306 return "$typeset$_[0];";
114             }
115 3         12 return ();
116             }
117              
118             sub return_statement_for_type {
119 74     74 0 201 my ($self, $type) = @_;
120             # In the future may pass in an options hash
121 74 50       167 $type = $type->{type} if ref $type;
122 74         235 "return PERL_constant_IS$type;";
123             }
124              
125             sub return_statement_for_notdef {
126             # my ($self) = @_;
127 56     56 0 123 "return PERL_constant_NOTDEF;";
128             }
129              
130             sub return_statement_for_notfound {
131             # my ($self) = @_;
132 17     17 0 65 "return PERL_constant_NOTFOUND;";
133             }
134              
135             sub default_type {
136 1     1 1 11 'IV';
137             }
138              
139             sub macro_from_name {
140 115     115 0 248 my ($self, $item) = @_;
141 115         231 my $macro = $item->{name};
142 115 50       241 $macro = $item->{value} unless defined $macro;
143 115         276 $macro;
144             }
145              
146             sub macro_from_item {
147 143     143 0 308 my ($self, $item) = @_;
148 143         246 my $macro = $item->{macro};
149 143 100       458 $macro = $self->macro_from_name($item) unless defined $macro;
150 143         388 $macro;
151             }
152              
153             # Keep to the traditional perl source macro
154             sub memEQ {
155 18     18 0 48 "memEQ";
156             }
157              
158             sub params {
159 33     33 1 100 my ($self, $what) = @_;
160 33         184 foreach (sort keys %$what) {
161 74 50       223 warn "ExtUtils::Constant doesn't know how to handle values of type $_" unless defined $XS_Constant{$_};
162             }
163 33         90 my $params = {};
164 33 100       119 $params->{''} = 1 if $what->{''};
165 33 100 66     191 $params->{IV} = 1 if $what->{IV} || $what->{UV} || $what->{PVN};
      66        
166 33 100       142 $params->{NV} = 1 if $what->{NV};
167 33 100 66     176 $params->{PV} = 1 if $what->{PV} || $what->{PVN};
168 33 100       105 $params->{SV} = 1 if $what->{SV};
169 33         129 return $params;
170             }
171              
172              
173             sub C_constant_prefix_param {
174 19     19 0 67 "aTHX_ ";
175             }
176              
177             sub C_constant_prefix_param_defintion {
178 18     18 0 101 "pTHX_ ";
179             }
180              
181             sub namelen_param_definition {
182 7     7 0 46 'STRLEN ' . $_[0] -> namelen_param;
183             }
184              
185             sub C_constant_other_params_defintion {
186 17     17 0 53 my ($self, $params) = @_;
187 17         36 my $body = '';
188 17 100       68 $body .= ", int utf8" if $params->{''};
189 17 100       75 $body .= ", IV *iv_return" if $params->{IV};
190 17 100       115 $body .= ", NV *nv_return" if $params->{NV};
191 17 100       68 $body .= ", const char **pv_return" if $params->{PV};
192 17 100       56 $body .= ", SV **sv_return" if $params->{SV};
193 17         58 $body;
194             }
195              
196             sub C_constant_other_params {
197 10     10 0 33 my ($self, $params) = @_;
198 10         34 my $body = '';
199 10 100       38 $body .= ", utf8" if $params->{''};
200 10 100       41 $body .= ", iv_return" if $params->{IV};
201 10 50       31 $body .= ", nv_return" if $params->{NV};
202 10 100       36 $body .= ", pv_return" if $params->{PV};
203 10 50       25 $body .= ", sv_return" if $params->{SV};
204 10         36 $body;
205             }
206              
207             sub dogfood {
208 7     7 1 40 my ($self, $args, @items) = @_;
209             my ($package, $subname, $default_type, $what, $indent, $breakout) =
210 7         29 @{$args}{qw(package subname default_type what indent breakout)};
  7         36  
211 7         40 my $result = <<"EOT";
212             /* When generated this function returned values for the list of names given
213             in this section of perl code. Rather than manually editing these functions
214             to add or remove constants, which would result in this comment and section
215             of code becoming inaccurate, we recommend that you edit this section of
216             code, and use it to regenerate a new set of constant functions which you
217             then use to replace the originals.
218              
219             Regenerate these constant functions by feeding this entire source file to
220             perl -x
221              
222             #!$^X -w
223             use ExtUtils::Constant qw (constant_types C_constant XS_constant);
224              
225             EOT
226 7         94 $result .= $self->dump_names ({default_type=>$default_type, what=>$what,
227             indent=>0, declare_types=>1},
228             @items);
229 7         36 $result .= <<'EOT';
230              
231             print constant_types(), "\n"; # macro defs
232             EOT
233 7         62 $package = perl_stringify($package);
234 7         39 $result .=
235             "foreach (C_constant (\"$package\", '$subname', '$default_type', \$types, ";
236             # The form of the indent parameter isn't defined. (Yet)
237 7 50       27 if (defined $indent) {
238 0         0 require Data::Dumper;
239 0         0 $Data::Dumper::Terse=1;
240 0         0 $Data::Dumper::Terse=1; # Not used once. :-)
241 0         0 chomp ($indent = Data::Dumper::Dumper ($indent));
242 0         0 $result .= $indent;
243             } else {
244 7         23 $result .= 'undef';
245             }
246 7         37 $result .= ", $breakout" . ', @names) ) {
247             print $_, "\n"; # C constant subs
248             }
249             print "\n#### XS Section:\n";
250             print XS_constant ("' . $package . '", $types);
251             __END__