| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Templ::Parser; |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
4
|
use strict; |
|
|
1
|
|
|
|
|
11
|
|
|
|
1
|
|
|
|
|
25
|
|
|
4
|
1
|
|
|
1
|
|
3
|
use warnings; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
19
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
3
|
use Carp qw(cluck croak); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
37
|
|
|
7
|
1
|
|
|
1
|
|
3
|
use Data::Dumper; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
956
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
my $PKG = __PACKAGE__; |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
eval { require Perl::Tidy; require File::Temp }; |
|
12
|
|
|
|
|
|
|
my $can_tidy = $@ ? 0 : 1; |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
eval { require v5.10; }; |
|
15
|
|
|
|
|
|
|
my $can_say = $@ ? 0 : 1; |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub new { |
|
18
|
0
|
|
|
0
|
0
|
|
my $class = shift; |
|
19
|
0
|
0
|
0
|
|
|
|
if ( not defined $class || ref $class || $class !~ m/^(\w+\:\:)*\w+$/ ) { |
|
|
|
|
0
|
|
|
|
|
|
20
|
0
|
|
|
|
|
|
croak "Can only be called as Templ::Parser::...->new"; |
|
21
|
|
|
|
|
|
|
} |
|
22
|
0
|
0
|
|
|
|
|
if ($class eq $PKG) { |
|
23
|
0
|
|
|
|
|
|
croak "$PKG cannot be instantiated directly, use a subclass"; |
|
24
|
|
|
|
|
|
|
} |
|
25
|
0
|
|
|
|
|
|
my $self = bless {@_}, $class; |
|
26
|
0
|
|
|
|
|
|
return $self; |
|
27
|
|
|
|
|
|
|
} |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub parse { |
|
30
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
31
|
0
|
|
|
|
|
|
my $templ = shift; |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# The template is assumed to be starting as printing output, so |
|
34
|
|
|
|
|
|
|
# wrap the whole template in a header/footer, escaping the contents |
|
35
|
0
|
|
|
|
|
|
my $perl = ''; |
|
36
|
0
|
0
|
|
|
|
|
if ($self->prettify) { $perl .= $self->pretty_header; } |
|
|
0
|
|
|
|
|
|
|
|
37
|
0
|
|
|
|
|
|
my $quoted = $templ->templ_code; |
|
38
|
0
|
|
|
|
|
|
$quoted =~ s|\\|\\\\|gs; |
|
39
|
0
|
|
|
|
|
|
$quoted =~ s|'|\\'|gs; |
|
40
|
0
|
|
|
|
|
|
$perl .= $templ->header; |
|
41
|
0
|
|
|
|
|
|
$perl .= $self->header; |
|
42
|
0
|
|
|
|
|
|
$perl .= "'$quoted'"; |
|
43
|
0
|
|
|
|
|
|
$perl .= $self->footer; |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# Loop over all of the remaining <* ... *> tag types, performing the |
|
46
|
|
|
|
|
|
|
# prescribed replacements... run in reverse to process latest / deepest |
|
47
|
|
|
|
|
|
|
# subclass tags first |
|
48
|
|
|
|
|
|
|
# |
|
49
|
|
|
|
|
|
|
# $self->debug && print Data::Dumper->Dump([[$templ->tags]],['tags']); |
|
50
|
|
|
|
|
|
|
# $self->debug && print Data::Dumper->Dump([$templ],['templ']); |
|
51
|
0
|
|
|
|
|
|
foreach my $tag ( $templ->tags ) { |
|
52
|
0
|
|
|
|
|
|
$perl = $tag->process( $perl, $self ); |
|
53
|
|
|
|
|
|
|
} |
|
54
|
|
|
|
|
|
|
|
|
55
|
0
|
0
|
|
|
|
|
if ( $self->prettify ) { |
|
56
|
|
|
|
|
|
|
# Change any standalone single-quote print statements with |
|
57
|
|
|
|
|
|
|
# literal newlines in them to a series of individual print |
|
58
|
|
|
|
|
|
|
# or say statements for readability |
|
59
|
0
|
|
|
|
|
|
$perl =~ s{ |
|
60
|
|
|
|
|
|
|
(?: |
|
61
|
|
|
|
|
|
|
# $1 = Previous statement separator |
|
62
|
|
|
|
|
|
|
( (?: ^ | \; | \{ | \} ) [ \t]*? (?:\r?\n)? ) |
|
63
|
|
|
|
|
|
|
# $2 = Print statement indentation |
|
64
|
|
|
|
|
|
|
( \s*? ) |
|
65
|
|
|
|
|
|
|
# $3 = Double quote contents |
|
66
|
|
|
|
|
|
|
print \s* '(.*?)(?
|
|
67
|
|
|
|
|
|
|
# $4 = Closing brace or semicolon |
|
68
|
|
|
|
|
|
|
( \s* (?: (?:\;|\}) (?:\r?\n)? | $ ) ) |
|
69
|
|
|
|
|
|
|
) |
|
70
|
|
|
|
|
|
|
} |
|
71
|
0
|
|
|
|
|
|
{ $self->prettify_lines($1, $2, $3, $4) }egsx; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
|
|
74
|
0
|
0
|
|
|
|
|
if ( $self->tidy ) { |
|
75
|
0
|
0
|
|
|
|
|
if ($can_tidy) { |
|
76
|
0
|
|
|
|
|
|
require File::Temp; |
|
77
|
0
|
|
|
|
|
|
require Perl::Tidy; |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# Using a temp file because the output is weird when we don't |
|
80
|
0
|
|
|
|
|
|
( undef, my $tmp ) = File::Temp::tempfile(); |
|
81
|
0
|
|
|
|
|
|
Perl::Tidy::perltidy( |
|
82
|
|
|
|
|
|
|
'source' => \$perl, |
|
83
|
|
|
|
|
|
|
'destination' => $tmp, |
|
84
|
|
|
|
|
|
|
'argv' => [ split /\s+/, $self->tidy_options ], |
|
85
|
|
|
|
|
|
|
); |
|
86
|
0
|
|
0
|
|
|
|
open my $FH, '<', $tmp |
|
87
|
|
|
|
|
|
|
|| die "Unable to open file for reading $tmp: $!"; |
|
88
|
0
|
|
|
|
|
|
local $/ = undef; |
|
89
|
0
|
|
|
|
|
|
$perl = <$FH>; |
|
90
|
0
|
|
|
|
|
|
close $FH; |
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
else { |
|
93
|
0
|
|
|
|
|
|
warn "Unable to load Perl::Tidy and/or File::Temp\n"; |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
|
|
97
|
0
|
0
|
0
|
|
|
|
if ( $self->tidy || $self->prettify ) { |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# Remove blank append statements |
|
100
|
0
|
|
|
|
|
|
my $append = $self->append; |
|
101
|
0
|
|
|
|
|
|
$perl =~ s/(?:^|(?<=\n)[ \t]*)\Q$append\E'';[ \t]*(?:\r?\n|$)//; |
|
102
|
|
|
|
|
|
|
} |
|
103
|
|
|
|
|
|
|
|
|
104
|
0
|
0
|
|
|
|
|
if ( $self->debug ) { |
|
105
|
0
|
|
|
|
|
|
my @lines = split /\n/, $perl; |
|
106
|
0
|
|
|
|
|
|
my $format = '%' . length( scalar(@lines) . '' ) . "s: %s\n"; |
|
107
|
0
|
|
|
|
|
|
print STDERR sprintf( $format, ( $_ + 1 ), $lines[$_] ) foreach (0 .. $#lines); |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
|
|
110
|
0
|
|
|
|
|
|
return $perl; |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
# Breaks a print statement with newlines in it into multiple statements |
|
114
|
|
|
|
|
|
|
# Helps with formatting code to preserve indentation (used when prettify is |
|
115
|
|
|
|
|
|
|
# enabled) |
|
116
|
|
|
|
|
|
|
sub prettify_lines { |
|
117
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
118
|
0
|
|
|
|
|
|
my $pre = shift; # Previous opening brace or semicolon |
|
119
|
0
|
|
|
|
|
|
my $indent = shift; # Indentation spacing of the print statement |
|
120
|
0
|
|
|
|
|
|
my $contents = shift; # Contents of the single quotes of the print |
|
121
|
0
|
|
|
|
|
|
my $post = shift; # Closing brace or semicolon |
|
122
|
|
|
|
|
|
|
|
|
123
|
0
|
|
|
|
|
|
my $out = $pre; |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# Create a list of lines (and the ending partial line) in the print |
|
126
|
0
|
|
|
|
|
|
my @chunks = split /(.*?\n)/, $contents; |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# print "CHUNK <<$_>>\n" foreach @chunks; |
|
129
|
0
|
|
|
|
|
|
foreach ( 0 .. $#chunks ) { |
|
130
|
0
|
|
|
|
|
|
my $is_last_chunk = ( $_ == $#chunks ); |
|
131
|
0
|
|
|
|
|
|
my $chunk = $chunks[$_]; |
|
132
|
0
|
0
|
0
|
|
|
|
next if ( ( $chunk eq '' ) && ( not $is_last_chunk ) ); |
|
133
|
|
|
|
|
|
|
|
|
134
|
0
|
|
|
|
|
|
my $nl = ''; |
|
135
|
0
|
0
|
|
|
|
|
if ( $chunk =~ s/\r\n$// ) { $nl = '\r\n'; } |
|
|
0
|
0
|
|
|
|
|
|
|
136
|
0
|
|
|
|
|
|
elsif ( $chunk =~ s/\n$// ) { $nl = '\n'; } |
|
137
|
|
|
|
|
|
|
|
|
138
|
0
|
|
|
|
|
|
my $statement; |
|
139
|
0
|
0
|
|
|
|
|
if ($nl) { |
|
140
|
0
|
0
|
|
|
|
|
if ($self->append_pretty) { |
|
141
|
0
|
|
|
|
|
|
$statement = $self->append_pretty . "'$chunk'"; |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
else { |
|
144
|
0
|
|
|
|
|
|
$statement = $self->append . "'$chunk'" . '."$nl"'; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
else { |
|
148
|
0
|
|
|
|
|
|
$statement = $self->append . "'$chunk'"; |
|
149
|
|
|
|
|
|
|
} |
|
150
|
0
|
0
|
|
|
|
|
$statement .= $is_last_chunk ? $post : ";\n"; |
|
151
|
|
|
|
|
|
|
|
|
152
|
0
|
|
|
|
|
|
$out .= $statement; |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
0
|
|
|
|
|
|
return $out; |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
############################################################################## |
|
159
|
|
|
|
|
|
|
# Some override-able functions for subclasses |
|
160
|
|
|
|
|
|
|
|
|
161
|
0
|
|
|
0
|
0
|
|
sub pretty_header { return ''; } |
|
162
|
0
|
|
|
0
|
0
|
|
sub header { die "Subclass must override Templ::Parser->header"; } |
|
163
|
0
|
|
|
0
|
0
|
|
sub append { die "Subclass must override Templ::Parser->append"; } |
|
164
|
0
|
|
|
0
|
0
|
|
sub append_pretty { return ''; } |
|
165
|
0
|
|
|
0
|
0
|
|
sub footer { die "Subclass must override Templ::Parser->footer"; } |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
############################################################################## |
|
168
|
|
|
|
|
|
|
# Utility Functions |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# Returns the first defined value in a list, or a blank string if there are |
|
171
|
|
|
|
|
|
|
# # no defined values |
|
172
|
|
|
|
|
|
|
sub _default (@) { |
|
173
|
0
|
0
|
|
0
|
|
|
foreach (@_) { defined($_) && return $_; } |
|
|
0
|
|
|
|
|
|
|
|
174
|
0
|
|
|
|
|
|
return ''; |
|
175
|
|
|
|
|
|
|
} |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
############################################################################## |
|
178
|
|
|
|
|
|
|
# Accessors... |
|
179
|
|
|
|
|
|
|
sub debug { |
|
180
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
181
|
0
|
0
|
|
|
|
|
if ( defined $_[0] ) { $self->{'debug'} = shift; } |
|
|
0
|
|
|
|
|
|
|
|
182
|
0
|
|
|
|
|
|
return _default $self->{'debug'}, $Templ::Parser::debug, 0; |
|
183
|
|
|
|
|
|
|
} |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub tidy { |
|
186
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
187
|
0
|
0
|
|
|
|
|
if ( defined $_[0] ) { $self->{'tidy'} = shift; } |
|
|
0
|
|
|
|
|
|
|
|
188
|
0
|
|
|
|
|
|
return _default $self->{'tidy'}, $Templ::Parser::tidy, 0; |
|
189
|
|
|
|
|
|
|
} |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
sub tidy_options { |
|
192
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
193
|
0
|
0
|
|
|
|
|
if ( defined $_[0] ) { $self->{'tidy_options'} = shift; } |
|
|
0
|
|
|
|
|
|
|
|
194
|
0
|
|
|
|
|
|
return _default $self->{'tidy_options'}, $Templ::Parser::tidy_options, |
|
195
|
|
|
|
|
|
|
'-pbp -nst -b -aws -dws -dsm -nbbc -kbl=0 -asc -npro -sbl'; |
|
196
|
|
|
|
|
|
|
} |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
sub prettify { |
|
199
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
200
|
0
|
0
|
|
|
|
|
if ( defined $_[0] ) { $self->{'prettify'} = shift; } |
|
|
0
|
|
|
|
|
|
|
|
201
|
0
|
0
|
|
|
|
|
return _default $self->{'prettify'}, $Templ::Parser::prettify, |
|
202
|
|
|
|
|
|
|
( $self->tidy ? 1 : 0 ); |
|
203
|
|
|
|
|
|
|
} |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
1; |