line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Spreadsheet::Engine::Fn::base; |
2
|
|
|
|
|
|
|
|
3
|
28
|
|
|
28
|
|
176
|
use strict; |
|
28
|
|
|
|
|
62
|
|
|
28
|
|
|
|
|
1103
|
|
4
|
28
|
|
|
28
|
|
154
|
use warnings; |
|
28
|
|
|
|
|
63
|
|
|
28
|
|
|
|
|
746
|
|
5
|
|
|
|
|
|
|
|
6
|
28
|
|
|
28
|
|
154
|
use Carp; |
|
28
|
|
|
|
|
162
|
|
|
28
|
|
|
|
|
2170
|
|
7
|
28
|
|
|
28
|
|
44704
|
use Class::Struct; |
|
28
|
|
|
|
|
65242
|
|
|
28
|
|
|
|
|
194
|
|
8
|
28
|
|
|
28
|
|
4650
|
use Encode; |
|
28
|
|
|
|
|
71
|
|
|
28
|
|
|
|
|
3257
|
|
9
|
|
|
|
|
|
|
|
10
|
28
|
|
|
28
|
|
13698
|
use Spreadsheet::Engine::Value; |
|
28
|
|
|
|
|
115
|
|
|
28
|
|
|
|
|
827
|
|
11
|
28
|
|
|
28
|
|
12477
|
use Spreadsheet::Engine::Error; |
|
28
|
|
|
|
|
81
|
|
|
28
|
|
|
|
|
759
|
|
12
|
28
|
|
|
28
|
|
12266
|
use Spreadsheet::Engine::Fn::Operand; |
|
28
|
|
|
|
|
73
|
|
|
28
|
|
|
|
|
944
|
|
13
|
28
|
|
|
|
|
45435
|
use Spreadsheet::Engine::Sheet qw/ copy_function_args lookup_result_type |
14
|
|
|
|
|
|
|
operand_value_and_type operand_as_number operand_as_text |
15
|
28
|
|
|
28
|
|
175
|
top_of_stack_value_and_type /; |
|
28
|
|
|
|
|
65
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
struct(__PACKAGE__, |
18
|
|
|
|
|
|
|
{ |
19
|
|
|
|
|
|
|
fname => '$', |
20
|
|
|
|
|
|
|
operand => '$', |
21
|
|
|
|
|
|
|
errortext => '$', |
22
|
|
|
|
|
|
|
typelookup => '$', |
23
|
|
|
|
|
|
|
sheetdata => '$', |
24
|
|
|
|
|
|
|
_opstore => '@', |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub execute { |
29
|
18252
|
|
|
18252
|
1
|
25655
|
my $self = shift; |
30
|
|
|
|
|
|
|
|
31
|
18252
|
|
|
|
|
26380
|
my $result = eval { |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# make sure we check args even for functions that don't need any |
34
|
|
|
|
|
|
|
# TODO rearrange this logic |
35
|
18252
|
|
|
|
|
41588
|
my @foperand = $self->foperand; |
36
|
17970
|
|
|
|
|
60204
|
$self->result; |
37
|
|
|
|
|
|
|
}; |
38
|
|
|
|
|
|
|
|
39
|
18252
|
100
|
|
|
|
521655
|
if ($@) { |
40
|
1150
|
50
|
|
|
|
3675
|
die $@ unless ref $@; |
41
|
1150
|
|
|
|
|
1905
|
$result = $@; |
42
|
1150
|
|
|
|
|
2324
|
$result = $@; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
18252
|
50
|
|
|
|
45414
|
push @{ $self->operand }, { type => $result->type, value => $result->value } |
|
18252
|
|
|
|
|
402759
|
|
46
|
|
|
|
|
|
|
if $result; |
47
|
18252
|
|
|
|
|
673197
|
return; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub foperand { |
51
|
59395
|
|
|
59395
|
1
|
230255
|
my $self = shift; |
52
|
59395
|
100
|
|
|
|
740798
|
return $self->{_foperand} if defined $self->{_foperand}; |
53
|
|
|
|
|
|
|
|
54
|
18252
|
|
|
|
|
419992
|
copy_function_args($self->operand, \my @foperand); |
55
|
|
|
|
|
|
|
|
56
|
18252
|
50
|
66
|
|
|
127557
|
if ($self->can('argument_count') or $self->can('signature')) { |
57
|
6899
|
|
|
|
|
25720
|
my ($min_args, $max_args) = |
58
|
|
|
|
|
|
|
$self->can('argument_count') |
59
|
|
|
|
|
|
|
? ($self->argument_count) |
60
|
18252
|
100
|
|
|
|
86061
|
: (0 + @{ [ $self->signature ] }); |
61
|
18252
|
|
|
|
|
32703
|
my $have_args = scalar @foperand; |
62
|
|
|
|
|
|
|
|
63
|
18252
|
100
|
100
|
|
|
170051
|
if ( ($min_args < 0 and $have_args < -$min_args) |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
64
|
|
|
|
|
|
|
or ($min_args >= 0 and $have_args != $min_args) |
65
|
|
|
|
|
|
|
or (defined $max_args and $have_args > $max_args)) { |
66
|
282
|
|
|
|
|
6222
|
die Spreadsheet::Engine::Error->val( |
67
|
|
|
|
|
|
|
sprintf('Incorrect arguments to function "%s". ', $self->fname), |
68
|
|
|
|
|
|
|
); |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
17970
|
|
|
|
|
64817
|
return ($self->{_foperand} = \@foperand); |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
1539
|
|
|
1539
|
|
3813
|
sub _opvals { map $_->value, shift->_ops } |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub _ops { |
78
|
15595
|
|
|
15595
|
|
57146
|
my $self = shift; |
79
|
15595
|
100
|
|
|
|
16589
|
if (@{ $self->_opstore } == 0) { |
|
15595
|
|
|
|
|
358620
|
|
80
|
10051
|
|
|
|
|
70567
|
my $numargs = scalar @{ $self->foperand }; |
|
10051
|
|
|
|
|
19313
|
|
81
|
10051
|
|
|
|
|
28102
|
my @argdef = $self->signature; |
82
|
|
|
|
|
|
|
|
83
|
10051
|
|
|
|
|
15931
|
my @operands = (); |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# Loop over args, not defs, so that optional args don't fail |
86
|
10051
|
|
|
|
|
31173
|
for my $sig (@argdef[ 0 .. $numargs - 1 ]) { |
87
|
19866
|
|
|
|
|
21398
|
my $op; |
88
|
|
|
|
|
|
|
|
89
|
19866
|
100
|
|
|
|
52132
|
if ($sig eq 'n') { # any number - was 0 |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
90
|
11765
|
|
|
|
|
27992
|
$op = $self->next_operand_as_number; |
91
|
|
|
|
|
|
|
} elsif ($sig eq 't') { # any string - was 1 |
92
|
2150
|
|
|
|
|
5436
|
$op = $self->next_operand_as_text; |
93
|
|
|
|
|
|
|
} elsif ($sig eq '*') { # anything at all |
94
|
2743
|
|
|
|
|
5720
|
$op = $self->next_operand; |
95
|
|
|
|
|
|
|
} elsif ($sig eq 'r') { # range |
96
|
|
|
|
|
|
|
# TODO refactor this into Range object |
97
|
|
|
|
|
|
|
# For now we'll just hijack an op |
98
|
124
|
|
|
|
|
292
|
$op = Spreadsheet::Engine::Fn::Operand->new( |
99
|
|
|
|
|
|
|
type => 'r', |
100
|
124
|
|
|
|
|
222
|
value => pop @{ $self->foperand }, |
101
|
|
|
|
|
|
|
); |
102
|
124
|
50
|
|
|
|
4755
|
die Spreadsheet::Engine::Error->val('Incorrect arguments') |
103
|
|
|
|
|
|
|
unless $op->value->{type} eq 'range'; |
104
|
|
|
|
|
|
|
} else { |
105
|
3084
|
50
|
|
|
|
7936
|
croak 'Missing signature value in ' . $self->fname unless $sig; |
106
|
3084
|
|
|
|
|
8427
|
$op = $self->next_operand_as_number; |
107
|
3084
|
100
|
|
|
|
75181
|
my @tests = (ref $sig eq 'ARRAY') ? @{$sig} : $sig; |
|
464
|
|
|
|
|
1332
|
|
108
|
3084
|
|
|
|
|
5656
|
foreach my $check (@tests) { |
109
|
3548
|
100
|
|
|
|
19480
|
if (ref $check eq 'CODE') { |
|
|
50
|
|
|
|
|
|
110
|
1
|
50
|
|
|
|
21
|
die Spreadsheet::Engine::Error->val('Invalid arguments') |
111
|
|
|
|
|
|
|
unless $check->($op->value); |
112
|
|
|
|
|
|
|
} elsif ($check =~ /^([!<>]=?)(-?\d+)/) { # >=0 <1 etc. |
113
|
3547
|
|
|
|
|
11014
|
my ($test, $num) = ($1, $2); |
114
|
3547
|
|
|
|
|
75877
|
my $val = $op->value; |
115
|
3547
|
100
|
|
|
|
243559
|
die Spreadsheet::Engine::Error->val('Invalid arguments') |
116
|
|
|
|
|
|
|
unless eval "$val $test $num"; |
117
|
|
|
|
|
|
|
} else { |
118
|
0
|
|
|
|
|
0
|
croak "Error in signature ($check) of " . $self->fname; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
19435
|
50
|
66
|
|
|
540690
|
die $op if $op->is_error and not $self->_error_ops_ok; |
124
|
19435
|
|
|
|
|
181298
|
push @operands, $op; |
125
|
|
|
|
|
|
|
} |
126
|
9620
|
|
|
|
|
209117
|
$self->_opstore(\@operands); |
127
|
|
|
|
|
|
|
} |
128
|
15164
|
|
|
|
|
125504
|
return @{ $self->_opstore }; |
|
15164
|
|
|
|
|
311425
|
|
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# Usually, when extracting the operands based on the signature, any |
132
|
|
|
|
|
|
|
# operand that is of type 'error' will cause the entire function to die |
133
|
|
|
|
|
|
|
# with that error. Subclassing this method to return a true value will |
134
|
|
|
|
|
|
|
# allow that error to be passed through as-is. |
135
|
|
|
|
|
|
|
|
136
|
0
|
|
|
0
|
|
0
|
sub _error_ops_ok { 0 } |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub next_operand { |
139
|
11186
|
|
|
11186
|
1
|
39169
|
my $self = shift; |
140
|
11186
|
|
|
|
|
248237
|
my $value = |
141
|
|
|
|
|
|
|
operand_value_and_type($self->sheetdata, $self->foperand, |
142
|
|
|
|
|
|
|
$self->errortext, \my $tostype); |
143
|
11186
|
|
|
|
|
259006
|
return Spreadsheet::Engine::Fn::Operand->new( |
144
|
|
|
|
|
|
|
value => $value, |
145
|
|
|
|
|
|
|
type => $tostype |
146
|
|
|
|
|
|
|
); |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub next_operand_as_number { |
150
|
15007
|
|
|
15007
|
1
|
20280
|
my $self = shift; |
151
|
15007
|
|
|
|
|
324868
|
my $value = |
152
|
|
|
|
|
|
|
operand_as_number($self->sheetdata, $self->foperand, $self->errortext, |
153
|
|
|
|
|
|
|
\my $tostype); |
154
|
15007
|
|
|
|
|
377717
|
return Spreadsheet::Engine::Fn::Operand->new( |
155
|
|
|
|
|
|
|
value => $value, |
156
|
|
|
|
|
|
|
type => $tostype |
157
|
|
|
|
|
|
|
); |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
sub next_operand_as_text { |
161
|
2150
|
|
|
2150
|
1
|
2409
|
my $self = shift; |
162
|
2150
|
|
|
|
|
46794
|
my $value = |
163
|
|
|
|
|
|
|
operand_as_text($self->sheetdata, $self->foperand, $self->errortext, |
164
|
|
|
|
|
|
|
\my $tostype); |
165
|
2150
|
|
|
|
|
9474
|
return Spreadsheet::Engine::Fn::Operand->new( |
166
|
|
|
|
|
|
|
value => decode(utf8 => $value), |
167
|
|
|
|
|
|
|
type => $tostype |
168
|
|
|
|
|
|
|
); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub top_of_stack { |
172
|
396
|
|
|
396
|
1
|
571
|
my $self = shift; |
173
|
396
|
|
|
|
|
9177
|
my ($value, $type) = |
174
|
|
|
|
|
|
|
top_of_stack_value_and_type($self->sheetdata, $self->foperand, |
175
|
|
|
|
|
|
|
$self->errortext); |
176
|
396
|
100
|
|
|
|
1049
|
return unless $type; |
177
|
342
|
|
|
|
|
7128
|
return Spreadsheet::Engine::Fn::Operand->new( |
178
|
|
|
|
|
|
|
value => $value, |
179
|
|
|
|
|
|
|
type => $type |
180
|
|
|
|
|
|
|
); |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
sub optype { |
184
|
8945
|
|
|
8945
|
1
|
47484
|
my ($self, $operation, @op) = @_; |
185
|
|
|
|
|
|
|
|
186
|
8945
|
|
|
|
|
197736
|
my $tl = $self->typelookup->{$operation}; |
187
|
|
|
|
|
|
|
|
188
|
8945
|
|
|
|
|
61845
|
my $first = shift @op; |
189
|
8945
|
|
|
|
|
181839
|
my $type = $first->type; |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
# Check against self if no others supplied |
192
|
8945
|
100
|
100
|
|
|
81251
|
push @op, $first if $operation eq 'oneargnumeric' and not @op; |
193
|
|
|
|
|
|
|
|
194
|
8945
|
|
|
|
|
27751
|
while (my $next = shift @op) { |
195
|
9076
|
100
|
|
|
|
165008
|
$type = lookup_result_type($type, (ref $next ? $next->type : $next), $tl); |
196
|
|
|
|
|
|
|
} |
197
|
8945
|
|
|
|
|
200825
|
return Spreadsheet::Engine::Value->new(type => $type, value => 0); |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
1; |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
__END__ |