line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package types; |
2
|
|
|
|
|
|
|
|
3
|
5
|
|
|
5
|
|
370432
|
use 5.008; |
|
5
|
|
|
|
|
22
|
|
|
5
|
|
|
|
|
1375
|
|
4
|
5
|
|
|
5
|
|
35
|
use strict; |
|
5
|
|
|
|
|
14
|
|
|
5
|
|
|
|
|
273
|
|
5
|
5
|
|
|
5
|
|
26
|
use warnings; |
|
5
|
|
|
|
|
18
|
|
|
5
|
|
|
|
|
169
|
|
6
|
5
|
|
|
5
|
|
8153
|
use optimize; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION; |
9
|
|
|
|
|
|
|
$VERSION = do { my @r = (q$Revision: 1.5 $ =~ /\d+/g); $r[0] = 0; sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
my %typed; |
13
|
|
|
|
|
|
|
my %op_returns; |
14
|
|
|
|
|
|
|
my %function_returns; |
15
|
|
|
|
|
|
|
my %function_params; |
16
|
|
|
|
|
|
|
use constant SVpad_TYPED => 0x40000000; |
17
|
|
|
|
|
|
|
use B qw(OPpTARGET_MY OPf_MOD SVf_POK); |
18
|
|
|
|
|
|
|
use B::Utils; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
our %const_map = ( |
21
|
|
|
|
|
|
|
"B::NV" => 'float', |
22
|
|
|
|
|
|
|
"B::IV" => 'int', |
23
|
|
|
|
|
|
|
"B::PV" => 'string', |
24
|
|
|
|
|
|
|
); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub compare_type { |
28
|
|
|
|
|
|
|
my($a,$b) = @_; |
29
|
|
|
|
|
|
|
if($a eq $b) { |
30
|
|
|
|
|
|
|
return 1; |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
return 0; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub B::NULL::name { "void" } |
36
|
|
|
|
|
|
|
use Data::Dumper; |
37
|
|
|
|
|
|
|
sub check { |
38
|
|
|
|
|
|
|
my $class = shift; |
39
|
|
|
|
|
|
|
my $op = shift; |
40
|
|
|
|
|
|
|
my $cv = $op->find_cv(); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
#if($^H & 0x00000010) { |
43
|
|
|
|
|
|
|
unless($optimize::state->private & 0x00000010) { |
44
|
|
|
|
|
|
|
return; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# if($op->name eq 'padsv') { |
49
|
|
|
|
|
|
|
# print $op->flags ."\n"; |
50
|
|
|
|
|
|
|
# } |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
if(ref($op) eq 'B::PADOP' && $op->name eq 'gv') { |
53
|
|
|
|
|
|
|
# $op->dump; |
54
|
|
|
|
|
|
|
my $target = (($cv->PADLIST->ARRAY)[1]->ARRAY)[$op->padix]; |
55
|
|
|
|
|
|
|
# $target->dump; |
56
|
|
|
|
|
|
|
# exit; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
if($op->name eq 'int') { |
60
|
|
|
|
|
|
|
$op_returns{$op->seq}->{type} = 'int'; |
61
|
|
|
|
|
|
|
$op_returns{$op->seq}->{name} = 'int()'; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
if($op->name eq 'padsv') { |
65
|
|
|
|
|
|
|
my $target = (($cv->PADLIST->ARRAY)[0]->ARRAY)[$op->targ]; |
66
|
|
|
|
|
|
|
if(UNIVERSAL::isa($target,'B::SV') && $target->FLAGS & SVpad_TYPED) { |
67
|
|
|
|
|
|
|
$typed{$cv->ROOT->seq}->{$op->targ}->{type} = $target->SvSTASH->NAME; |
68
|
|
|
|
|
|
|
$typed{$cv->ROOT->seq}->{$op->targ}->{name} = $target->PV; |
69
|
|
|
|
|
|
|
} elsif(UNIVERSAL::isa($target,'B::SV') && |
70
|
|
|
|
|
|
|
exists($typed{$cv->ROOT->seq}->{$target->PV})) { |
71
|
|
|
|
|
|
|
$typed{$cv->ROOT->seq}->{$op->targ} = $typed{$cv->ROOT->seq}->{$target->PV}; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
if($cv->FLAGS & SVf_POK && !$function_params{$cv->START->seq}) { |
75
|
|
|
|
|
|
|
#we have, we have, we have arguments |
76
|
|
|
|
|
|
|
my @type; |
77
|
|
|
|
|
|
|
my @name; |
78
|
|
|
|
|
|
|
my $i = 1; |
79
|
|
|
|
|
|
|
foreach (split ",", $cv->PV) { |
80
|
|
|
|
|
|
|
my ($type, $sigil, $name) = split /\b/, $_; |
81
|
|
|
|
|
|
|
# print "$type - $sigil - $name \n"; |
82
|
|
|
|
|
|
|
push @type, $type; |
83
|
|
|
|
|
|
|
if($sigil && $name) { |
84
|
|
|
|
|
|
|
push @name, $sigil.$name; |
85
|
|
|
|
|
|
|
$typed{$cv->ROOT->seq}->{"$sigil$name"}->{type} = $type; |
86
|
|
|
|
|
|
|
$typed{$cv->ROOT->seq}->{"$sigil$name"}->{name} = $sigil.$name; |
87
|
|
|
|
|
|
|
} else { |
88
|
|
|
|
|
|
|
push @name, "Argument $i"; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
$i++; |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
$function_params{$cv->START->seq}->{name} = \@name; |
94
|
|
|
|
|
|
|
$function_params{$cv->START->seq}->{type} = \@type; |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
#print $cv->PV . "\n"; |
98
|
|
|
|
|
|
|
$cv->PV(";@"); |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
if(ref($op->next) ne 'B::NULL' && |
103
|
|
|
|
|
|
|
($op->next->name =~/2cv$/ || |
104
|
|
|
|
|
|
|
($op->next->name eq 'null' && $op->next->oldname =~/2cv$/))) { |
105
|
|
|
|
|
|
|
my $entersub = $op->next; |
106
|
|
|
|
|
|
|
my $i = 1; |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
while($entersub->name ne 'entersub' && |
109
|
|
|
|
|
|
|
ref($entersub->next) ne 'B::NULL') { |
110
|
|
|
|
|
|
|
$i++ if($entersub->name ne 'null'); |
111
|
|
|
|
|
|
|
$entersub = $entersub->next; |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
if($entersub->name eq 'entersub') { |
115
|
|
|
|
|
|
|
my $sv; |
116
|
|
|
|
|
|
|
if(ref($op) eq 'B::PADOP') { |
117
|
|
|
|
|
|
|
$sv = (($cv->PADLIST->ARRAY)[1]->ARRAY)[$op->padix]; |
118
|
|
|
|
|
|
|
} else { |
119
|
|
|
|
|
|
|
die; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
if(ref($sv->CV) ne 'B::SPECIAL') { |
122
|
|
|
|
|
|
|
my $foo = $sv->CV->START->seq; |
123
|
|
|
|
|
|
|
if(exists($function_returns{$foo})) { |
124
|
|
|
|
|
|
|
$op_returns{$op->seq + $i}->{type} = $function_returns{$foo}->{type}; |
125
|
|
|
|
|
|
|
$op_returns{$op->seq + $i}->{name} = $sv->STASH->NAME . "::" . $sv->SAFENAME."()"; |
126
|
|
|
|
|
|
|
# print "AND IT HAS A RETURN VALUE $i\n"; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
if(exists($function_params{$foo})) { |
129
|
|
|
|
|
|
|
my $param_list = $entersub->first(); |
130
|
|
|
|
|
|
|
get_list_proto($param_list, $cv); |
131
|
|
|
|
|
|
|
$param_list = delete($op_returns{$param_list->seq}); |
132
|
|
|
|
|
|
|
pop(@{$param_list->{type}}); |
133
|
|
|
|
|
|
|
pop(@{$param_list->{name}}); |
134
|
|
|
|
|
|
|
# print Data::Dumper::Dumper($function_params{$foo}); |
135
|
|
|
|
|
|
|
# print Data::Dumper::Dumper($param_list); |
136
|
|
|
|
|
|
|
match_protos($function_params{$foo}, $param_list); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
# $sv->CV->dump(); |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub match_protos { |
144
|
|
|
|
|
|
|
my ($target, $source) = @_; |
145
|
|
|
|
|
|
|
my $targets = scalar @{$target->{name}} - 1; |
146
|
|
|
|
|
|
|
my $sources = scalar @{$source->{name}} - 1; |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
if($sources < $targets) { |
149
|
|
|
|
|
|
|
die "Not enough items in list at " . |
150
|
|
|
|
|
|
|
$optimize::state->file . ":" . |
151
|
|
|
|
|
|
|
$optimize::state->line . "\n"; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
foreach my $i (0..$targets) { |
154
|
|
|
|
|
|
|
my ($target_name, $target_type) = |
155
|
|
|
|
|
|
|
($target->{name}->[$i], $target->{type}->[$i]); |
156
|
|
|
|
|
|
|
my ($source_name, $source_type) = |
157
|
|
|
|
|
|
|
($source->{name}->[$i], $source->{type}->[$i]); |
158
|
|
|
|
|
|
|
if((!$target_type->isa($source_type) and !$source_type->isa($target_type)) or ($target_type->can('check') && !$target_type->check($source_type))) { |
159
|
|
|
|
|
|
|
die "Type mismatch in list for" . |
160
|
|
|
|
|
|
|
" $source_type ($source_name) to $target_type ($target_name) at " . |
161
|
|
|
|
|
|
|
$optimize::state->file . ":" . |
162
|
|
|
|
|
|
|
$optimize::state->line . "\n"; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
if(ref($op->next) ne 'B::NULL') { |
170
|
|
|
|
|
|
|
# print $op->name . " - " . $op->next->name . "\n"; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
if(ref($op->next) ne 'B::NULL' && |
173
|
|
|
|
|
|
|
ref($op->next->next) ne 'B::NULL' && |
174
|
|
|
|
|
|
|
$op->next->next->name eq 'entersub') { |
175
|
|
|
|
|
|
|
# print "sub entry\n"; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
if(ref($op) eq 'B::LISTOP' && $op->first->name eq 'pushmark') { |
180
|
|
|
|
|
|
|
get_list_proto($op,$cv); |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
if(ref($op->next) ne 'B::NULL' && |
185
|
|
|
|
|
|
|
ref($cv->START) ne 'B::NULL' && |
186
|
|
|
|
|
|
|
($op->next->name eq 'lineseq' && |
187
|
|
|
|
|
|
|
$op->next->next->name =~/^leave/) || |
188
|
|
|
|
|
|
|
$op->next->name eq 'return') { |
189
|
|
|
|
|
|
|
my ($type, $value, $const) = get_type($op, $cv); |
190
|
|
|
|
|
|
|
my $lineseq = $op->next; |
191
|
|
|
|
|
|
|
my $leave = $lineseq->next; |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
if(exists($function_returns{$cv->START->seq}) && |
194
|
|
|
|
|
|
|
$function_returns{$cv->START->seq}->{type} ne $type) { |
195
|
|
|
|
|
|
|
die "Return type mismatch: " . $op->name . |
196
|
|
|
|
|
|
|
" $type at " . |
197
|
|
|
|
|
|
|
$optimize::state->file . ":" . |
198
|
|
|
|
|
|
|
$optimize::state->line . " does not match" . |
199
|
|
|
|
|
|
|
" return value $function_returns{$cv->START->seq}->{type}". |
200
|
|
|
|
|
|
|
" at $function_returns{$cv->START->seq}->{file}\n"; |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
my $subname = ""; |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
if(ref($cv->GV) ne 'B::SPECIAL' && $cv->GV->SAFENAME ne '__ANON__') { |
210
|
|
|
|
|
|
|
$subname = $cv->GV->STASH->NAME . "::" . $cv->GV->SAFENAME; |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
if($subname && exists($function_returns{$subname}) && |
213
|
|
|
|
|
|
|
$function_returns{$subname}->{type} ne $type) { |
214
|
|
|
|
|
|
|
die "Function $subname redefined with a different type (was $function_returns{$subname}->{type} now $type) at " . $optimize::state->file . ":" . $optimize::state->line . "\n"; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
$function_returns{$cv->START->seq}->{type} = $type; |
220
|
|
|
|
|
|
|
$function_returns{$cv->START->seq}->{name} = $value; |
221
|
|
|
|
|
|
|
$function_returns{$cv->START->seq}->{file} = $optimize::state->file . ":" . $optimize::state->line; |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
if($subname) { |
224
|
|
|
|
|
|
|
$function_returns{$subname} = $function_returns{$cv->START->seq}; |
225
|
|
|
|
|
|
|
# print "GOT subname $subname\n"; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
# print "scope leave retval ($type, $value): " . $op->name . "-" . $lineseq->next->name . "\n"; |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
if(ref($op) eq 'B::BINOP') { |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
my ($lhs, $rhs, $target, $expr, $const, $mod); |
239
|
|
|
|
|
|
|
my ($lhs_v, $rhs_v, $target_v, $expr_v); |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
if($op->private & OPpTARGET_MY && |
243
|
|
|
|
|
|
|
exists($typed{$cv->ROOT->seq}->{$op->targ})) { |
244
|
|
|
|
|
|
|
$target = $typed{$cv->ROOT->seq}->{$op->targ}->{type}; |
245
|
|
|
|
|
|
|
$target_v = $typed{$cv->ROOT->seq}->{$op->targ}->{name}; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
if($op->first->name eq 'padsv' |
249
|
|
|
|
|
|
|
&& exists($typed{$cv->ROOT->seq}->{$op->first->targ})) { |
250
|
|
|
|
|
|
|
$rhs = $typed{$cv->ROOT->seq}->{$op->first->targ}->{type}; |
251
|
|
|
|
|
|
|
$rhs_v = $typed{$cv->ROOT->seq}->{$op->first->targ}->{name}; |
252
|
|
|
|
|
|
|
} elsif(exists($op_returns{$op->first->seq})) { |
253
|
|
|
|
|
|
|
$rhs = $op_returns{$op->first->seq}->{type}; |
254
|
|
|
|
|
|
|
$rhs_v = $op_returns{$op->first->seq}->{name}; |
255
|
|
|
|
|
|
|
} elsif($op->first->name eq 'const' && |
256
|
|
|
|
|
|
|
exists($const_map{ref($op->first->sv)})) { |
257
|
|
|
|
|
|
|
$rhs = $const_map{ref($op->first->sv)}; |
258
|
|
|
|
|
|
|
$rhs_v = "constant '" . $op->first->sv->sv."'"; |
259
|
|
|
|
|
|
|
$const++; |
260
|
|
|
|
|
|
|
} elsif($op->first->name eq 'null' && |
261
|
|
|
|
|
|
|
$op->first->oldname eq 'list') { |
262
|
|
|
|
|
|
|
get_list_proto($op->first,$cv); |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
if($op->last->name eq 'padsv' |
266
|
|
|
|
|
|
|
&& exists($typed{$cv->ROOT->seq}->{$op->last->targ})) { |
267
|
|
|
|
|
|
|
$lhs = $typed{$cv->ROOT->seq}->{$op->last->targ}->{type}; |
268
|
|
|
|
|
|
|
$lhs_v = $typed{$cv->ROOT->seq}->{$op->last->targ}->{name}; |
269
|
|
|
|
|
|
|
if($op->last->flags & OPf_MOD) { |
270
|
|
|
|
|
|
|
die "target should be empty" if($target); |
271
|
|
|
|
|
|
|
$target = $lhs; |
272
|
|
|
|
|
|
|
$target_v = $lhs_v; |
273
|
|
|
|
|
|
|
$mod++; |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
} elsif(exists($op_returns{$op->last->seq})) { |
276
|
|
|
|
|
|
|
$lhs = $op_returns{$op->last->seq}->{type}; |
277
|
|
|
|
|
|
|
$lhs_v = $op_returns{$op->last->seq}->{name}; |
278
|
|
|
|
|
|
|
} elsif($op->last->name eq 'const' && |
279
|
|
|
|
|
|
|
exists($const_map{ref($op->last->sv)})) { |
280
|
|
|
|
|
|
|
$lhs = $const_map{ref($op->last->sv)}; |
281
|
|
|
|
|
|
|
$lhs_v = "constant '" . $op->last->sv->sv."'"; |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
} elsif($op->last->name eq 'null' && |
284
|
|
|
|
|
|
|
$op->last->oldname eq 'list') { |
285
|
|
|
|
|
|
|
get_list_proto($op->first,$cv); |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
$lhs_v = $lhs = "unknown" unless($lhs); |
290
|
|
|
|
|
|
|
$rhs_v = $rhs = "unknown" unless($rhs); |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
$target_v = $target = "" unless($target); |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
return if($target eq '' && $const); |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
#first lets deterimne what the expression returns |
299
|
|
|
|
|
|
|
# if they are equal the expression returns that |
300
|
|
|
|
|
|
|
# otherwise it returns what is higher on he inclusion team |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
{ |
304
|
|
|
|
|
|
|
my($is_lhs, $is_rhs) = (0,0); |
305
|
|
|
|
|
|
|
if($lhs->can("check") && $lhs->check($rhs)) { |
306
|
|
|
|
|
|
|
$is_lhs = 1; |
307
|
|
|
|
|
|
|
} elsif($lhs->isa($rhs)) { |
308
|
|
|
|
|
|
|
$is_lhs = 1; |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
if($rhs->can("check") && $rhs->check($lhs)) { |
312
|
|
|
|
|
|
|
$is_rhs = 1; |
313
|
|
|
|
|
|
|
} elsif($rhs->isa($lhs)) { |
314
|
|
|
|
|
|
|
$is_rhs = 1; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
if($is_lhs && $is_rhs) { |
317
|
|
|
|
|
|
|
$expr = $lhs; |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
} elsif($is_lhs) { |
320
|
|
|
|
|
|
|
$expr = $lhs; |
321
|
|
|
|
|
|
|
# print "$lhs < $rhs\n"; |
322
|
|
|
|
|
|
|
} elsif($is_rhs) { |
323
|
|
|
|
|
|
|
$expr = $rhs; |
324
|
|
|
|
|
|
|
# print "$rhs < $lhs\n"; |
325
|
|
|
|
|
|
|
} else { |
326
|
|
|
|
|
|
|
die "Type mismatch, can't " . $op->name . |
327
|
|
|
|
|
|
|
" $rhs ($rhs_v) to $lhs ($lhs_v) at " . |
328
|
|
|
|
|
|
|
$optimize::state->file . ":" . |
329
|
|
|
|
|
|
|
$optimize::state->line . "\n"; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
$expr_v = "$lhs_v, $rhs_v"; |
332
|
|
|
|
|
|
|
# print "Expression returns ($expr) ($expr_v)" . |
333
|
|
|
|
|
|
|
# $optimize::state->file . ": . " . |
334
|
|
|
|
|
|
|
# $optimize::state->line . "\n"; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
# return if(!$lhs and $op->first->name eq 'const'); |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
unless($target) { |
343
|
|
|
|
|
|
|
#the target is empty |
344
|
|
|
|
|
|
|
$op_returns{$op->seq}->{type} = $expr; |
345
|
|
|
|
|
|
|
$op_returns{$op->seq}->{name} = $expr_v; |
346
|
|
|
|
|
|
|
return; |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
# print "$expr - $target\n"; |
350
|
|
|
|
|
|
|
# print "$target->isa($expr): ". $target->isa($expr) . "\n"; |
351
|
|
|
|
|
|
|
# print "$expr->isa($target): ". $expr->isa($target) . "\n"; |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
if((!$target->isa($expr) and !$expr->isa($target)) or ($target->can('check') && !$target->check($expr))) { |
356
|
|
|
|
|
|
|
if($mod) { |
357
|
|
|
|
|
|
|
die "Type mismatch, can't " . $op->name . |
358
|
|
|
|
|
|
|
" $rhs ($rhs_v) to $lhs ($lhs_v) at " . |
359
|
|
|
|
|
|
|
$optimize::state->file . ":" . |
360
|
|
|
|
|
|
|
$optimize::state->line . "\n"; |
361
|
|
|
|
|
|
|
} else { |
362
|
|
|
|
|
|
|
die "Type mismatch, can't assign result of $lhs $lhs_v " |
363
|
|
|
|
|
|
|
. $op->name . " $rhs $rhs_v to $target ($target_v) at " |
364
|
|
|
|
|
|
|
. $optimize::state->file . ":" |
365
|
|
|
|
|
|
|
. $optimize::state->line . "\n"; |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
$op_returns{$op->seq}->{type} = $target; |
369
|
|
|
|
|
|
|
$op_returns{$op->seq}->{name} = $target_v; |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
BEGIN { $optimize::loaded{"types"} = __PACKAGE__ } |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
sub import { |
377
|
|
|
|
|
|
|
my ($package, $filename, $line) = caller; |
378
|
|
|
|
|
|
|
#$^H |= 0x00020000; |
379
|
|
|
|
|
|
|
#$^H{"use_types"}++; |
380
|
|
|
|
|
|
|
$^H |= 0x00000010; |
381
|
|
|
|
|
|
|
# optimize->register(\&entry, $package, $filename, $line); |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
sub unimport { |
385
|
|
|
|
|
|
|
my ($package, $filename, $line) = caller; |
386
|
|
|
|
|
|
|
$^H &= ~ 0x00000010; |
387
|
|
|
|
|
|
|
#$^H |= 0x00020000; |
388
|
|
|
|
|
|
|
#delete($^H{"use_types"}); |
389
|
|
|
|
|
|
|
# optimize->unregister($package); |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
sub get_type { |
393
|
|
|
|
|
|
|
my($op, $cv) = @_; |
394
|
|
|
|
|
|
|
my ($type, $value, $const) = ("","",0); |
395
|
|
|
|
|
|
|
if($op->name eq 'padsv' |
396
|
|
|
|
|
|
|
&& exists($typed{$cv->ROOT->seq}->{$op->targ})) { |
397
|
|
|
|
|
|
|
$type = $typed{$cv->ROOT->seq}->{$op->targ}->{type}; |
398
|
|
|
|
|
|
|
$value = $typed{$cv->ROOT->seq}->{$op->targ}->{name}; |
399
|
|
|
|
|
|
|
} elsif(exists($op_returns{$op->seq})) { |
400
|
|
|
|
|
|
|
$type = $op_returns{$op->seq}->{type}; |
401
|
|
|
|
|
|
|
$value = $op_returns{$op->seq}->{name}; |
402
|
|
|
|
|
|
|
} elsif($op->name eq 'const' && |
403
|
|
|
|
|
|
|
exists($const_map{ref($op->sv)})) { |
404
|
|
|
|
|
|
|
$type = $const_map{ref($op->sv)}; |
405
|
|
|
|
|
|
|
$value = "constant '" . $op->sv->sv."'"; |
406
|
|
|
|
|
|
|
$const++; |
407
|
|
|
|
|
|
|
} elsif($op->name eq 'null' && |
408
|
|
|
|
|
|
|
$op->oldname eq 'list') { |
409
|
|
|
|
|
|
|
get_list_proto($op,$cv); |
410
|
|
|
|
|
|
|
} else { |
411
|
|
|
|
|
|
|
$type = $value = "unknown"; |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
return ($type, $value, $const); |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
sub get_list_proto { |
417
|
|
|
|
|
|
|
my ($op, $cv) = @_; |
418
|
|
|
|
|
|
|
my $o = $op->first->sibling(); |
419
|
|
|
|
|
|
|
# print "start\n"; |
420
|
|
|
|
|
|
|
my @type; |
421
|
|
|
|
|
|
|
my @name; |
422
|
|
|
|
|
|
|
while(ref($o) ne 'B::NULL') { |
423
|
|
|
|
|
|
|
my $kid = $o; |
424
|
|
|
|
|
|
|
if($o->name eq 'null') { |
425
|
|
|
|
|
|
|
$kid = $o->first; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
if($kid->name eq 'padsv' && |
428
|
|
|
|
|
|
|
exists($typed{$cv->ROOT->seq}->{$kid->targ})) { |
429
|
|
|
|
|
|
|
push @type, $typed{$cv->ROOT->seq}->{$kid->targ}->{type}; |
430
|
|
|
|
|
|
|
push @name, $typed{$cv->ROOT->seq}->{$kid->targ}->{name}; |
431
|
|
|
|
|
|
|
} elsif(exists($op_returns{$kid->seq})) { |
432
|
|
|
|
|
|
|
push @type, $op_returns{$kid->seq}->{type}; |
433
|
|
|
|
|
|
|
push @name, $op_returns{$kid->seq}->{name}; |
434
|
|
|
|
|
|
|
} elsif($kid->name eq 'const' && |
435
|
|
|
|
|
|
|
exists($const_map{ref($kid->sv)})) { |
436
|
|
|
|
|
|
|
push @type, $const_map{ref($kid->sv)}; |
437
|
|
|
|
|
|
|
push @name, $kid->sv->sv; |
438
|
|
|
|
|
|
|
} else { |
439
|
|
|
|
|
|
|
push @type, "unknown"; |
440
|
|
|
|
|
|
|
push @name, "unknown"; |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
# print $kid->name . "\n"; |
443
|
|
|
|
|
|
|
$o = $o->sibling; |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
if(@type > 1) { |
447
|
|
|
|
|
|
|
$op_returns{$op->seq}->{type} = \@type; |
448
|
|
|
|
|
|
|
$op_returns{$op->seq}->{name} = \@name; |
449
|
|
|
|
|
|
|
} else { |
450
|
|
|
|
|
|
|
$op_returns{$op->seq}->{type} = $type[0]; |
451
|
|
|
|
|
|
|
$op_returns{$op->seq}->{name} = $name[0]; |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
use Data::Dumper; |
454
|
|
|
|
|
|
|
# print Dumper(\@type); |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
package unknown; |
459
|
|
|
|
|
|
|
our $dummy = 1; |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
package int; |
463
|
|
|
|
|
|
|
our $dummy = 1; |
464
|
|
|
|
|
|
|
sub check { |
465
|
|
|
|
|
|
|
return 0 if($_[0] eq 'int' && ($_[1] ne 'number' && $_[1] ne 'int')); |
466
|
|
|
|
|
|
|
return 1; |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
package float; |
469
|
|
|
|
|
|
|
use base qw(int); |
470
|
|
|
|
|
|
|
sub check { |
471
|
|
|
|
|
|
|
return 0 if($_[1] eq 'string'); |
472
|
|
|
|
|
|
|
return 1; |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
our $dummy = 1; |
475
|
|
|
|
|
|
|
package number; |
476
|
|
|
|
|
|
|
use base qw(float); |
477
|
|
|
|
|
|
|
sub check { |
478
|
|
|
|
|
|
|
return 0 if($_[1] eq 'string'); |
479
|
|
|
|
|
|
|
return 1; |
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
our $dummy = 1; |
482
|
|
|
|
|
|
|
package string; |
483
|
|
|
|
|
|
|
use base qw(number); |
484
|
|
|
|
|
|
|
sub check { return 1}; |
485
|
|
|
|
|
|
|
1; |
486
|
|
|
|
|
|
|
__END__ |