File Coverage

blib/lib/XS/Install/FrozenShit/Typemaps/OutputMap.pm
Criterion Covered Total %
statement 45 56 80.3
branch 13 18 72.2
condition 3 6 50.0
subroutine 10 11 90.9
pod 6 6 100.0
total 77 97 79.3


line stmt bran cond sub pod time code
1             package
2             XS::Install::FrozenShit::Typemaps::OutputMap;
3 1     1   13 use 5.006001;
  1         4  
4 1     1   4 use strict;
  1         2  
  1         15  
5 1     1   3 use warnings;
  1         1  
  1         863  
6             our $VERSION = '3.57';
7              
8             =head1 NAME
9              
10             XS::Install::FrozenShit::Typemaps::OutputMap - Entry in the OUTPUT section of a typemap
11              
12             =head1 SYNOPSIS
13              
14             use XS::Install::FrozenShit::Typemaps;
15             ...
16             my $output = $typemap->get_output_map('T_NV');
17             my $code = $output->code();
18             $output->code("...");
19              
20             =head1 DESCRIPTION
21              
22             Refer to L for details.
23              
24             =head1 METHODS
25              
26             =cut
27              
28             =head2 new
29              
30             Requires C and C parameters.
31              
32             =cut
33              
34             sub new {
35 150     150 1 270 my $prot = shift;
36 150   66     420 my $class = ref($prot)||$prot;
37 150         328 my %args = @_;
38              
39 150 100       323 if (!ref($prot)) {
40 50 50 33     187 if (not defined $args{xstype} or not defined $args{code}) {
41 0         0 die("Need xstype and code parameters");
42             }
43             }
44              
45 150 100       682 my $self = bless(
46             (ref($prot) ? {%$prot} : {})
47             => $class
48             );
49              
50 150 100       429 $self->{xstype} = $args{xstype} if defined $args{xstype};
51 150 100       381 $self->{code} = $args{code} if defined $args{code};
52 150         502 $self->{code} =~ s/^(?=\S)/\t/mg;
53              
54 150         484 return $self;
55             }
56              
57             =head2 code
58              
59             Returns or sets the OUTPUT mapping code for this entry.
60              
61             =cut
62              
63             sub code {
64 3 50   3 1 9 $_[0]->{code} = $_[1] if @_ > 1;
65 3         10 return $_[0]->{code};
66             }
67              
68             =head2 xstype
69              
70             Returns the name of the XS type of the OUTPUT map.
71              
72             =cut
73              
74             sub xstype {
75 200     200 1 645 return $_[0]->{xstype};
76             }
77              
78             =head2 cleaned_code
79              
80             Returns a cleaned-up copy of the code to which certain transformations
81             have been applied to make it more ANSI compliant.
82              
83             =cut
84              
85             sub cleaned_code {
86 2     2 1 5 my $self = shift;
87 2         8 my $code = $self->code;
88              
89             # Move C pre-processor instructions to column 1 to be strictly ANSI
90             # conformant. Some pre-processors are fussy about this.
91 2         7 $code =~ s/^\s+#/#/mg;
92 2         86 $code =~ s/\s*\z/\n/;
93              
94 2         10 return $code;
95             }
96              
97             =head2 targetable_legacy
98              
99             Do not use for new code.
100              
101             This is the original version of the targetable() method, whose behaviour
102             has been frozen for backwards compatibility. It is used to determine
103             whether to emit an early C, which will be in scope for most of
104             the XSUB. More recent XSUB code generation emits a C in a tighter
105             scope if one has not already been emitted. Some XS code assumes that
106             C has been declared, so continue to declare it under the same
107             conditions as before. The newer C method may be true under
108             additional circumstances.
109              
110             If the optimization can not be applied, this returns undef. If it can be
111             applied, this method returns a hash reference containing the following
112             information:
113              
114             type: Any of the characters i, u, n, p
115             with_size: Bool indicating whether this is the sv_setpvn variant
116             what: The code that actually evaluates to the output scalar
117             what_size: If "with_size", this has the string length (as code,
118             not constant, including leading comma)
119              
120              
121             =cut
122              
123             sub targetable_legacy {
124 2     2 1 5 my $self = shift;
125 2 100       14 return $self->{targetable_legacy} if exists $self->{targetable_legacy};
126              
127 1         2 our $bal; # ()-balanced
128             $bal = qr[
129             (?:
130             (?>[^()]+)
131             |
132             \( (??{ $bal }) \)
133             )*
134 1         20 ]x;
135             my $bal_no_comma = qr[
136             (?:
137             (?>[^(),]+)
138             |
139             \( (??{ $bal }) \)
140             )+
141 1         7 ]x;
142              
143             # matches variations on (SV*)
144 1         4 my $sv_cast = qr[
145             (?:
146             \( \s* SV \s* \* \s* \) \s*
147             )?
148             ]x;
149              
150             my $size = qr[ # Third arg (to setpvn)
151             , \s* (??{ $bal })
152 1         7 ]xo;
153              
154 1         4 my $code = $self->code;
155              
156             # We can still bootstrap compile 're', because in code re.pm is
157             # available to miniperl, and does not attempt to load the XS code.
158 1     1   9 use re 'eval';
  1         2  
  1         405  
159              
160 1         322 my ($type, $with_size, $arg, $sarg) =
161             ($code =~
162             m[^
163             \s+
164             sv_set([iunp])v(n)? # Type, is_setpvn
165             \s*
166             \( \s*
167             $sv_cast \$arg \s* , \s*
168             ( $bal_no_comma ) # Set from
169             ( $size )? # Possible sizeof set-from
170             \s* \) \s* ; \s* $
171             ]xo
172             );
173              
174 1         6 my $rv = undef;
175 1 50       6 if ($type) {
176 0         0 $rv = {
177             type => $type,
178             with_size => $with_size,
179             what => $arg,
180             what_size => $sarg,
181             };
182             }
183 1         9 $self->{targetable_legacy} = $rv;
184 1         41 return $rv;
185             }
186              
187             =head2 targetable
188              
189             Class method.
190              
191             Return a boolean indicating whether the supplied code snippet is suitable
192             for using TARG as the destination SV rather than an new mortal.
193              
194             In principle most things are, except expressions which would set the SV
195             to a ref value. That can cause the referred value to never be freed, as
196             targs aren't freed (at least for the lifetime of their CV). So in
197             practice, we restrict it to an approved list of sv_setfoo() forms, and
198             only where there is no extra code following the sv_setfoo() (so we have to
199             match the closing bracket, allowing for nested brackets etc within).
200              
201             =cut
202              
203             my %targetable_cache;
204              
205             sub targetable {
206 0     0 1   my ($class, $code) = @_;
207              
208 0 0         return $targetable_cache{$code} if exists $targetable_cache{$code};
209              
210             # Match a string with zero or more balanced/nested parentheses
211             # within it, e.g.
212             #
213             # "aa,bb(cc,dd)ee(ff,gg(hh,ii)jj,kk)ll"
214              
215 0           our $bal;
216             $bal = qr[
217             (?:
218             (?>[^()]+)
219             |
220             " ([^"] | \\")* "
221             |
222             \( (??{ $bal }) \)
223             )*
224 0           ]x;
225              
226             # Like $bal, but doesn't allow commas at the *top* level; e.g.
227             #
228             # "aabb(cc,dd)ee(ff,gg(hh,ii)jj,kk)ll"
229             #
230             # Something like "aa,bb(cc,dd)" will just match/consume the "aa"
231             # part of the string.
232              
233             my $bal_no_comma = qr[
234             (?:
235             (?>[^(),]+)
236             |
237             " ([^"] | \\")* "
238             |
239             \( (??{ $bal }) \)
240             )+
241 0           ]x;
242              
243             # the SV whose value is to be set (typically arg 1)
244             # Note that currently ParseXS will always call with $arg expanded
245             # to 'RETVALSV', but also match other possibilities too for future
246             # use.
247              
248 0           my $target = qr[
249             (?:
250             \( \s* SV \s* \* \s* \) \s* # optional SV* cast
251             )?
252             (?:
253             \$arg
254             |
255             RETVAL
256             |
257             RETVALSV
258             |
259             ST\(\d+\)
260             )
261             \s*
262             ]x;
263              
264             # We can still bootstrap compile 're', because in code re.pm is
265             # available to miniperl, and does not attempt to load the XS code.
266 1     1   6 use re 'eval';
  1         1  
  1         133  
267              
268 0           my $match =
269             ($code =~
270             m[^
271             \s*
272             (?:
273             # 1-arg functions
274             sv_set_(?:undef|true|false)
275             \s*
276             \( \s*
277             $target # arg 1: SV to set
278             |
279             # 2-arg functions
280             sv_set(?:iv|iv_mg|uv|uv_mg|nv|nv_mg|pv|pv_mg|_bool)
281             \s*
282             \( \s*
283             $target # arg 1: SV to set
284             , \s*
285             $bal_no_comma # arg 2: value to use
286             |
287             # 3-arg functions
288             sv_set(?:pvn|pvn_mg)
289             \s*
290             \( \s*
291             $target # arg 1: SV to set
292             , \s*
293             $bal_no_comma # arg 2: value to use
294             , \s*
295             $bal_no_comma # arg 3: length
296             )
297             \s* \)
298             \s* ; \s*
299             $
300             ]xo
301             );
302              
303 0           $targetable_cache{$code} = $match;
304 0           return $match;
305             }
306              
307             =head1 SEE ALSO
308              
309             L
310              
311             =head1 AUTHOR
312              
313             Steffen Mueller C<>
314              
315             =head1 COPYRIGHT & LICENSE
316              
317             Copyright 2009, 2010, 2011, 2012 Steffen Mueller
318              
319             This program is free software; you can redistribute it and/or
320             modify it under the same terms as Perl itself.
321              
322             =cut
323              
324             1;
325