This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
new perldelta
[perl5.git] / ext / B / t / optree_constants.t
... / ...
CommitLineData
1#!perl
2
3BEGIN {
4 unshift @INC, 't';
5 require Config;
6 if (($Config::Config{'extensions'} !~ /\bB\b/) ){
7 print "1..0 # Skip -- Perl configured without B module\n";
8 exit 0;
9 }
10}
11
12use OptreeCheck; # ALSO DOES @ARGV HANDLING !!!!!!
13
14plan tests => 99;
15
16#################################
17
18my sub lleexx {}
19sub tsub0 {}
20sub tsub1 {} $tsub1 = 1;
21sub t::tsub2 {}
22sub t::tsub3 {} $tsub3 = 1;
23{
24 package t;
25 sub tsub4 {}
26 sub tsub5 {} $tsub5 = 1;
27}
28
29use constant { # see also t/op/gv.t line 358
30 myaref => [ 1,2,3 ],
31 myfl => 1.414213,
32 myglob => \*STDIN,
33 myhref => { a => 1 },
34 myint => 42,
35 myrex => qr/foo/,
36 mystr => 'hithere',
37 mysub => \&ok,
38 myundef => undef,
39 myunsub => \&nosuch,
40 myanonsub => sub {},
41 mylexsub => \&lleexx,
42 tsub0 => \&tsub0,
43 tsub1 => \&tsub1,
44 tsub2 => \&t::tsub2,
45 tsub3 => \&t::tsub3,
46 tsub4 => \&t::tsub4,
47 tsub5 => \&t::tsub5,
48};
49
50sub myyes() { 1==1 }
51sub myno () { return 1!=1 }
52sub pi () { 3.14159 };
53
54my $want = { # expected types, how value renders in-line, todos (maybe)
55 mystr => [ 'PV', '"'.mystr.'"' ],
56 myhref => [ 'IV', '\\\\HASH'],
57 pi => [ 'NV', pi ],
58 myglob => [ 'IV', '\\\\' ],
59 mysub => [ 'IV', '\\\\&main::ok' ],
60 myunsub => [ 'IV', '\\\\&main::nosuch' ],
61 myanonsub => [ 'IV', '\\\\CODE' ],
62 mylexsub => [ 'IV', '\\\\&lleexx' ],
63 tsub0 => [ 'IV', '\\\\&main::tsub0' ],
64 tsub1 => [ 'IV', '\\\\&main::tsub1' ],
65 tsub2 => [ 'IV', '\\\\&t::tsub2' ],
66 tsub3 => [ 'IV', '\\\\&t::tsub3' ],
67 tsub4 => [ 'IV', '\\\\&t::tsub4' ],
68 tsub5 => [ 'IV', '\\\\&t::tsub5' ],
69 # these are not inlined, at least not per BC::Concise
70 #myyes => [ 'IV', ],
71 #myno => [ 'IV', ],
72 myaref => [ 'IV', '\\\\ARRAY' ],
73 myfl => [ 'NV', myfl ],
74 myint => [ 'IV', myint ],
75 myrex => [ 'IV', '\\\\"\\(?^:Foo\\)"' ],
76 myundef => [ 'NULL', ],
77};
78
79use constant WEEKDAYS
80 => qw ( Sunday Monday Tuesday Wednesday Thursday Friday Saturday );
81
82
83$::{napier} = \2.71828; # counter-example (doesn't get optimized).
84eval "sub napier ();";
85
86
87# should be able to undefine constant::import here ???
88INIT {
89 # eval 'sub constant::import () {}';
90 # undef *constant::import::{CODE};
91};
92
93#################################
94pass("RENDER CONSTANT SUBS RETURNING SCALARS");
95
96for $func (sort keys %$want) {
97 # no strict 'refs'; # why not needed ?
98 checkOptree ( name => "$func() as a coderef",
99 code => \&{$func},
100 noanchors => 1,
101 expect => <<EOT_EOT, expect_nt => <<EONT_EONT);
102 is a constant sub, optimized to a $want->{$func}[0]
103EOT_EOT
104 is a constant sub, optimized to a $want->{$func}[0]
105EONT_EONT
106
107}
108
109pass("RENDER CALLS TO THOSE CONSTANT SUBS");
110
111for $func (sort keys %$want) {
112 # print "# doing $func\n";
113 checkOptree ( name => "call $func",
114 code => "$func",
115 ($want->{$func}[2]) ? ( todo => $want->{$func}[2]) : (),
116 bc_opts => '-nobanner',
117 expect => <<EOT_EOT, expect_nt => <<EONT_EONT);
1183 <1> leavesub[2 refs] K/REFC,1 ->(end)
119- <\@> lineseq KP ->3
1201 <;> dbstate(main 833 (eval 44):1) v ->2
1212 <\$> const[$want->{$func}[0] $want->{$func}[1]] s*/FOLD ->3
122EOT_EOT
1233 <1> leavesub[2 refs] K/REFC,1 ->(end)
124- <\@> lineseq KP ->3
1251 <;> dbstate(main 833 (eval 44):1) v ->2
1262 <\$> const($want->{$func}[0] $want->{$func}[1]) s*/FOLD ->3
127EONT_EONT
128
129}
130
131##############
132pass("MORE TESTS");
133
134checkOptree ( name => 'myyes() as coderef',
135 code => sub () { 1==1 },
136 noanchors => 1,
137 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
138 is a constant sub, optimized to a SPECIAL
139EOT_EOT
140 is a constant sub, optimized to a SPECIAL
141EONT_EONT
142
143
144checkOptree ( name => 'myyes() as coderef',
145 prog => 'sub a() { 1==1 }; print a',
146 noanchors => 1,
147 strip_open_hints => 1,
148 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
149# 6 <@> leave[1 ref] vKP/REFC ->(end)
150# 1 <0> enter v ->2
151# 2 <;> nextstate(main 2 -e:1) v:>,<,%,{ ->3
152# 5 <@> print vK ->6
153# 3 <0> pushmark s ->4
154# 4 <$> const[SPECIAL sv_yes] s*/FOLD ->5
155EOT_EOT
156# 6 <@> leave[1 ref] vKP/REFC ->(end)
157# 1 <0> enter v ->2
158# 2 <;> nextstate(main 2 -e:1) v:>,<,%,{ ->3
159# 5 <@> print vK ->6
160# 3 <0> pushmark s ->4
161# 4 <$> const(SPECIAL sv_yes) s*/FOLD ->5
162EONT_EONT
163
164
165# Need to do this as a prog, not code, as only the first constant to use
166# PL_sv_no actually gets to use the real thing - every one following is
167# copied.
168checkOptree ( name => 'myno() as coderef',
169 prog => 'sub a() { 1!=1 }; print a',
170 noanchors => 1,
171 strip_open_hints => 1,
172 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
173# 6 <@> leave[1 ref] vKP/REFC ->(end)
174# 1 <0> enter v ->2
175# 2 <;> nextstate(main 2 -e:1) v:>,<,%,{ ->3
176# 5 <@> print vK ->6
177# 3 <0> pushmark s ->4
178# 4 <$> const[SPECIAL sv_no] s*/FOLD ->5
179EOT_EOT
180# 6 <@> leave[1 ref] vKP/REFC ->(end)
181# 1 <0> enter v ->2
182# 2 <;> nextstate(main 2 -e:1) v:>,<,%,{ ->3
183# 5 <@> print vK ->6
184# 3 <0> pushmark s ->4
185# 4 <$> const(SPECIAL sv_no) s*/FOLD ->5
186EONT_EONT
187
188
189my ($expect, $expect_nt) = (" is a constant sub, optimized to a AV\n") x 2;
190
191
192checkOptree ( name => 'constant sub returning list',
193 code => \&WEEKDAYS,
194 noanchors => 1,
195 expect => $expect, expect_nt => $expect_nt);
196
197
198sub printem {
199 printf "myint %d mystr %s myfl %f pi %f\n"
200 , myint, mystr, myfl, pi;
201}
202
203my ($expect, $expect_nt) = (<<'EOT_EOT', <<'EONT_EONT');
204# 9 <1> leavesub[1 ref] K/REFC,1 ->(end)
205# - <@> lineseq KP ->9
206# 1 <;> nextstate(main 635 optree_constants.t:163) v:>,<,% ->2
207# 8 <@> prtf sK ->9
208# 2 <0> pushmark sM ->3
209# 3 <$> const[PV "myint %d mystr %s myfl %f pi %f\n"] sM/FOLD ->4
210# 4 <$> const[IV 42] sM*/FOLD ->5
211# 5 <$> const[PV "hithere"] sM*/FOLD ->6
212# 6 <$> const[NV 1.414213] sM*/FOLD ->7
213# 7 <$> const[NV 3.14159] sM*/FOLD ->8
214EOT_EOT
215# 9 <1> leavesub[1 ref] K/REFC,1 ->(end)
216# - <@> lineseq KP ->9
217# 1 <;> nextstate(main 635 optree_constants.t:163) v:>,<,% ->2
218# 8 <@> prtf sK ->9
219# 2 <0> pushmark sM ->3
220# 3 <$> const(PV "myint %d mystr %s myfl %f pi %f\n") sM/FOLD ->4
221# 4 <$> const(IV 42) sM*/FOLD ->5
222# 5 <$> const(PV "hithere") sM*/FOLD ->6
223# 6 <$> const(NV 1.414213) sM*/FOLD ->7
224# 7 <$> const(NV 3.14159) sM*/FOLD ->8
225EONT_EONT
226
227s|\\n"[])] sM\K/FOLD|| for $expect, $expect_nt;
228
229checkOptree ( name => 'call many in a print statement',
230 code => \&printem,
231 strip_open_hints => 1,
232 expect => $expect, expect_nt => $expect_nt);
233
234# test constant expression folding
235
236checkOptree ( name => 'arithmetic constant folding in print',
237 code => 'print 1+2+3',
238 strip_open_hints => 1,
239 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
240# 5 <1> leavesub[1 ref] K/REFC,1 ->(end)
241# - <@> lineseq KP ->5
242# 1 <;> nextstate(main 937 (eval 53):1) v ->2
243# 4 <@> print sK ->5
244# 2 <0> pushmark s ->3
245# 3 <$> const[IV 6] s/FOLD ->4
246EOT_EOT
247# 5 <1> leavesub[1 ref] K/REFC,1 ->(end)
248# - <@> lineseq KP ->5
249# 1 <;> nextstate(main 937 (eval 53):1) v ->2
250# 4 <@> print sK ->5
251# 2 <0> pushmark s ->3
252# 3 <$> const(IV 6) s/FOLD ->4
253EONT_EONT
254
255checkOptree ( name => 'string constant folding in print',
256 code => 'print "foo"."bar"',
257 strip_open_hints => 1,
258 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
259# 5 <1> leavesub[1 ref] K/REFC,1 ->(end)
260# - <@> lineseq KP ->5
261# 1 <;> nextstate(main 942 (eval 55):1) v ->2
262# 4 <@> print sK ->5
263# 2 <0> pushmark s ->3
264# 3 <$> const[PV "foobar"] s/FOLD ->4
265EOT_EOT
266# 5 <1> leavesub[1 ref] K/REFC,1 ->(end)
267# - <@> lineseq KP ->5
268# 1 <;> nextstate(main 942 (eval 55):1) v ->2
269# 4 <@> print sK ->5
270# 2 <0> pushmark s ->3
271# 3 <$> const(PV "foobar") s/FOLD ->4
272EONT_EONT
273
274checkOptree ( name => 'boolean or folding',
275 code => 'print "foobar" if 1 or 0',
276 strip_open_hints => 1,
277 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
278# 5 <1> leavesub[1 ref] K/REFC,1 ->(end)
279# - <@> lineseq KP ->5
280# 1 <;> nextstate(main 942 (eval 55):1) v ->2
281# 4 <@> print sK/FOLD ->5
282# 2 <0> pushmark s ->3
283# 3 <$> const[PV "foobar"] s ->4
284EOT_EOT
285# 5 <1> leavesub[1 ref] K/REFC,1 ->(end)
286# - <@> lineseq KP ->5
287# 1 <;> nextstate(main 942 (eval 55):1) v ->2
288# 4 <@> print sK/FOLD ->5
289# 2 <0> pushmark s ->3
290# 3 <$> const(PV "foobar") s ->4
291EONT_EONT
292
293checkOptree ( name => 'lc*,uc*,gt,lt,ge,le,cmp',
294 code => sub {
295 $s = uc('foo.').ucfirst('bar.').lc('LOW.').lcfirst('LOW');
296 print "a-lt-b" if "a" lt "b";
297 print "b-gt-a" if "b" gt "a";
298 print "a-le-b" if "a" le "b";
299 print "b-ge-a" if "b" ge "a";
300 print "b-cmp-a" if "b" cmp "a";
301 print "a-gt-b" if "a" gt "b"; # should be suppressed
302 },
303 strip_open_hints => 1,
304 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
305# r <1> leavesub[1 ref] K/REFC,1 ->(end)
306# - <@> lineseq KP ->r
307# 1 <;> nextstate(main 916 optree_constants.t:307) v:>,<,%,{ ->2
308# 4 <2> sassign vKS/2 ->5
309# 2 <$> const[PV "FOO.Bar.low.lOW"] s/FOLD ->3
310# - <1> ex-rv2sv sKRM*/1 ->4
311# 3 <#> gvsv[*s] s ->4
312# 5 <;> nextstate(main 916 optree_constants.t:308) v:>,<,%,{ ->6
313# 8 <@> print vK/FOLD ->9
314# 6 <0> pushmark s ->7
315# 7 <$> const[PV "a-lt-b"] s ->8
316# 9 <;> nextstate(main 916 optree_constants.t:309) v:>,<,%,{ ->a
317# c <@> print vK/FOLD ->d
318# a <0> pushmark s ->b
319# b <$> const[PV "b-gt-a"] s ->c
320# d <;> nextstate(main 916 optree_constants.t:310) v:>,<,%,{ ->e
321# g <@> print vK/FOLD ->h
322# e <0> pushmark s ->f
323# f <$> const[PV "a-le-b"] s ->g
324# h <;> nextstate(main 916 optree_constants.t:311) v:>,<,%,{ ->i
325# k <@> print vK/FOLD ->l
326# i <0> pushmark s ->j
327# j <$> const[PV "b-ge-a"] s ->k
328# l <;> nextstate(main 916 optree_constants.t:312) v:>,<,%,{ ->m
329# o <@> print vK/FOLD ->p
330# m <0> pushmark s ->n
331# n <$> const[PV "b-cmp-a"] s ->o
332# p <;> nextstate(main 916 optree_constants.t:313) v:>,<,%,{ ->q
333# q <$> const[SPECIAL sv_no] s/SHORT,FOLD ->r
334EOT_EOT
335# r <1> leavesub[1 ref] K/REFC,1 ->(end)
336# - <@> lineseq KP ->r
337# 1 <;> nextstate(main 916 optree_constants.t:307) v:>,<,%,{ ->2
338# 4 <2> sassign vKS/2 ->5
339# 2 <$> const(PV "FOO.Bar.low.lOW") s/FOLD ->3
340# - <1> ex-rv2sv sKRM*/1 ->4
341# 3 <$> gvsv(*s) s ->4
342# 5 <;> nextstate(main 916 optree_constants.t:308) v:>,<,%,{ ->6
343# 8 <@> print vK/FOLD ->9
344# 6 <0> pushmark s ->7
345# 7 <$> const(PV "a-lt-b") s ->8
346# 9 <;> nextstate(main 916 optree_constants.t:309) v:>,<,%,{ ->a
347# c <@> print vK/FOLD ->d
348# a <0> pushmark s ->b
349# b <$> const(PV "b-gt-a") s ->c
350# d <;> nextstate(main 916 optree_constants.t:310) v:>,<,%,{ ->e
351# g <@> print vK/FOLD ->h
352# e <0> pushmark s ->f
353# f <$> const(PV "a-le-b") s ->g
354# h <;> nextstate(main 916 optree_constants.t:311) v:>,<,%,{ ->i
355# k <@> print vK/FOLD ->l
356# i <0> pushmark s ->j
357# j <$> const(PV "b-ge-a") s ->k
358# l <;> nextstate(main 916 optree_constants.t:312) v:>,<,%,{ ->m
359# o <@> print vK/FOLD ->p
360# m <0> pushmark s ->n
361# n <$> const(PV "b-cmp-a") s ->o
362# p <;> nextstate(main 916 optree_constants.t:313) v:>,<,%,{ ->q
363# q <$> const(SPECIAL sv_no) s/SHORT,FOLD ->r
364EONT_EONT
365
366checkOptree ( name => 'mixed constant folding, with explicit braces',
367 code => 'print "foo"."bar".(2+3)',
368 strip_open_hints => 1,
369 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
370# 5 <1> leavesub[1 ref] K/REFC,1 ->(end)
371# - <@> lineseq KP ->5
372# 1 <;> nextstate(main 977 (eval 28):1) v ->2
373# 4 <@> print sK ->5
374# 2 <0> pushmark s ->3
375# 3 <$> const[PV "foobar5"] s/FOLD ->4
376EOT_EOT
377# 5 <1> leavesub[1 ref] K/REFC,1 ->(end)
378# - <@> lineseq KP ->5
379# 1 <;> nextstate(main 977 (eval 28):1) v ->2
380# 4 <@> print sK ->5
381# 2 <0> pushmark s ->3
382# 3 <$> const(PV "foobar5") s/FOLD ->4
383EONT_EONT
384
385__END__
386
387=head NB
388
389Optimized constant subs are stored as bare scalars in the stash
390(package hash), which formerly held only GVs (typeglobs).
391
392But you cant create them manually - you cant assign a scalar to a
393stash element, and expect it to work like a constant-sub, even if you
394provide a prototype.
395
396This is a feature; alternative is too much action-at-a-distance. The
397following test demonstrates - napier is not seen as a function at all,
398much less an optimized one.
399
400=cut
401
402checkOptree ( name => 'not evertnapier',
403 code => \&napier,
404 noanchors => 1,
405 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
406 has no START
407EOT_EOT
408 has no START
409EONT_EONT
410
411