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   6 use strict;
  1         7  
  1         27  
4 1     1   4 use vars qw($VERSION %XS_Constant %XS_TypeSet @ISA @EXPORT_OK $is_perl56);
  1         2  
  1         59  
5 1     1   4 use Carp;
  1         2  
  1         42  
6 1     1   5 use ExtUtils::Constant::Utils 'perl_stringify';
  1         2  
  1         1086  
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 28 my $start = 1;
72 7         22 my @lines;
73 7         43 push @lines, "#define PERL_constant_NOTFOUND\t$start\n"; $start++;
  7         24  
74 7         26 push @lines, "#define PERL_constant_NOTDEF\t$start\n"; $start++;
  7         17  
75 7         143 foreach (sort keys %XS_Constant) {
76 70 100       188 next if $_ eq '';
77 63         188 push @lines, "#define PERL_constant_IS$_\t$start\n"; $start++;
  63         129  
78             }
79 7         41 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         83 return join '', @lines;
93             }
94              
95             sub valid_type {
96 165     165 0 373 my ($self, $type) = @_;
97 165         1257 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 162 my $self = shift;
103 74         138 my $args = shift;
104 74         165 my $type = $args->{type};
105 74         176 my $typeset = $XS_TypeSet{$type};
106 74 100       309 if (ref $typeset) {
    100          
107 1 50       6 die "Type $type is aggregate, but only single value given"
108             if @_ == 1;
109 1         7 return map {"$typeset->[$_]$_[$_];"} 0 .. $#$typeset;
  2         16  
110             } elsif (defined $typeset) {
111 70 50       210 confess "Aggregate value given for type $type"
112             if @_ > 1;
113 70         340 return "$typeset$_[0];";
114             }
115 3         14 return ();
116             }
117              
118             sub return_statement_for_type {
119 74     74 0 199 my ($self, $type) = @_;
120             # In the future may pass in an options hash
121 74 50       211 $type = $type->{type} if ref $type;
122 74         269 "return PERL_constant_IS$type;";
123             }
124              
125             sub return_statement_for_notdef {
126             # my ($self) = @_;
127 56     56 0 166 "return PERL_constant_NOTDEF;";
128             }
129              
130             sub return_statement_for_notfound {
131             # my ($self) = @_;
132 17     17 0 62 "return PERL_constant_NOTFOUND;";
133             }
134              
135             sub default_type {
136 1     1 1 8 'IV';
137             }
138              
139             sub macro_from_name {
140 115     115 0 228 my ($self, $item) = @_;
141 115         222 my $macro = $item->{name};
142 115 50       288 $macro = $item->{value} unless defined $macro;
143 115         289 $macro;
144             }
145              
146             sub macro_from_item {
147 143     143 0 315 my ($self, $item) = @_;
148 143         286 my $macro = $item->{macro};
149 143 100       446 $macro = $self->macro_from_name($item) unless defined $macro;
150 143         419 $macro;
151             }
152              
153             # Keep to the traditional perl source macro
154             sub memEQ {
155 18     18 0 58 "memEQ";
156             }
157              
158             sub params {
159 33     33 1 100 my ($self, $what) = @_;
160 33         175 foreach (sort keys %$what) {
161 74 50       258 warn "ExtUtils::Constant doesn't know how to handle values of type $_" unless defined $XS_Constant{$_};
162             }
163 33         96 my $params = {};
164 33 100       131 $params->{''} = 1 if $what->{''};
165 33 100 66     189 $params->{IV} = 1 if $what->{IV} || $what->{UV} || $what->{PVN};
      66        
166 33 100       108 $params->{NV} = 1 if $what->{NV};
167 33 100 66     173 $params->{PV} = 1 if $what->{PV} || $what->{PVN};
168 33 100       117 $params->{SV} = 1 if $what->{SV};
169 33         116 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 89 "pTHX_ ";
179             }
180              
181             sub namelen_param_definition {
182 7     7 0 88 'STRLEN ' . $_[0] -> namelen_param;
183             }
184              
185             sub C_constant_other_params_defintion {
186 17     17 0 60 my ($self, $params) = @_;
187 17         52 my $body = '';
188 17 100       66 $body .= ", int utf8" if $params->{''};
189 17 100       92 $body .= ", IV *iv_return" if $params->{IV};
190 17 100       116 $body .= ", NV *nv_return" if $params->{NV};
191 17 100       74 $body .= ", const char **pv_return" if $params->{PV};
192 17 100       57 $body .= ", SV **sv_return" if $params->{SV};
193 17         69 $body;
194             }
195              
196             sub C_constant_other_params {
197 10     10 0 32 my ($self, $params) = @_;
198 10         33 my $body = '';
199 10 100       42 $body .= ", utf8" if $params->{''};
200 10 100       35 $body .= ", iv_return" if $params->{IV};
201 10 50       34 $body .= ", nv_return" if $params->{NV};
202 10 100       39 $body .= ", pv_return" if $params->{PV};
203 10 50       41 $body .= ", sv_return" if $params->{SV};
204 10         34 $body;
205             }
206              
207             sub dogfood {
208 7     7 1 39 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         40  
211 7         41 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         102 $result .= $self->dump_names ({default_type=>$default_type, what=>$what,
227             indent=>0, declare_types=>1},
228             @items);
229 7         38 $result .= <<'EOT';
230              
231             print constant_types(), "\n"; # macro defs
232             EOT
233 7         58 $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       32 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         20 $result .= 'undef';
245             }
246 7         32 $result .= ", $breakout" . ', @names) ) {
247             print $_, "\n"; # C constant subs
248             }
249             print "\n#### XS Section:\n";
250             print XS_constant ("' . $package . '", $types);
251             __END__