| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Error::Show; |
|
2
|
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
453101
|
use 5.024000; |
|
|
4
|
|
|
|
|
13
|
|
|
4
|
4
|
|
|
4
|
|
20
|
use strict; |
|
|
4
|
|
|
|
|
13
|
|
|
|
4
|
|
|
|
|
97
|
|
|
5
|
4
|
|
|
4
|
|
13
|
use warnings; |
|
|
4
|
|
|
|
|
15
|
|
|
|
4
|
|
|
|
|
247
|
|
|
6
|
4
|
|
|
4
|
|
54
|
use feature "say"; |
|
|
4
|
|
|
|
|
17
|
|
|
|
4
|
|
|
|
|
631
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $VERSION = 'v0.5.0'; |
|
11
|
|
|
|
|
|
|
|
|
12
|
4
|
|
|
4
|
|
1750
|
use constant::more DEBUG=>undef; |
|
|
4
|
|
|
|
|
3636
|
|
|
|
4
|
|
|
|
|
24
|
|
|
13
|
|
|
|
|
|
|
use constant::more { |
|
14
|
4
|
|
|
|
|
90
|
PACKAGE=> 0, |
|
15
|
|
|
|
|
|
|
FILENAME=> 1, |
|
16
|
|
|
|
|
|
|
LINE=> 2, |
|
17
|
|
|
|
|
|
|
SUBROUTINE=> 3, |
|
18
|
|
|
|
|
|
|
HASARGS=> 4, |
|
19
|
|
|
|
|
|
|
WANTARRAY=> 5, |
|
20
|
|
|
|
|
|
|
EVALTEXT=> 6, |
|
21
|
|
|
|
|
|
|
IS_REQUIRE=> 7, |
|
22
|
|
|
|
|
|
|
HINTS=> 8, |
|
23
|
|
|
|
|
|
|
BITMASK=> 9, |
|
24
|
|
|
|
|
|
|
HINT_HASH=> 10, |
|
25
|
|
|
|
|
|
|
MESSAGE=> 11, |
|
26
|
|
|
|
|
|
|
SEQUENCE=> 12, |
|
27
|
|
|
|
|
|
|
CODE_LINES=> 13, |
|
28
|
4
|
|
|
4
|
|
593
|
}; |
|
|
4
|
|
|
|
|
7
|
|
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# |
|
31
|
|
|
|
|
|
|
# A list of top level file paths or scalar refs to check for syntax errors |
|
32
|
|
|
|
|
|
|
# |
|
33
|
|
|
|
|
|
|
my @IINC; |
|
34
|
|
|
|
|
|
|
sub context; |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
my %programs; |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub import { |
|
39
|
4
|
|
|
4
|
|
36
|
my $package=shift; |
|
40
|
|
|
|
|
|
|
# Add support for reexporters that manipulate the export level |
|
41
|
4
|
|
50
|
|
|
57
|
my @caller=caller($Exporter::ExportLevel//0);; |
|
42
|
4
|
|
|
|
|
23
|
my @options=@_; |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# Only have one sub to export and we only export it if the caller has a line |
|
46
|
|
|
|
|
|
|
# number. Otherise we are being invoked from the CLI |
|
47
|
|
|
|
|
|
|
# |
|
48
|
4
|
50
|
|
|
|
14
|
if($caller[LINE]){ |
|
49
|
4
|
|
|
4
|
|
3522
|
no strict "refs"; |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
18916
|
|
|
50
|
4
|
|
|
|
|
5
|
my $name; |
|
51
|
4
|
|
|
|
|
8
|
$name=$caller[0]."::context"; |
|
52
|
4
|
|
|
|
|
6
|
*{$name}=\&{"context"}; |
|
|
4
|
|
|
|
|
21
|
|
|
|
4
|
|
|
|
|
12
|
|
|
53
|
|
|
|
|
|
|
|
|
54
|
4
|
|
|
|
|
8
|
$name=$caller[0]."::streval"; |
|
55
|
4
|
|
|
|
|
24
|
*{$name}=\&{"streval"}; |
|
|
4
|
|
|
|
|
22
|
|
|
|
4
|
|
|
|
|
22
|
|
|
56
|
|
|
|
|
|
|
|
|
57
|
4
|
|
|
|
|
7
|
$name=$caller[0]."::throw"; |
|
58
|
4
|
|
|
|
|
6
|
*{$name}=\&{"throw"}; |
|
|
4
|
|
|
|
|
10
|
|
|
|
4
|
|
|
|
|
11
|
|
|
59
|
4
|
|
|
|
|
3735
|
return; |
|
60
|
|
|
|
|
|
|
} |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# |
|
63
|
|
|
|
|
|
|
# CLI Options include |
|
64
|
|
|
|
|
|
|
# |
|
65
|
|
|
|
|
|
|
|
|
66
|
0
|
|
|
|
|
0
|
require POSIX; #For _exit; |
|
67
|
0
|
|
|
|
|
0
|
require IPC::Open3; |
|
68
|
0
|
|
|
|
|
0
|
require Symbol; |
|
69
|
0
|
|
|
|
|
0
|
my %options; |
|
70
|
|
|
|
|
|
|
|
|
71
|
0
|
|
|
|
|
0
|
my $clean=grep /clean/i, @options; |
|
72
|
0
|
|
|
|
|
0
|
my $splain=grep /splain/i, @options; |
|
73
|
0
|
|
|
|
|
0
|
my $do_warn=grep /warn/i, @options; |
|
74
|
0
|
|
|
|
|
0
|
my $no_handler=grep /no_handler/i, @options; |
|
75
|
|
|
|
|
|
|
|
|
76
|
0
|
0
|
|
|
|
0
|
my @warn=$do_warn?():"-MError::Show::Internal"; |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# |
|
80
|
|
|
|
|
|
|
# 1. Command line argument activation ie -MError::Show |
|
81
|
|
|
|
|
|
|
# |
|
82
|
|
|
|
|
|
|
# Find out any extra lib paths used. To do this we: |
|
83
|
|
|
|
|
|
|
# |
|
84
|
|
|
|
|
|
|
# a. fork/exec a new perl process using the value of $^X. |
|
85
|
|
|
|
|
|
|
# b. The new process dumps the @INC array to STDOUT |
|
86
|
|
|
|
|
|
|
# c. This process reads the output and stores in @IINC |
|
87
|
|
|
|
|
|
|
# |
|
88
|
|
|
|
|
|
|
# Only run it the first time its used |
|
89
|
|
|
|
|
|
|
# Is this the best way? Not sure. At least this way there is no argument |
|
90
|
|
|
|
|
|
|
# processing, perl process does it for us. |
|
91
|
|
|
|
|
|
|
# |
|
92
|
|
|
|
|
|
|
|
|
93
|
0
|
0
|
|
|
|
0
|
@IINC=map {chomp; $_} do { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
94
|
0
|
0
|
|
|
|
0
|
open my $fh, "-|", $^X . q| -E 'map print("$_\n"), @INC'| or die "$!"; |
|
95
|
0
|
|
|
|
|
0
|
<$fh>; |
|
96
|
|
|
|
|
|
|
} unless @IINC; |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# |
|
99
|
|
|
|
|
|
|
# 2. Extract the extra include paths |
|
100
|
|
|
|
|
|
|
# |
|
101
|
|
|
|
|
|
|
# Built up the 'extra' array of any include paths not already listed |
|
102
|
|
|
|
|
|
|
# from the STDOUT dumping above |
|
103
|
|
|
|
|
|
|
# |
|
104
|
0
|
|
|
|
|
0
|
my @extra=map {("-I", $_)} grep {my $i=$_; !grep { $i eq $_} @IINC} @INC; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# |
|
109
|
|
|
|
|
|
|
# 3. Syntax checking the program |
|
110
|
|
|
|
|
|
|
# |
|
111
|
|
|
|
|
|
|
# Now we have the include paths sorted, |
|
112
|
|
|
|
|
|
|
# a. fork/exec again, this time with the -c switch for perl to check syntax |
|
113
|
|
|
|
|
|
|
# b. slurp STDERR from child process |
|
114
|
|
|
|
|
|
|
# c. execute the context routine to parse and show more source code context |
|
115
|
|
|
|
|
|
|
# d. print! |
|
116
|
|
|
|
|
|
|
# The proc |
|
117
|
|
|
|
|
|
|
|
|
118
|
0
|
|
|
|
|
0
|
local $/=undef; |
|
119
|
0
|
|
|
|
|
0
|
my $file=$0; |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
#push @file, @ARGV; |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
#my $runnable=not $^C;#$options{check}; |
|
124
|
|
|
|
|
|
|
#for my $file(@file){ |
|
125
|
0
|
0
|
0
|
|
|
0
|
die "Error::Show cannot process STDIN, -e and -E programs" if $file eq "-e" or $file eq "-E" or $file eq "-"; |
|
|
|
|
0
|
|
|
|
|
|
126
|
0
|
0
|
|
|
|
0
|
die "Error::Show cannot access \"$file\"" unless -f $file; |
|
127
|
0
|
|
|
|
|
0
|
my @cmd= ($^X ,@warn, @extra, "-c", $file); |
|
128
|
|
|
|
|
|
|
|
|
129
|
0
|
|
|
|
|
0
|
my $pid; |
|
130
|
|
|
|
|
|
|
my $result; |
|
131
|
0
|
|
|
|
|
0
|
eval { |
|
132
|
0
|
|
|
|
|
0
|
$pid=IPC::Open3::open3(my $chld_in, my $chld_out, my $chld_err = Symbol::gensym(), @cmd); |
|
133
|
0
|
|
|
|
|
0
|
$result=<$chld_err>; |
|
134
|
0
|
|
|
|
|
0
|
close $chld_in; |
|
135
|
0
|
|
|
|
|
0
|
close $chld_out; |
|
136
|
0
|
|
|
|
|
0
|
close $chld_err; |
|
137
|
0
|
|
|
|
|
0
|
wait; |
|
138
|
|
|
|
|
|
|
}; |
|
139
|
0
|
0
|
0
|
|
|
0
|
if(!$pid and $@){ |
|
140
|
0
|
|
|
|
|
0
|
die "Error::Show failed to syntax check"; |
|
141
|
|
|
|
|
|
|
} |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# |
|
145
|
|
|
|
|
|
|
# 4. Status code from child indicates success |
|
146
|
|
|
|
|
|
|
# When 0 this means syntax was ok. Otherwise error |
|
147
|
|
|
|
|
|
|
# Attempt to propogate code to exit status |
|
148
|
|
|
|
|
|
|
# |
|
149
|
0
|
0
|
|
|
|
0
|
my $code=$?>255? (0xFF & ~$?): $?; |
|
150
|
|
|
|
|
|
|
|
|
151
|
0
|
|
|
|
|
0
|
my $runnable=$?==0; |
|
152
|
|
|
|
|
|
|
|
|
153
|
0
|
|
|
|
|
0
|
my $status=context( $result, splain=>$splain, clean=>$clean)."\n"; |
|
154
|
|
|
|
|
|
|
|
|
155
|
0
|
0
|
|
|
|
0
|
if($^C){ |
|
156
|
0
|
0
|
|
|
|
0
|
if($runnable){ |
|
157
|
|
|
|
|
|
|
#only print status if we want warnings |
|
158
|
0
|
0
|
|
|
|
0
|
print STDERR $do_warn?$status: "$file syntax OK\n"; |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
} |
|
161
|
|
|
|
|
|
|
else{ |
|
162
|
|
|
|
|
|
|
#Not runnable, thus syntax error. Always print |
|
163
|
0
|
|
|
|
|
0
|
print STDERR $status; |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
} |
|
166
|
0
|
|
|
|
|
0
|
POSIX::_exit $code; |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
else{ |
|
170
|
|
|
|
|
|
|
#not checking, we want to run |
|
171
|
0
|
0
|
|
|
|
0
|
if($runnable){ |
|
172
|
|
|
|
|
|
|
# don't bother with warnings |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# v0.4.0 |
|
175
|
|
|
|
|
|
|
# Install an global handler, unless asked not to |
|
176
|
|
|
|
|
|
|
# |
|
177
|
0
|
0
|
|
|
|
0
|
unless($no_handler){ |
|
178
|
|
|
|
|
|
|
$SIG{__DIE__}=sub { |
|
179
|
|
|
|
|
|
|
# propagate eval and parsing errors |
|
180
|
0
|
0
|
0
|
0
|
|
0
|
die @_ if $^S or ! defined $^S; |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# Otherwise hard error |
|
183
|
0
|
|
|
|
|
0
|
my @frames; |
|
184
|
0
|
|
|
|
|
0
|
my $i=0; |
|
185
|
0
|
|
|
|
|
0
|
push @frames , [caller $i++] while caller $i; |
|
186
|
0
|
|
|
|
|
0
|
say STDERR Error::Show::context bless {error=>$_[0], frames=>\@frames}, "Error::Show::Exception"; |
|
187
|
0
|
|
|
|
|
0
|
exit; |
|
188
|
0
|
|
|
|
|
0
|
}; |
|
189
|
|
|
|
|
|
|
} |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
else{ |
|
194
|
|
|
|
|
|
|
#Not runnable, thus syntax error. Always print |
|
195
|
0
|
|
|
|
|
0
|
print STDERR $status; |
|
196
|
0
|
|
|
|
|
0
|
POSIX::_exit $code; |
|
197
|
|
|
|
|
|
|
} |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
} |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
sub process_string_error{ |
|
203
|
|
|
|
|
|
|
|
|
204
|
8
|
|
|
8
|
0
|
12
|
my $error_in=shift; |
|
205
|
8
|
|
|
|
|
53
|
my %opts=@_; |
|
206
|
|
|
|
|
|
|
|
|
207
|
8
|
|
|
|
|
64
|
require Scalar::Util; |
|
208
|
8
|
|
|
|
|
26
|
my @error_lines; |
|
209
|
|
|
|
|
|
|
my @errors; |
|
210
|
|
|
|
|
|
|
#my @entry; |
|
211
|
8
|
|
|
|
|
0
|
my %entry; |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
# Convert the object (or string) error to string.. and process the line numbers etc. |
|
216
|
|
|
|
|
|
|
# This is the easiest way to support multiple Execption types. |
|
217
|
|
|
|
|
|
|
# |
|
218
|
8
|
|
|
|
|
0
|
my $error; |
|
219
|
8
|
|
33
|
|
|
43
|
$error||="$error_in"; |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
#local $_=$error; |
|
222
|
|
|
|
|
|
|
#Substitue with a line number relative to the start marker |
|
223
|
|
|
|
|
|
|
#Reported line numbers are 1 based, stored lines are 0 based |
|
224
|
|
|
|
|
|
|
#my $translation=$opts{translation}; |
|
225
|
|
|
|
|
|
|
#my $start=$opts{start}; |
|
226
|
|
|
|
|
|
|
|
|
227
|
8
|
|
|
|
|
15
|
my $i=0; |
|
228
|
8
|
|
|
|
|
29
|
for(split "\n", $error){ |
|
229
|
9
|
|
|
|
|
11
|
DEBUG and say STDERR "ERROR LINE: ".$_; |
|
230
|
9
|
50
|
33
|
|
|
81
|
if(/at (.*?) line (\d+)/ |
|
231
|
|
|
|
|
|
|
or /Missing right curly or square bracket at (.*?) (\d+) at end of line/){ |
|
232
|
|
|
|
|
|
|
# |
|
233
|
|
|
|
|
|
|
# Group by file names |
|
234
|
|
|
|
|
|
|
# |
|
235
|
9
|
|
|
|
|
35
|
DEBUG and say STDERR "PROCESSING: ".$_; |
|
236
|
9
|
|
|
|
|
11
|
DEBUG and say STDERR "file: $1 and line $2"; |
|
237
|
9
|
|
50
|
|
|
108
|
my $entry=$entry{$1}//=[]; |
|
238
|
|
|
|
|
|
|
#push @$entry, {file=>$1, line=>$2,message=>$_, sequence=>$i++}; |
|
239
|
9
|
|
|
|
|
24
|
my $a=[]; |
|
240
|
9
|
|
|
|
|
26
|
$a->[FILENAME]=$1; |
|
241
|
9
|
|
|
|
|
27
|
$a->[LINE]=$2-1; |
|
242
|
9
|
|
|
|
|
22
|
$a->[MESSAGE]=$_; |
|
243
|
9
|
50
|
|
|
|
28
|
$a->[MESSAGE]=$opts{message} if $opts{message}; |
|
244
|
9
|
|
|
|
|
21
|
$a->[SEQUENCE]=$i++; |
|
245
|
9
|
50
|
|
|
|
39
|
$a->[EVALTEXT]=$opts{program} if $opts{program}; |
|
246
|
9
|
|
|
|
|
29
|
push @$entry, $a; |
|
247
|
|
|
|
|
|
|
} |
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
#Key is file name |
|
253
|
|
|
|
|
|
|
# value is a hash of filename,line number, perl error string and the sequence number |
|
254
|
|
|
|
|
|
|
|
|
255
|
8
|
|
|
|
|
32
|
\%entry; |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
} |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
# Takes a hash ref 'normalized error' sources, cross reference with source |
|
260
|
|
|
|
|
|
|
# files and internal caching of string eval, and generates context lines around |
|
261
|
|
|
|
|
|
|
# target line number |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
sub text_output { |
|
264
|
27
|
|
|
27
|
0
|
38
|
my $info_ref=shift; |
|
265
|
27
|
|
|
|
|
126
|
my %opts=@_; |
|
266
|
27
|
|
|
|
|
51
|
my $total=""; |
|
267
|
27
|
|
|
|
|
30
|
DEBUG and say STDERR "Reverse flag in text output set to: $opts{reverse}"; |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# Sort by sequence number |
|
270
|
|
|
|
|
|
|
# Errors are stored by filename internally. Sort by sequence number. |
|
271
|
|
|
|
|
|
|
# |
|
272
|
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
my @sorted_info= |
|
274
|
1
|
|
|
|
|
3
|
sort {$a->[SEQUENCE] <=> $b->[SEQUENCE] } |
|
275
|
27
|
|
|
|
|
63
|
map { $_->@* } values %$info_ref; |
|
|
28
|
|
|
|
|
100
|
|
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# Reverse the order if we want the first error listed last |
|
278
|
|
|
|
|
|
|
# |
|
279
|
27
|
100
|
|
|
|
64
|
@sorted_info=reverse (@sorted_info) if $opts{reverse}; |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# Process each of the errors in sequence |
|
282
|
27
|
|
|
|
|
42
|
my $counter=0; |
|
283
|
27
|
|
50
|
|
|
94
|
my $limit=$opts{limit}//100; |
|
284
|
27
|
|
|
|
|
46
|
for my $info (@sorted_info){ |
|
285
|
28
|
50
|
33
|
|
|
62
|
last if $counter>=$limit and $limit >0; |
|
286
|
28
|
|
|
|
|
35
|
$counter++; |
|
287
|
28
|
50
|
|
|
|
69
|
unless(exists $info->[CODE_LINES]){ |
|
288
|
28
|
|
|
|
|
34
|
my @code; |
|
289
|
|
|
|
|
|
|
|
|
290
|
28
|
100
|
|
|
|
103
|
if(my @f=$info->[FILENAME] =~ /\(eval \d+\)/g){ |
|
291
|
|
|
|
|
|
|
# Not actually a file, this was an eval |
|
292
|
4
|
|
|
|
|
8
|
my $prog=$programs{$f[0]}; |
|
293
|
4
|
|
50
|
|
|
24
|
@code=split "\n", $prog//""; |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
# Remove the cached code once its been accessed, unless we really want to keep it |
|
296
|
4
|
100
|
|
|
|
26
|
delete $programs{$f[0]} unless $opts{keep}; |
|
297
|
|
|
|
|
|
|
} |
|
298
|
|
|
|
|
|
|
else { |
|
299
|
24
|
|
|
|
|
35
|
@code=split "\n", do { |
|
300
|
24
|
50
|
|
|
|
4307
|
open my $fh, "<", $info->[FILENAME] or warn "Could not open file for reading: $info->[FILENAME]"; |
|
301
|
24
|
|
|
|
|
131
|
local $/=undef; |
|
302
|
24
|
|
|
|
|
1280
|
<$fh>; |
|
303
|
|
|
|
|
|
|
}; |
|
304
|
|
|
|
|
|
|
} |
|
305
|
28
|
|
|
|
|
106
|
$info->[CODE_LINES]=\@code; |
|
306
|
|
|
|
|
|
|
} |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# At this point we have lines of code in an array |
|
309
|
|
|
|
|
|
|
# |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
#Find start mark and end mark |
|
312
|
|
|
|
|
|
|
# |
|
313
|
28
|
|
|
|
|
41
|
my $start_line=0; |
|
314
|
28
|
100
|
|
|
|
71
|
if($opts{start_mark}){ |
|
315
|
5
|
|
|
|
|
7
|
my $counter=0; |
|
316
|
5
|
|
|
|
|
6
|
my $start_mark=$opts{start_mark}; |
|
317
|
5
|
|
|
|
|
12
|
for($info->[CODE_LINES]->@*){ |
|
318
|
36
|
100
|
|
|
|
73
|
if(/$start_mark/){ |
|
319
|
4
|
|
|
|
|
5
|
$start_line+=$counter+1; |
|
320
|
4
|
|
|
|
|
7
|
last; |
|
321
|
|
|
|
|
|
|
} |
|
322
|
32
|
|
|
|
|
30
|
$counter++; |
|
323
|
|
|
|
|
|
|
} |
|
324
|
|
|
|
|
|
|
# Don't include the start marker in the results |
|
325
|
|
|
|
|
|
|
} |
|
326
|
|
|
|
|
|
|
|
|
327
|
28
|
|
|
|
|
65
|
my $end_line=$info->[CODE_LINES]->@*-1; |
|
328
|
|
|
|
|
|
|
|
|
329
|
28
|
100
|
|
|
|
54
|
if($opts{end_mark}){ |
|
330
|
5
|
|
|
|
|
5
|
my $counter=0; |
|
331
|
5
|
|
|
|
|
5
|
my $end_mark=$opts{end_mark}; |
|
332
|
5
|
|
|
|
|
8
|
for (reverse($info->[CODE_LINES]->@*)){ |
|
333
|
22
|
100
|
|
|
|
36
|
if(/$end_mark/){ |
|
334
|
4
|
|
|
|
|
5
|
$end_line-=$counter; |
|
335
|
4
|
|
|
|
|
5
|
last; |
|
336
|
|
|
|
|
|
|
} |
|
337
|
18
|
|
|
|
|
16
|
$counter++; |
|
338
|
|
|
|
|
|
|
} |
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
|
|
341
|
28
|
50
|
|
|
|
58
|
$start_line+=$opts{start_offset} if $opts{start_offset}; |
|
342
|
28
|
50
|
|
|
|
71
|
$end_line-=$opts{end_offset } if $opts{end_offset}; |
|
343
|
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
# preclamp the error line to within this range so that 'Unmatched ' errors |
|
345
|
|
|
|
|
|
|
# at least show ssomething. |
|
346
|
|
|
|
|
|
|
# |
|
347
|
28
|
50
|
|
|
|
67
|
$info->[LINE]=$end_line if $info->[LINE]>$end_line; |
|
348
|
|
|
|
|
|
|
|
|
349
|
28
|
|
|
|
|
28
|
DEBUG and say "START LINE after offset: $start_line"; |
|
350
|
28
|
|
|
|
|
30
|
DEBUG and say "END LINE after offset: $end_line"; |
|
351
|
|
|
|
|
|
|
# At this point the file min and max lines we should consider are |
|
352
|
|
|
|
|
|
|
# start_line and end line inclusive. The $start_line is also used as an |
|
353
|
|
|
|
|
|
|
# offset to shift error sources |
|
354
|
|
|
|
|
|
|
# |
|
355
|
|
|
|
|
|
|
|
|
356
|
28
|
|
|
|
|
63
|
my $min=$info->[LINE]-$opts{pre_lines}; |
|
357
|
28
|
|
|
|
|
50
|
my $max=$info->[LINE]+$opts{post_lines}; |
|
358
|
|
|
|
|
|
|
|
|
359
|
28
|
|
|
|
|
51
|
my $target= $info->[LINE];#-$start_line; |
|
360
|
28
|
|
|
|
|
35
|
DEBUG and say "TARGET: $target"; |
|
361
|
|
|
|
|
|
|
|
|
362
|
28
|
100
|
|
|
|
51
|
$min=$min<$start_line ? $start_line: $min; |
|
363
|
|
|
|
|
|
|
|
|
364
|
28
|
100
|
|
|
|
45
|
$max=$max>$end_line?$end_line:$max; |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# |
|
367
|
|
|
|
|
|
|
# format counter on the largest number to be expected |
|
368
|
|
|
|
|
|
|
# |
|
369
|
28
|
|
|
|
|
54
|
my $f_len=length("$max"); |
|
370
|
|
|
|
|
|
|
|
|
371
|
28
|
|
50
|
|
|
60
|
my $indent=$opts{current_indent}//""; |
|
372
|
28
|
|
|
|
|
102
|
my $out="$indent$info->[FILENAME]\n"; |
|
373
|
|
|
|
|
|
|
|
|
374
|
28
|
|
|
|
|
48
|
my $format="$indent%${f_len}d% 2s %s\n"; |
|
375
|
28
|
|
|
|
|
38
|
my $mark=""; |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
#Change min and max to one based index |
|
378
|
|
|
|
|
|
|
#$min++; |
|
379
|
|
|
|
|
|
|
#$max--; |
|
380
|
28
|
|
|
|
|
32
|
DEBUG and say STDERR "min before print $min"; |
|
381
|
28
|
|
|
|
|
39
|
DEBUG and say STDERR "max before print $max"; |
|
382
|
28
|
|
|
|
|
74
|
for my $l($min..$max){ |
|
383
|
268
|
|
|
|
|
342
|
$mark=""; |
|
384
|
|
|
|
|
|
|
|
|
385
|
268
|
|
|
|
|
325
|
my $a=$l-$start_line+1; |
|
386
|
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
#Perl line number is 1 based |
|
388
|
268
|
100
|
|
|
|
410
|
$mark="=>" if $l==$target; |
|
389
|
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
# Print lines as per the index in file array |
|
392
|
268
|
|
|
|
|
587
|
$out.=sprintf $format, $a, $mark, $info->[CODE_LINES][$l]; |
|
393
|
|
|
|
|
|
|
} |
|
394
|
|
|
|
|
|
|
|
|
395
|
28
|
|
|
|
|
67
|
$total.=$out; |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
# Modifiy the message now with updated line numbers |
|
398
|
|
|
|
|
|
|
# TODO: Tidy this up |
|
399
|
28
|
50
|
|
|
|
91
|
$info->[MESSAGE]=~s/line (\d+)(?:\.|,)/(($1-1)>$max?$max:$1-1)-$start_line+1/e; |
|
|
6
|
|
|
|
|
32
|
|
|
400
|
|
|
|
|
|
|
|
|
401
|
28
|
100
|
|
|
|
96
|
$total.=$info->[MESSAGE]."\n" unless $opts{clean}; |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
} |
|
404
|
27
|
50
|
|
|
|
57
|
if($opts{splain}){ |
|
405
|
0
|
|
|
|
|
0
|
$total=splain($total); |
|
406
|
|
|
|
|
|
|
} |
|
407
|
27
|
|
|
|
|
127
|
$total; |
|
408
|
|
|
|
|
|
|
} |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
# |
|
412
|
|
|
|
|
|
|
# Front end to the main processing sub. Configures and checks the inputs |
|
413
|
|
|
|
|
|
|
# |
|
414
|
|
|
|
|
|
|
my $msg= "Trace must be a ref to array of {file=>.., line=>..} pairs"; |
|
415
|
|
|
|
|
|
|
sub context{ |
|
416
|
10
|
50
|
33
|
10
|
1
|
169906
|
shift if(defined $_[0] and $_[0] eq __PACKAGE__); |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
|
|
419
|
10
|
|
|
|
|
21
|
my $error=shift; |
|
420
|
10
|
100
|
|
|
|
21
|
return unless $error; |
|
421
|
|
|
|
|
|
|
|
|
422
|
8
|
|
|
|
|
38
|
my %opts=@_; |
|
423
|
|
|
|
|
|
|
|
|
424
|
8
|
|
|
|
|
13
|
my $out; |
|
425
|
8
|
|
|
|
|
14
|
my $do_internal_frames=1; |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
#return unless $opts{error} or $opts{frames} or $do_internal_frames; |
|
428
|
|
|
|
|
|
|
#$opts{start_mark};#//=qr|.*|; #regex which matches the start of the code |
|
429
|
8
|
|
50
|
|
|
44
|
$opts{pre_lines}//=5; #Number of lines to show before target line |
|
430
|
8
|
|
50
|
|
|
38
|
$opts{post_lines}//=5; #Number of lines to show after target line |
|
431
|
8
|
|
50
|
|
|
31
|
$opts{start_offset}//=0; #Offset past start mark to consider as min line |
|
432
|
8
|
|
50
|
|
|
62
|
$opts{end_offset}//=0; #Offset before end to consider as max line |
|
433
|
8
|
|
50
|
|
|
31
|
$opts{translation}//=0; #A static value added to the line numbering |
|
434
|
8
|
|
50
|
|
|
48
|
$opts{indent}//=" "; |
|
435
|
8
|
|
50
|
|
|
34
|
$opts{file}//=""; |
|
436
|
8
|
|
|
|
|
23
|
$opts{current_indent}=""; |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
|
|
440
|
8
|
100
|
|
|
|
20
|
unless($opts{reverse}){ |
|
441
|
|
|
|
|
|
|
# Show the actual error |
|
442
|
7
|
|
|
|
|
15
|
$opts{clean}=undef; |
|
443
|
7
|
|
|
|
|
35
|
my $info_ref=process_string_error $error, %opts ; |
|
444
|
7
|
|
|
|
|
37
|
$out.=text_output $info_ref, %opts; |
|
445
|
7
|
|
|
|
|
53
|
$opts{current_indent}.=$opts{indent}; |
|
446
|
|
|
|
|
|
|
} |
|
447
|
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# Convert from supported exceptions classes to internal format |
|
453
|
8
|
|
|
|
|
15
|
my $frames; |
|
454
|
8
|
|
66
|
|
|
34
|
$frames||=eval {$error->{frames}}; # Error::Show::Exception |
|
|
8
|
|
|
|
|
64
|
|
|
455
|
8
|
|
66
|
|
|
21
|
$frames||=eval {[$error->trace->frames]}; # Exception::Class::Base ok |
|
|
3
|
|
|
|
|
119
|
|
|
456
|
8
|
|
66
|
|
|
24
|
$frames||=eval {$error->caller_stack}; # Exception::Base ok |
|
|
3
|
|
|
|
|
94
|
|
|
457
|
8
|
|
66
|
|
|
20
|
$frames||=eval {[$error->getStackTrace]}; # Class::Throwable ok |
|
|
3
|
|
|
|
|
79
|
|
|
458
|
8
|
|
66
|
|
|
16
|
$frames||=eval {\($error->frames)}; # Mojo::Exception ok |
|
|
3
|
|
|
|
|
93
|
|
|
459
|
8
|
|
100
|
|
|
24
|
$frames||=[]; |
|
460
|
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
# |
|
462
|
8
|
100
|
66
|
|
|
71
|
if($do_internal_frames and @$frames==0){ |
|
463
|
3
|
|
|
|
|
6
|
my $i=0; |
|
464
|
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
#build call frames |
|
466
|
3
|
|
|
|
|
3
|
my @frame; |
|
467
|
|
|
|
|
|
|
my @stack; |
|
468
|
|
|
|
|
|
|
|
|
469
|
3
|
|
|
|
|
46
|
while(@frame=caller($i++)){ |
|
470
|
3
|
|
|
|
|
15
|
push @$frames, [@frame]; |
|
471
|
|
|
|
|
|
|
} |
|
472
|
|
|
|
|
|
|
} |
|
473
|
|
|
|
|
|
|
|
|
474
|
8
|
|
|
|
|
13
|
my $dstf="Devel::StackTrace::Frame"; |
|
475
|
|
|
|
|
|
|
|
|
476
|
8
|
|
|
|
|
50
|
require Scalar::Util; |
|
477
|
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
#DEBUG and ; |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
# Reverse the ordering of errors here if requested |
|
482
|
|
|
|
|
|
|
# |
|
483
|
8
|
|
|
|
|
20
|
my @frames_copy=$frames->@*; |
|
484
|
8
|
100
|
|
|
|
27
|
@frames_copy=reverse @frames_copy if $opts{reverse}; |
|
485
|
|
|
|
|
|
|
# Check for trace kv pair. If this is present. We ignore the error |
|
486
|
|
|
|
|
|
|
# |
|
487
|
|
|
|
|
|
|
# Iterate through the list |
|
488
|
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
#my %_opts=%opts; |
|
490
|
8
|
|
|
|
|
16
|
$opts{clean}=1; |
|
491
|
8
|
|
|
|
|
12
|
my $i=0; #Sequence number |
|
492
|
8
|
|
|
|
|
16
|
for my $e (@frames_copy) { |
|
493
|
|
|
|
|
|
|
|
|
494
|
19
|
|
|
|
|
36
|
my $a=[]; |
|
495
|
19
|
50
|
50
|
|
|
84
|
if((Scalar::Util::blessed($e)//"") eq "Devel::StackTrace::Frame"){ |
|
496
|
|
|
|
|
|
|
#Convert to an array |
|
497
|
0
|
|
|
|
|
0
|
$a->[PACKAGE]=$e->package; |
|
498
|
0
|
|
|
|
|
0
|
$a->[FILENAME]=$e->filename; |
|
499
|
0
|
|
|
|
|
0
|
$a->[LINE]=$e->line; |
|
500
|
0
|
|
|
|
|
0
|
$a->[SUBROUTINE]=$e->subroutine; |
|
501
|
0
|
|
|
|
|
0
|
$a->[HASARGS]=$e->hasargs; |
|
502
|
0
|
|
|
|
|
0
|
$a->[WANTARRAY]=$e->wantarray; |
|
503
|
0
|
|
|
|
|
0
|
$a->[EVALTEXT]=$e->evaltext; |
|
504
|
0
|
|
|
|
|
0
|
$a->[IS_REQUIRE]=$e->is_require; |
|
505
|
0
|
|
|
|
|
0
|
$a->[HINTS]=$e->hints; |
|
506
|
0
|
|
|
|
|
0
|
$a->[BITMASK]=$e->bitmask; |
|
507
|
0
|
|
|
|
|
0
|
$a->[HINT_HASH]=$e->hints; |
|
508
|
|
|
|
|
|
|
#$e=\@a; |
|
509
|
|
|
|
|
|
|
} |
|
510
|
|
|
|
|
|
|
else { |
|
511
|
|
|
|
|
|
|
#Copy incase multiple calls to context on same error |
|
512
|
19
|
|
|
|
|
80
|
@$a=$e->@*; |
|
513
|
|
|
|
|
|
|
} |
|
514
|
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
# Skip over any frames from this package |
|
516
|
19
|
50
|
|
|
|
91
|
next if $a->[PACKAGE] eq __PACKAGE__; |
|
517
|
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
|
|
519
|
19
|
|
50
|
|
|
92
|
$a->[MESSAGE]//=""; |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
#Force a message if one is provided |
|
522
|
19
|
|
|
|
|
34
|
$a->[LINE]--; #Make the error 0 based |
|
523
|
19
|
50
|
|
|
|
69
|
$a->[MESSAGE]=$opts{message} if $opts{message}; |
|
524
|
19
|
|
|
|
|
34
|
$a->[SEQUENCE]=$i++; |
|
525
|
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
# Generate the context here |
|
527
|
|
|
|
|
|
|
# |
|
528
|
19
|
|
|
|
|
27
|
my %entry; |
|
529
|
19
|
|
|
|
|
83
|
my $entry=$entry{$a->[FILENAME]}=[]; |
|
530
|
19
|
|
|
|
|
37
|
push @$entry, $a; |
|
531
|
19
|
|
|
|
|
74
|
$out.= text_output \%entry, %opts; |
|
532
|
19
|
|
|
|
|
159
|
$opts{current_indent}.=$opts{indent}; |
|
533
|
|
|
|
|
|
|
} |
|
534
|
8
|
100
|
|
|
|
23
|
if($opts{reverse}){ |
|
535
|
|
|
|
|
|
|
# Show the actual error |
|
536
|
1
|
|
|
|
|
2
|
$opts{clean}=undef; |
|
537
|
1
|
|
|
|
|
6
|
my $info_ref=process_string_error $error, %opts ; |
|
538
|
1
|
|
|
|
|
4
|
$out.=text_output $info_ref, %opts; |
|
539
|
1
|
|
|
|
|
9
|
$opts{current_indent}.=$opts{indent}; |
|
540
|
|
|
|
|
|
|
} |
|
541
|
8
|
|
|
|
|
62
|
$out; |
|
542
|
|
|
|
|
|
|
} |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
my ($chld_in, $chld_out, $chld_err); |
|
547
|
|
|
|
|
|
|
my @cmd="splain"; |
|
548
|
|
|
|
|
|
|
my $pid; |
|
549
|
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
sub splain { |
|
551
|
0
|
|
|
0
|
1
|
0
|
my $out; |
|
552
|
|
|
|
|
|
|
#Attempt to open splain process if it isn't already |
|
553
|
0
|
0
|
|
|
|
0
|
unless($pid){ |
|
554
|
0
|
|
|
|
|
0
|
eval{ |
|
555
|
0
|
|
|
|
|
0
|
$pid= IPC::Open3::open3($chld_in, $chld_out, $chld_err = Symbol::gensym(), @cmd); |
|
556
|
|
|
|
|
|
|
#$chld_in->autoflush(1); |
|
557
|
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
}; |
|
559
|
0
|
0
|
0
|
|
|
0
|
if(!$pid and $@){ |
|
560
|
0
|
|
|
|
|
0
|
warn "Error::Show Could not splain the results"; |
|
561
|
|
|
|
|
|
|
} |
|
562
|
|
|
|
|
|
|
}; |
|
563
|
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
#Attempt to write to the process and read from it |
|
565
|
0
|
|
|
|
|
0
|
eval { |
|
566
|
0
|
|
|
|
|
0
|
print $chld_in $_[0], "\n";; |
|
567
|
0
|
|
|
|
|
0
|
close $chld_in; |
|
568
|
0
|
|
|
|
|
0
|
$out=<$chld_out>; |
|
569
|
0
|
|
|
|
|
0
|
close $chld_out; |
|
570
|
0
|
|
|
|
|
0
|
close $chld_err; |
|
571
|
|
|
|
|
|
|
}; |
|
572
|
|
|
|
|
|
|
|
|
573
|
0
|
0
|
|
|
|
0
|
if($@){ |
|
574
|
0
|
|
|
|
|
0
|
$pid=undef; |
|
575
|
0
|
|
|
|
|
0
|
close $chld_in; |
|
576
|
0
|
|
|
|
|
0
|
close $chld_out; |
|
577
|
0
|
|
|
|
|
0
|
close $chld_err; |
|
578
|
0
|
|
|
|
|
0
|
warn "Error::Show Could not splain the results"; |
|
579
|
|
|
|
|
|
|
} |
|
580
|
0
|
|
|
|
|
0
|
$out; |
|
581
|
|
|
|
|
|
|
} |
|
582
|
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
sub streval ($;$){ |
|
584
|
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
# The program we want to execute |
|
586
|
2
|
|
|
2
|
1
|
147936
|
my $code= $_[0]; |
|
587
|
2
|
50
|
|
|
|
11
|
if(ref($code) eq "CODE"){ |
|
588
|
0
|
|
|
|
|
0
|
return eval {$code->()}; |
|
|
0
|
|
|
|
|
0
|
|
|
589
|
|
|
|
|
|
|
} |
|
590
|
2
|
|
33
|
|
|
12
|
my $package=$_[1]//caller; |
|
591
|
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
# Wrap the eval in a sub. Here we can seperate syntax/complile errors and run |
|
594
|
|
|
|
|
|
|
# time errors |
|
595
|
|
|
|
|
|
|
# |
|
596
|
|
|
|
|
|
|
|
|
597
|
2
|
|
|
|
|
4
|
my $file; |
|
598
|
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
# Do eval to get current eval number and then calculate the NEXT eval number |
|
600
|
2
|
|
|
|
|
316
|
my $number=eval '__FILE__=~ qr/(\d+)/; $1'; |
|
601
|
2
|
|
|
|
|
25
|
$number++; |
|
602
|
2
|
|
|
|
|
4
|
$file="(eval $number)"; |
|
603
|
2
|
|
|
|
|
7
|
$programs{$file}=$code; |
|
604
|
2
|
|
|
|
|
5
|
my @in_sub_frame; |
|
605
|
|
|
|
|
|
|
# Attempt to compile |
|
606
|
|
|
|
|
|
|
# |
|
607
|
|
|
|
|
|
|
my $sub; |
|
608
|
|
|
|
|
|
|
{ |
|
609
|
2
|
|
|
|
|
2
|
local $@; |
|
|
2
|
|
|
|
|
5
|
|
|
610
|
|
|
|
|
|
|
#$sub=eval "sub {package $package; \@in_sub_frame=caller(0); local \$@; my \@res=eval {$code}; if(\$@){} \@res}"; |
|
611
|
2
|
|
|
|
|
363
|
$sub=eval "sub {package $package; \@in_sub_frame=caller(0); $code}"; |
|
612
|
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
# Check for SYNTAX error |
|
614
|
|
|
|
|
|
|
# |
|
615
|
2
|
|
|
|
|
16
|
my $error=$@; |
|
616
|
2
|
100
|
66
|
|
|
13
|
if(!defined($sub) or $error){ |
|
617
|
1
|
50
|
|
|
|
4
|
if(!ref $error){ |
|
618
|
|
|
|
|
|
|
# extract the filename (including the () )stored in the error |
|
619
|
1
|
|
|
|
|
7
|
my $filename= $error=~/\(eval \d+\)/g; |
|
620
|
|
|
|
|
|
|
|
|
621
|
1
|
|
|
|
|
2
|
my @frame; |
|
622
|
|
|
|
|
|
|
my @stack; |
|
623
|
|
|
|
|
|
|
|
|
624
|
1
|
|
|
|
|
2
|
my $i=1; |
|
625
|
1
|
|
|
|
|
3
|
push @stack, [@frame]; #frame from actual eval |
|
626
|
1
|
|
|
|
|
12
|
while(@frame=caller($i++)){ |
|
627
|
1
|
|
|
|
|
5
|
push @stack, [@frame]; |
|
628
|
|
|
|
|
|
|
} |
|
629
|
|
|
|
|
|
|
|
|
630
|
1
|
|
|
|
|
9
|
my $o=bless {error=>$error, frames=>\@stack}, "Error::Show::Exception"; |
|
631
|
1
|
|
|
|
|
7
|
die $o;#{error=>$error, frames=>\@stack}; |
|
632
|
|
|
|
|
|
|
} |
|
633
|
|
|
|
|
|
|
else{ |
|
634
|
0
|
|
|
|
|
0
|
die $error; |
|
635
|
|
|
|
|
|
|
} |
|
636
|
|
|
|
|
|
|
} |
|
637
|
|
|
|
|
|
|
} |
|
638
|
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
|
|
640
|
1
|
|
|
|
|
2
|
my $result; |
|
641
|
|
|
|
|
|
|
{ |
|
642
|
|
|
|
|
|
|
# Check for RUNTIME error |
|
643
|
1
|
|
|
|
|
2
|
local $@; |
|
|
1
|
|
|
|
|
1
|
|
|
644
|
1
|
|
|
|
|
1
|
my @frame; |
|
645
|
1
|
|
|
|
|
2
|
$result=eval { $sub->(); }; |
|
|
1
|
|
|
|
|
15
|
|
|
646
|
1
|
|
|
|
|
1
|
my $error=$@; |
|
647
|
1
|
50
|
|
|
|
4
|
if($error){ |
|
648
|
0
|
0
|
|
|
|
0
|
if(!ref $error){ |
|
649
|
|
|
|
|
|
|
# extract the filename stored in the error string |
|
650
|
0
|
|
|
|
|
0
|
my $filename= $error=~/\(eval (\d+)\)/g; |
|
651
|
0
|
|
|
|
|
0
|
my @stack; |
|
652
|
0
|
|
|
|
|
0
|
my $i=1; |
|
653
|
0
|
|
|
|
|
0
|
push @stack, [@in_sub_frame]; #frame from actual eval |
|
654
|
0
|
|
|
|
|
0
|
while(@frame=caller($i++)){ |
|
655
|
0
|
|
|
|
|
0
|
push @stack, [@frame]; |
|
656
|
|
|
|
|
|
|
} |
|
657
|
|
|
|
|
|
|
|
|
658
|
0
|
|
|
|
|
0
|
my $o=bless {error=>$error, frames=>\@stack}, "Error::Show::Exception"; |
|
659
|
0
|
|
|
|
|
0
|
die $o; |
|
660
|
|
|
|
|
|
|
} |
|
661
|
|
|
|
|
|
|
else { |
|
662
|
|
|
|
|
|
|
# Rethrow as is |
|
663
|
0
|
|
|
|
|
0
|
die $error; |
|
664
|
|
|
|
|
|
|
} |
|
665
|
|
|
|
|
|
|
} |
|
666
|
|
|
|
|
|
|
} |
|
667
|
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
# otherwise return the result |
|
669
|
1
|
|
|
|
|
2
|
$result; |
|
670
|
|
|
|
|
|
|
} |
|
671
|
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
sub throw { |
|
673
|
2
|
|
|
2
|
1
|
457960
|
my $error=shift; |
|
674
|
2
|
|
33
|
|
|
10
|
$error//=$@; |
|
675
|
2
|
|
|
|
|
17
|
my @c=caller(0); |
|
676
|
|
|
|
|
|
|
|
|
677
|
2
|
|
|
|
|
6
|
my @frames; |
|
678
|
2
|
|
|
|
|
5
|
my $i=1; |
|
679
|
2
|
|
|
|
|
17
|
while(my @frame=caller($i++)){ |
|
680
|
8
|
|
|
|
|
75
|
push @frames, \@frame; |
|
681
|
|
|
|
|
|
|
} |
|
682
|
|
|
|
|
|
|
|
|
683
|
2
|
50
|
|
|
|
10
|
unless(ref $error){ |
|
684
|
|
|
|
|
|
|
# Error is just a string. so we re create the file and line number |
|
685
|
|
|
|
|
|
|
# from the the caller this sub |
|
686
|
|
|
|
|
|
|
# |
|
687
|
2
|
|
|
|
|
54
|
die bless {error=>"$error at $c[1] line $c[2]", frames=>\@frames}, "Error::Show::Exception"; |
|
688
|
|
|
|
|
|
|
} |
|
689
|
|
|
|
|
|
|
else { |
|
690
|
|
|
|
|
|
|
# rethrow |
|
691
|
0
|
|
|
|
|
0
|
die bless {error=>$error, frames=>\@frames}, "Error::Show::Exception"; |
|
692
|
|
|
|
|
|
|
} |
|
693
|
|
|
|
|
|
|
} |
|
694
|
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
package Error::Show::Exception; |
|
696
|
|
|
|
|
|
|
use overload |
|
697
|
20
|
|
|
20
|
|
1279
|
'""'=>sub { "$_[0]{error}" }, |
|
698
|
4
|
|
|
4
|
|
2546
|
'eq'=>sub { "$_[0]{error}" eq $_[1] }; |
|
|
4
|
|
|
5
|
|
6411
|
|
|
|
4
|
|
|
|
|
54
|
|
|
|
5
|
|
|
|
|
28
|
|
|
699
|
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
1; |
|
701
|
|
|
|
|
|
|
__END__ |