| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package CodeGen::Cpppp::Template; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = '0.005'; # VERSION |
|
4
|
|
|
|
|
|
|
# ABSTRACT: Base class for template classes created by compiling cpppp |
|
5
|
|
|
|
|
|
|
|
|
6
|
17
|
|
|
17
|
|
226
|
use v5.20; |
|
|
17
|
|
|
|
|
99
|
|
|
7
|
17
|
|
|
17
|
|
89
|
use warnings; |
|
|
17
|
|
|
|
|
30
|
|
|
|
17
|
|
|
|
|
925
|
|
|
8
|
17
|
|
|
17
|
|
103
|
use Carp; |
|
|
17
|
|
|
|
|
80
|
|
|
|
17
|
|
|
|
|
1443
|
|
|
9
|
17
|
|
|
17
|
|
101
|
use experimental 'signatures', 'lexical_subs', 'postderef'; |
|
|
17
|
|
|
|
|
51
|
|
|
|
17
|
|
|
|
|
180
|
|
|
10
|
17
|
|
|
17
|
|
3326
|
use Scalar::Util 'looks_like_number'; |
|
|
17
|
|
|
|
|
49
|
|
|
|
17
|
|
|
|
|
1248
|
|
|
11
|
17
|
|
|
17
|
|
11105
|
use Hash::Util; |
|
|
17
|
|
|
|
|
80333
|
|
|
|
17
|
|
|
|
|
124
|
|
|
12
|
17
|
|
|
17
|
|
11747
|
use CodeGen::Cpppp::Output; |
|
|
17
|
|
|
|
|
56
|
|
|
|
17
|
|
|
|
|
838
|
|
|
13
|
17
|
|
|
17
|
|
9647
|
use CodeGen::Cpppp::AntiCharacter; |
|
|
17
|
|
|
|
|
57
|
|
|
|
17
|
|
|
|
|
616
|
|
|
14
|
17
|
|
|
17
|
|
114
|
use Exporter (); |
|
|
17
|
|
|
|
|
34
|
|
|
|
17
|
|
|
|
|
1258
|
|
|
15
|
|
|
|
|
|
|
require version; |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
package CodeGen::Cpppp::Template::Exports { |
|
19
|
|
|
|
|
|
|
use constant { |
|
20
|
17
|
|
|
|
|
5844
|
PUBLIC => 'public', |
|
21
|
|
|
|
|
|
|
PROTECTED => 'protected', |
|
22
|
|
|
|
|
|
|
PRIVATE => 'private', |
|
23
|
17
|
|
|
17
|
|
113
|
}; |
|
|
17
|
|
|
|
|
35
|
|
|
24
|
|
|
|
|
|
|
our @EXPORT_OK= qw( PUBLIC PROTECTED PRIVATE compile_cpppp format_commandline |
|
25
|
|
|
|
|
|
|
format_timestamp |
|
26
|
|
|
|
|
|
|
); |
|
27
|
|
|
|
|
|
|
our %EXPORT_TAGS= ( |
|
28
|
|
|
|
|
|
|
'v0' => [qw( PUBLIC PROTECTED PRIVATE compile_cpppp )], |
|
29
|
|
|
|
|
|
|
); |
|
30
|
|
|
|
|
|
|
#sub util { |
|
31
|
|
|
|
|
|
|
# return bless [ caller ], __PACKAGE__; |
|
32
|
|
|
|
|
|
|
#} |
|
33
|
|
|
|
|
|
|
#sub _caller { ref $_[0] eq __PACKAGE__? @{+shift} : caller(1) } |
|
34
|
|
|
|
|
|
|
sub compile_cpppp { |
|
35
|
1
|
|
|
1
|
|
12
|
my ($pkg, $filename, $line)= caller; |
|
36
|
1
|
|
|
|
|
3
|
my $cpppp; |
|
37
|
1
|
50
|
|
|
|
6
|
if (@_ == 1) { |
|
38
|
|
|
|
|
|
|
# If the argument has any line terminator, assume it is cpppp code |
|
39
|
1
|
50
|
|
|
|
8
|
if (index($_[0], "\n") >= 0) { |
|
|
|
50
|
|
|
|
|
|
|
40
|
0
|
|
|
|
|
0
|
$cpppp= $_[0]; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
# if the argument is '__DATA__', read it from DATA |
|
43
|
|
|
|
|
|
|
elsif ($_[0] eq '__DATA__') { |
|
44
|
17
|
|
|
17
|
|
122
|
no strict 'refs'; |
|
|
17
|
|
|
|
|
35
|
|
|
|
17
|
|
|
|
|
21747
|
|
|
45
|
1
|
|
|
|
|
2
|
my $fh= *{${pkg}.'::DATA'}; |
|
|
1
|
|
|
|
|
7
|
|
|
46
|
1
|
|
|
|
|
94
|
my $pos= $fh->tell; |
|
47
|
1
|
|
|
|
|
13559
|
local $/= undef; |
|
48
|
1
|
|
|
|
|
33
|
$cpppp= <$fh>; |
|
49
|
|
|
|
|
|
|
# now find out what line __DATA__ started on |
|
50
|
1
|
50
|
|
|
|
3
|
eval { |
|
51
|
1
|
|
|
|
|
36
|
$fh->seek(0,0); |
|
52
|
1
|
|
|
|
|
34
|
$/= \$pos; |
|
53
|
1
|
|
|
|
|
29
|
$line= 1 + scalar(()= <$fh> =~ /\n/g); |
|
54
|
|
|
|
|
|
|
} or Carp::carp("Can't determine line number of __DATA__"); |
|
55
|
1
|
|
|
|
|
27
|
close $fh; |
|
56
|
|
|
|
|
|
|
} |
|
57
|
|
|
|
|
|
|
} |
|
58
|
1
|
50
|
|
|
|
7
|
Carp::croak("compile_cppp argument should either be '__DATA__' or lines of cpppp code ending with '\\n'") |
|
59
|
|
|
|
|
|
|
unless defined $cpppp; |
|
60
|
1
|
50
|
|
|
|
5
|
Carp::croak("cpppp source cannot be empty") |
|
61
|
|
|
|
|
|
|
unless length $cpppp; |
|
62
|
|
|
|
|
|
|
|
|
63
|
1
|
|
|
|
|
14
|
my $parse= CodeGen::Cpppp->new->parse_cpppp(\$cpppp, $filename, $line); |
|
64
|
1
|
|
|
|
|
21
|
$pkg->_init_parse_data($parse); |
|
65
|
|
|
|
|
|
|
$pkg->_build_BUILD_method( |
|
66
|
1
|
|
|
|
|
7
|
$pkg->cpppp_version, $parse->{code}, $filename, $line); |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
sub format_commandline { |
|
69
|
2
|
|
|
2
|
|
1348
|
require CodeGen::Cpppp::Platform; |
|
70
|
2
|
|
|
|
|
12
|
CodeGen::Cpppp::Platform::format_commandline(@_); |
|
71
|
|
|
|
|
|
|
} |
|
72
|
|
|
|
|
|
|
sub format_timestamp { |
|
73
|
0
|
|
|
0
|
|
0
|
my @t= gmtime; |
|
74
|
0
|
|
|
|
|
0
|
sprintf "%04d-%02d-%02dT%02d:%02d:%02dZ", $t[5]+1900, @t[4,3,2,1,0] |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
|
|
78
|
25
|
|
|
25
|
|
68
|
sub _tag_for_version($ver) { |
|
|
25
|
|
|
|
|
62
|
|
|
|
25
|
|
|
|
|
44
|
|
|
79
|
25
|
|
|
|
|
136
|
return ':v0'; |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub import { |
|
83
|
45
|
|
|
45
|
|
184100
|
my $class= $_[0]; |
|
84
|
45
|
|
|
|
|
129
|
my $caller= caller; |
|
85
|
45
|
|
|
|
|
240
|
for (my $i= 1; $i < @_; $i++) { |
|
86
|
28
|
100
|
|
|
|
132
|
if ($_[$i] eq '-setup') { |
|
87
|
25
|
|
|
|
|
303
|
my $ver= version->parse($_[$i+1]); |
|
88
|
25
|
|
|
|
|
105
|
splice(@_, $i, 2, _tag_for_version($ver)); |
|
89
|
25
|
|
|
|
|
115
|
$class->_setup_derived_package($caller, $ver); |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
} |
|
92
|
45
|
|
|
|
|
211
|
splice(@_, 0, 1, 'CodeGen::Cpppp::Template::Exports'); |
|
93
|
45
|
|
|
|
|
20735
|
goto \&Exporter::import; |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
our $_next_pkg= 1; |
|
97
|
24
|
|
|
24
|
|
54
|
sub _create_derived_package($class, $cpppp_ver, $parse_data) { |
|
|
24
|
|
|
|
|
67
|
|
|
|
24
|
|
|
|
|
40
|
|
|
|
24
|
|
|
|
|
41
|
|
|
|
24
|
|
|
|
|
70
|
|
|
98
|
24
|
|
|
|
|
73
|
my $pkg= 'CodeGen::Cpppp::Template::_'.$_next_pkg++; |
|
99
|
17
|
|
|
17
|
|
143
|
no strict 'refs'; |
|
|
17
|
|
|
|
|
31
|
|
|
|
17
|
|
|
|
|
3982
|
|
|
100
|
24
|
|
|
|
|
69
|
@{"${pkg}::ISA"}= ( $class ); |
|
|
24
|
|
|
|
|
627
|
|
|
101
|
24
|
|
|
|
|
72
|
${"${pkg}::cpppp_version"}= $cpppp_ver; |
|
|
24
|
|
|
|
|
140
|
|
|
102
|
24
|
|
|
|
|
215
|
$pkg->_init_parse_data($parse_data); |
|
103
|
|
|
|
|
|
|
} |
|
104
|
|
|
|
|
|
|
|
|
105
|
25
|
|
|
25
|
|
43
|
sub _setup_derived_package($class, $pkg, $cpppp_ver) { |
|
|
25
|
|
|
|
|
45
|
|
|
|
25
|
|
|
|
|
40
|
|
|
|
25
|
|
|
|
|
41
|
|
|
|
25
|
|
|
|
|
89
|
|
|
106
|
25
|
|
|
|
|
277
|
strict->import; |
|
107
|
25
|
|
|
|
|
1022
|
warnings->import; |
|
108
|
25
|
|
|
|
|
294
|
utf8->import; |
|
109
|
25
|
|
|
|
|
281
|
experimental->import(qw( lexical_subs signatures postderef )); |
|
110
|
|
|
|
|
|
|
|
|
111
|
17
|
|
|
17
|
|
138
|
no strict 'refs'; |
|
|
17
|
|
|
|
|
33
|
|
|
|
17
|
|
|
|
|
3546
|
|
|
112
|
25
|
100
|
|
|
|
3885
|
@{"${pkg}::ISA"}= ( $class ) unless @{"${pkg}::ISA"}; |
|
|
1
|
|
|
|
|
21
|
|
|
|
25
|
|
|
|
|
195
|
|
|
113
|
25
|
|
|
|
|
47
|
${"${pkg}::cpppp_version"}= $cpppp_ver; |
|
|
25
|
|
|
|
|
164
|
|
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
25
|
|
|
25
|
|
54
|
sub _init_parse_data($class, $parse_data) { |
|
|
25
|
|
|
|
|
51
|
|
|
|
25
|
|
|
|
|
36
|
|
|
|
25
|
|
|
|
|
33
|
|
|
117
|
17
|
|
|
17
|
|
124
|
no strict 'refs'; |
|
|
17
|
|
|
|
|
35
|
|
|
|
17
|
|
|
|
|
8209
|
|
|
118
|
25
|
|
|
|
|
60
|
${"${class}::_parse_data"}= $parse_data; |
|
|
25
|
|
|
|
|
232
|
|
|
119
|
|
|
|
|
|
|
# Create accessors for all of the attributes declared in the template. |
|
120
|
25
|
|
|
|
|
105
|
for (keys $parse_data->{template_parameter}->%*) { |
|
121
|
15
|
|
|
|
|
27
|
my $name= $_; |
|
122
|
15
|
|
|
8
|
|
49
|
*{"${class}::$name"}= sub { $_[0]{$name} }; |
|
|
15
|
|
|
|
|
60
|
|
|
|
8
|
|
|
|
|
40
|
|
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
# Expose all of the functions declared in the template |
|
125
|
25
|
|
|
|
|
99
|
for (keys $parse_data->{template_method}->%*) { |
|
126
|
5
|
|
|
|
|
12
|
my $name= $_; |
|
127
|
5
|
|
|
|
|
75
|
*{"${class}::$name"}= sub { |
|
128
|
4
|
50
|
|
4
|
|
2716
|
my $m= shift->{template_method}{$name} |
|
129
|
|
|
|
|
|
|
or croak "Template execution did not define method '$name'"; |
|
130
|
4
|
|
|
|
|
15
|
goto $m; |
|
131
|
5
|
|
|
|
|
28
|
}; |
|
132
|
|
|
|
|
|
|
} |
|
133
|
25
|
|
|
|
|
116
|
$class; |
|
134
|
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
|
|
136
|
1
|
|
|
1
|
0
|
2
|
sub cpppp_version($class) { |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
2
|
|
|
137
|
17
|
|
|
17
|
|
176
|
no strict 'refs'; |
|
|
17
|
|
|
|
|
32
|
|
|
|
17
|
|
|
|
|
5991
|
|
|
138
|
1
|
|
33
|
|
|
28
|
${"${class}::cpppp_version"} // __PACKAGE__->VERSION |
|
|
1
|
|
|
|
|
21
|
|
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
|
|
141
|
25
|
|
|
25
|
|
47
|
sub _gen_perl_scope_functions($class, $cpppp_ver) { |
|
|
25
|
|
|
|
|
39
|
|
|
|
25
|
|
|
|
|
49
|
|
|
|
25
|
|
|
|
|
40
|
|
|
142
|
|
|
|
|
|
|
return ( |
|
143
|
25
|
|
|
|
|
1521
|
'# line '. (__LINE__+1) . ' "' . __FILE__ . '"', |
|
144
|
0
|
|
|
0
|
|
|
'my sub param { unshift @_, $self; goto $self->can("_init_param") }', |
|
|
0
|
|
|
|
|
|
|
|
145
|
0
|
|
|
0
|
|
|
'my sub define { unshift @_, $self; goto $self->can("define_template_macro") }', |
|
|
0
|
|
|
|
|
|
|
|
146
|
0
|
|
|
0
|
|
|
'my sub section { unshift @_, $self; goto $self->can("current_output_section") }', |
|
|
0
|
|
|
|
|
|
|
|
147
|
0
|
|
|
0
|
|
|
'my sub template { unshift @_, $self->context; goto $self->context->can("new_template") }', |
|
|
0
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
'my $trim_comma= CodeGen::Cpppp::AntiCharacter->new(qr/,/, qr/\s*/);', |
|
149
|
|
|
|
|
|
|
'my $trim_ws= CodeGen::Cpppp::AntiCharacter->new(qr/\s*/);', |
|
150
|
|
|
|
|
|
|
); |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
25
|
|
|
25
|
|
42
|
sub _gen_BUILD_method($class, $cpppp_ver, $perl, $src_filename, $src_lineno) { |
|
|
25
|
|
|
|
|
74
|
|
|
|
25
|
|
|
|
|
40
|
|
|
|
25
|
|
|
|
|
41
|
|
|
|
25
|
|
|
|
|
53
|
|
|
|
25
|
|
|
|
|
40
|
|
|
|
25
|
|
|
|
|
68
|
|
|
154
|
|
|
|
|
|
|
return |
|
155
|
25
|
|
|
|
|
202
|
"sub ${class}::BUILD(\$self, \$constructor_parameters=undef) {", |
|
156
|
|
|
|
|
|
|
" Scalar::Util::weaken(\$self);", |
|
157
|
|
|
|
|
|
|
# Inject all the lexical functions that need to be in scope |
|
158
|
|
|
|
|
|
|
$class->_gen_perl_scope_functions($cpppp_ver), |
|
159
|
|
|
|
|
|
|
qq{# line $src_lineno "$src_filename"}, |
|
160
|
|
|
|
|
|
|
$perl, |
|
161
|
|
|
|
|
|
|
"}", |
|
162
|
|
|
|
|
|
|
} |
|
163
|
|
|
|
|
|
|
|
|
164
|
1
|
|
|
1
|
|
2
|
sub _build_BUILD_method($class, $version, $perl, $src_filename, $src_lineno) { |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
3
|
|
|
165
|
|
|
|
|
|
|
{ |
|
166
|
17
|
|
|
17
|
|
124
|
no strict 'refs'; |
|
|
17
|
|
|
|
|
39
|
|
|
|
17
|
|
|
|
|
15160
|
|
|
|
1
|
|
|
|
|
1
|
|
|
167
|
1
|
50
|
|
|
|
3
|
croak "${class}::BUILD is already defined" if defined &{$class.'::BUILD'}; |
|
|
1
|
|
|
|
|
8
|
|
|
168
|
|
|
|
|
|
|
} |
|
169
|
1
|
50
|
|
|
|
7
|
croak "Compile failed for ${class}::BUILD() : $@" |
|
170
|
|
|
|
|
|
|
unless eval join "\n", |
|
171
|
|
|
|
|
|
|
$class->_gen_BUILD_method($version, $perl, $src_lineno, $src_filename), |
|
172
|
|
|
|
|
|
|
'1'; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
|
|
176
|
6
|
|
|
6
|
1
|
37
|
sub context { $_[0]{context} } |
|
177
|
|
|
|
|
|
|
|
|
178
|
36
|
|
|
36
|
1
|
5402
|
sub output { $_[0]->flush->{output} } |
|
179
|
|
|
|
|
|
|
|
|
180
|
13
|
|
|
13
|
1
|
31
|
sub current_output_section($self, $new=undef) { |
|
|
13
|
|
|
|
|
16
|
|
|
|
13
|
|
|
|
|
18
|
|
|
|
13
|
|
|
|
|
13
|
|
|
181
|
13
|
50
|
|
|
|
26
|
if (defined $new) { |
|
182
|
13
|
50
|
|
|
|
23
|
$self->output->has_section($new) |
|
183
|
|
|
|
|
|
|
or croak "No defined output section '$new'"; |
|
184
|
13
|
|
|
|
|
37
|
$self->_finish_render; |
|
185
|
13
|
|
|
|
|
22
|
$self->{current_output_section}= $new; |
|
186
|
|
|
|
|
|
|
} |
|
187
|
13
|
|
|
|
|
30
|
$self->{current_output_section}; |
|
188
|
|
|
|
|
|
|
} |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
|
|
191
|
0
|
0
|
0
|
0
|
1
|
0
|
sub autocolumn { $_[0]{autocolumn} = $_[1]||0 if @_ > 1; $_[0]{autocolumn} } |
|
|
0
|
|
|
|
|
0
|
|
|
192
|
0
|
0
|
0
|
0
|
1
|
0
|
sub autocomma { $_[0]{autocomma} = $_[1]||0 if @_ > 1; $_[0]{autocomma} } |
|
|
0
|
|
|
|
|
0
|
|
|
193
|
0
|
0
|
0
|
0
|
1
|
0
|
sub autoindent { $_[0]{autoindent} = $_[1]||0 if @_ > 1; $_[0]{autoindent} } |
|
|
0
|
|
|
|
|
0
|
|
|
194
|
0
|
0
|
0
|
0
|
1
|
0
|
sub autostatementline { $_[0]{autostatementline}= $_[1]||0 if @_ > 1; $_[0]{autostatementline} } |
|
|
0
|
|
|
|
|
0
|
|
|
195
|
219
|
50
|
|
219
|
1
|
380
|
sub indent { $_[0]{indent} = $_[1] if @_ > 1; $_[0]{indent} } |
|
|
219
|
|
|
|
|
362
|
|
|
196
|
0
|
0
|
0
|
0
|
1
|
0
|
sub emit_POD { $_[0]{emit_POD} = $_[1]||0 if @_ > 1; $_[0]{emit_POD} } |
|
|
0
|
|
|
|
|
0
|
|
|
197
|
|
|
|
|
|
|
|
|
198
|
92
|
|
|
92
|
|
118
|
sub _parse_data($class) { |
|
|
92
|
|
|
|
|
123
|
|
|
|
92
|
|
|
|
|
127
|
|
|
199
|
92
|
100
|
|
|
|
262
|
$class = ref $class if ref $class; |
|
200
|
17
|
|
|
17
|
|
141
|
no strict 'refs'; |
|
|
17
|
|
|
|
|
31
|
|
|
|
17
|
|
|
|
|
3805
|
|
|
201
|
92
|
|
|
|
|
115
|
return ${"${class}::_parse_data"}; |
|
|
92
|
|
|
|
|
402
|
|
|
202
|
|
|
|
|
|
|
} |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
|
|
205
|
34
|
|
|
34
|
0
|
2969
|
sub new($class, @args) { |
|
|
34
|
|
|
|
|
66
|
|
|
|
34
|
|
|
|
|
57
|
|
|
|
34
|
|
|
|
|
49
|
|
|
206
|
17
|
|
|
17
|
|
120
|
no strict 'refs'; |
|
|
17
|
|
|
|
|
32
|
|
|
|
17
|
|
|
|
|
68487
|
|
|
207
|
34
|
50
|
66
|
|
|
243
|
my %attrs= @args == 1 && ref $args[0]? $args[0]->%* |
|
|
|
100
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
: !(@args&1)? @args |
|
209
|
|
|
|
|
|
|
: croak "Expected even-length list or hashref"; |
|
210
|
34
|
|
|
|
|
116
|
my $parse= $class->_parse_data; |
|
211
|
|
|
|
|
|
|
# Make sure each attr is the correct type of ref, for the params. |
|
212
|
34
|
|
|
|
|
102
|
for (keys %attrs) { |
|
213
|
34
|
100
|
|
|
|
130
|
if (my $p= $parse->{template_parameter}{$_}) { |
|
214
|
10
|
100
|
|
|
|
47
|
if ($p eq '@') { ref $attrs{$_} eq 'ARRAY' or croak("Expected ARRAY for parameter $_"); } |
|
|
2
|
100
|
|
|
|
189
|
|
|
|
|
100
|
|
|
|
|
|
|
215
|
3
|
100
|
|
|
|
205
|
elsif ($p eq '%') { ref $attrs{$_} eq 'HASH' or croak("Expected HASH for parameter $_"); } |
|
216
|
|
|
|
|
|
|
} |
|
217
|
|
|
|
|
|
|
else { |
|
218
|
24
|
50
|
|
|
|
168
|
croak("Unknown parameter '$_' to template $parse->{filename}") |
|
219
|
|
|
|
|
|
|
unless $class->can($_); |
|
220
|
|
|
|
|
|
|
} |
|
221
|
|
|
|
|
|
|
} |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
my $self= bless { |
|
224
|
|
|
|
|
|
|
autocomma => 1, |
|
225
|
|
|
|
|
|
|
autostatementline => 1, |
|
226
|
|
|
|
|
|
|
(map +($_ => $parse->{$_}||0), qw( |
|
227
|
|
|
|
|
|
|
autoindent autocolumn convert_linecomment_to_c89 |
|
228
|
|
|
|
|
|
|
)), |
|
229
|
|
|
|
|
|
|
indent => $parse->{indent}, |
|
230
|
32
|
|
100
|
|
|
480
|
output => CodeGen::Cpppp::Output->new, |
|
231
|
|
|
|
|
|
|
current_output_section => 'private', |
|
232
|
|
|
|
|
|
|
%attrs, |
|
233
|
|
|
|
|
|
|
}, $class; |
|
234
|
|
|
|
|
|
|
Scalar::Util::weaken($self->{context}) |
|
235
|
32
|
100
|
|
|
|
235
|
if $self->{context}; |
|
236
|
32
|
|
|
|
|
473
|
$self->BUILD(\%attrs); |
|
237
|
31
|
|
|
|
|
313
|
$self->flush; |
|
238
|
|
|
|
|
|
|
} |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
|
|
241
|
8
|
|
|
8
|
1
|
19
|
sub coerce_parameters($class, $params) { |
|
|
8
|
|
|
|
|
20
|
|
|
|
8
|
|
|
|
|
15
|
|
|
|
8
|
|
|
|
|
14
|
|
|
242
|
8
|
|
|
|
|
37
|
my %ret; |
|
243
|
8
|
|
|
|
|
46
|
my $parse= $class->_parse_data; |
|
244
|
8
|
|
|
|
|
38
|
for my $k (keys $parse->{template_parameter}->%*) { |
|
245
|
0
|
|
|
|
|
0
|
my $p= $parse->{template_parameter}{$k}; |
|
246
|
0
|
|
0
|
|
|
0
|
my $v= $params->{$p.$k} // $params->{$k}; |
|
247
|
0
|
0
|
|
|
|
0
|
next unless defined $v; |
|
248
|
0
|
0
|
|
|
|
0
|
if ($p eq '@') { |
|
|
|
0
|
|
|
|
|
|
|
249
|
0
|
0
|
|
|
|
0
|
$v= ref $v eq 'HASH'? [ keys %$v ] : [ $v ] |
|
|
|
0
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
unless ref $v eq 'ARRAY'; |
|
251
|
|
|
|
|
|
|
} elsif ($p eq '%') { |
|
252
|
|
|
|
|
|
|
# If it isn't a hash, treat it like a list that needs added to a set |
|
253
|
0
|
0
|
|
|
|
0
|
$v= { map +($_ => 1), ref $v eq 'ARRAY'? @$v : ($v) } |
|
|
|
0
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
unless ref $v eq 'HASH'; |
|
255
|
|
|
|
|
|
|
} |
|
256
|
0
|
|
|
|
|
0
|
$ret{$k}= $v; |
|
257
|
|
|
|
|
|
|
} |
|
258
|
8
|
|
|
|
|
25
|
\%ret; |
|
259
|
|
|
|
|
|
|
} |
|
260
|
|
|
|
|
|
|
|
|
261
|
30
|
|
|
30
|
|
54
|
sub _init_param($self, $name, $ref, @initial_value) { |
|
|
30
|
|
|
|
|
35
|
|
|
|
30
|
|
|
|
|
34
|
|
|
|
30
|
|
|
|
|
35
|
|
|
|
30
|
|
|
|
|
36
|
|
|
|
30
|
|
|
|
|
28
|
|
|
262
|
30
|
100
|
|
|
|
59
|
if (exists $self->{$name}) { |
|
263
|
|
|
|
|
|
|
# Assign the value received from constructor to the variable in the template |
|
264
|
|
|
|
|
|
|
ref $ref eq 'SCALAR'? ($$ref= $self->{$name}) |
|
265
|
1
|
50
|
|
|
|
6
|
: ref $ref eq 'ARRAY' ? (@$ref= @{$self->{$name} || []}) |
|
266
|
8
|
50
|
|
|
|
34
|
: ref $ref eq 'HASH' ? (%$ref= %{$self->{$name} || {}}) |
|
|
2
|
50
|
|
|
|
16
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
: croak "Unhandled ref type ".ref($ref); |
|
268
|
|
|
|
|
|
|
} else { |
|
269
|
22
|
50
|
|
|
|
71
|
ref $ref eq 'SCALAR'? ($$ref= $initial_value[0]) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
: ref $ref eq 'ARRAY' ? (@$ref= @initial_value) |
|
271
|
|
|
|
|
|
|
: ref $ref eq 'HASH' ? (%$ref= @initial_value) |
|
272
|
|
|
|
|
|
|
: croak "Unhandled ref type ".ref($ref); |
|
273
|
|
|
|
|
|
|
} |
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
# Now store the variable of the template directly into this hash |
|
276
|
|
|
|
|
|
|
ref $ref eq 'SCALAR'? Hash::Util::hv_store(%$self, $name, $$ref) |
|
277
|
30
|
100
|
|
|
|
113
|
: ($self->{$name}= $ref); |
|
278
|
30
|
|
|
|
|
65
|
$ref; |
|
279
|
|
|
|
|
|
|
} |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
|
|
282
|
70
|
|
|
70
|
1
|
97
|
sub flush($self) { |
|
|
70
|
|
|
|
|
105
|
|
|
|
70
|
|
|
|
|
81
|
|
|
283
|
70
|
|
|
|
|
229
|
$self->_finish_render; |
|
284
|
70
|
|
|
|
|
312
|
$self; |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
|
|
288
|
0
|
|
|
0
|
1
|
0
|
sub define_template_macro($self, $name, $code) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
289
|
0
|
|
|
|
|
0
|
$self->{template_macro}{$name}= $code; |
|
290
|
|
|
|
|
|
|
} |
|
291
|
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
|
|
293
|
5
|
|
|
5
|
1
|
59
|
sub define_template_method($self, $name, $code) { |
|
|
5
|
|
|
|
|
9
|
|
|
|
5
|
|
|
|
|
11
|
|
|
|
5
|
|
|
|
|
8
|
|
|
|
5
|
|
|
|
|
8
|
|
|
294
|
5
|
|
|
|
|
61
|
$self->{template_method}{$name}= $code; |
|
295
|
|
|
|
|
|
|
} |
|
296
|
|
|
|
|
|
|
|
|
297
|
0
|
|
|
0
|
|
0
|
sub _render_pod_block($self, $i) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
298
|
0
|
0
|
|
|
|
0
|
if ($self->emit_POD) { |
|
299
|
0
|
|
|
|
|
0
|
$self->_finish_render; |
|
300
|
0
|
|
|
|
|
0
|
$self->{output}->append($self->{current_output_section} => $self->_parse_data->{pod_blocks}[$i]); |
|
301
|
|
|
|
|
|
|
} |
|
302
|
|
|
|
|
|
|
} |
|
303
|
|
|
|
|
|
|
|
|
304
|
83
|
|
|
83
|
|
102
|
sub _finish_render($self) { |
|
|
83
|
|
|
|
|
112
|
|
|
|
83
|
|
|
|
|
87
|
|
|
305
|
83
|
100
|
|
|
|
187
|
return unless defined $self->{current_out}; |
|
306
|
|
|
|
|
|
|
# Second pass, adjust whitespace of all column markers so they line up. |
|
307
|
|
|
|
|
|
|
# Iterate from leftmost column rightward. |
|
308
|
65
|
|
|
|
|
83
|
for my $group_i (sort { $a <=> $b } keys %{$self->{current_out_colgroup_state}}) { |
|
|
1
|
|
|
|
|
4
|
|
|
|
65
|
|
|
|
|
246
|
|
|
309
|
|
|
|
|
|
|
delete $self->{current_out_colgroup_state}{$group_i} |
|
310
|
4
|
50
|
|
|
|
14
|
if $self->{current_out_colgroup_state}{$group_i} == 2; |
|
311
|
4
|
|
|
|
|
8
|
my $token= _colmarker($group_i); |
|
312
|
|
|
|
|
|
|
# Find the longest prefix (excluding trailing whitespace) |
|
313
|
|
|
|
|
|
|
# Also find the max number of digits following column. |
|
314
|
4
|
|
|
|
|
12
|
my ($maxcol, $maxdigit)= (0,0); |
|
315
|
4
|
|
|
|
|
5
|
my ($linestart, $col); |
|
316
|
4
|
|
|
|
|
257
|
while ($self->{current_out} =~ /[ ]* $token (-? 0x[A-Fa-f0-9]+ | -? \d+)? /gx) { |
|
317
|
20
|
|
|
|
|
72
|
$linestart= rindex($self->{current_out}, "\n", $-[0])+1; |
|
318
|
20
|
|
|
|
|
38
|
$col= $-[0] - $linestart; |
|
319
|
20
|
100
|
|
|
|
39
|
$maxcol= $col if $col > $maxcol; |
|
320
|
20
|
100
|
100
|
|
|
146
|
$maxdigit= length $1 if defined $1 && length $1 > $maxdigit; |
|
321
|
|
|
|
|
|
|
} |
|
322
|
4
|
|
|
|
|
150
|
$self->{current_out} =~ s/[ ]* $token (?= (-? 0x[A-Fa-f0-9]+ | -? \d+)? )/ |
|
323
|
20
|
|
|
|
|
60
|
$linestart= rindex($self->{current_out}, "\n", $-[0])+1; |
|
324
|
20
|
100
|
|
|
|
133
|
" "x(1 + $maxcol - ($-[0] - $linestart) + ($1? $maxdigit - length($1) : 0)) |
|
325
|
|
|
|
|
|
|
/gex; |
|
326
|
|
|
|
|
|
|
} |
|
327
|
65
|
|
|
|
|
242
|
$self->{output}->append($self->{current_output_section} => $self->{current_out}); |
|
328
|
65
|
|
|
|
|
143
|
$self->{current_out}= ''; |
|
329
|
|
|
|
|
|
|
} |
|
330
|
|
|
|
|
|
|
|
|
331
|
13
|
|
|
13
|
|
15
|
sub _colmarker($colgroup_id) { join '', "\x{200A}", map chr(0x2000+$_), split //, $colgroup_id; } |
|
|
13
|
|
|
|
|
20
|
|
|
|
13
|
|
|
|
|
13
|
|
|
|
13
|
|
|
|
|
117
|
|
|
332
|
0
|
0
|
0
|
0
|
|
0
|
sub _str_esc { join '', map +(ord($_) > 0x7e || ord($_) < 0x21? sprintf("\\x{%X}",ord) : $_), split //, $_[0] } |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
sub _render_code_block { |
|
335
|
50
|
|
|
50
|
|
374
|
my ($self, $i, @expr_subs)= @_; |
|
336
|
50
|
|
|
|
|
100
|
my $block= $self->_parse_data->{code_block_templates}[$i]; |
|
337
|
50
|
|
|
|
|
91
|
my $text= $block->{text}; |
|
338
|
|
|
|
|
|
|
# Continue appending to the same output buffer so that autocolumn can |
|
339
|
|
|
|
|
|
|
# inspect the result as a whole. |
|
340
|
50
|
|
100
|
|
|
171
|
my $out= \($self->{current_out} //= ''); |
|
341
|
50
|
|
|
|
|
85
|
my $at= 0; |
|
342
|
50
|
|
|
|
|
81
|
my %colmarker; |
|
343
|
|
|
|
|
|
|
# @subst contains a list of positions in the template body where text |
|
344
|
|
|
|
|
|
|
# may need inserted. |
|
345
|
50
|
|
|
|
|
60
|
for my $s (@{$block->{subst}}) { |
|
|
50
|
|
|
|
|
137
|
|
|
346
|
153
|
|
|
|
|
337
|
$$out .= substr($text, $at, $s->{pos} - $at); |
|
347
|
153
|
|
|
|
|
210
|
$at= $s->{pos} + $s->{len}; |
|
348
|
|
|
|
|
|
|
# Column marker - may substitute for whitespace during _finish_render |
|
349
|
153
|
100
|
|
|
|
314
|
if ($s->{colgroup}) { |
|
|
|
50
|
|
|
|
|
|
|
350
|
20
|
|
66
|
|
|
51
|
my $mark= $colmarker{$s->{colgroup}} //= _colmarker($s->{colgroup}); |
|
351
|
20
|
|
|
|
|
32
|
$$out .= $mark; |
|
352
|
20
|
100
|
|
|
|
40
|
$self->{current_out_colgroup_state}{$s->{colgroup}}= $s->{last}? 2 : 1; |
|
353
|
|
|
|
|
|
|
} |
|
354
|
|
|
|
|
|
|
# Variable interpolation - insert value of one of the @expr_subs here |
|
355
|
|
|
|
|
|
|
elsif (defined $s->{eval_idx}) { |
|
356
|
133
|
50
|
|
|
|
223
|
my $fn= $expr_subs[$s->{eval_idx}] |
|
357
|
|
|
|
|
|
|
or die; |
|
358
|
|
|
|
|
|
|
# Identify the indent settings at this point so that other modules can |
|
359
|
|
|
|
|
|
|
# automatically generate matching code. |
|
360
|
133
|
|
|
|
|
2601
|
my ($last_char)= ($$out =~ /(\S) (\s*) \Z/x); |
|
361
|
133
|
|
|
|
|
300
|
my $cur_line= substr($$out, rindex($$out, "\n")+1); |
|
362
|
133
|
|
|
|
|
769
|
(my $indent_prefix= $cur_line) =~ s/\S/ /g; |
|
363
|
133
|
|
|
|
|
180
|
local $CodeGen::Cpppp::CURRENT_INDENT_PREFIX= $indent_prefix; |
|
364
|
133
|
100
|
|
|
|
265
|
local $CodeGen::Cpppp::INDENT= $self->indent if defined $self->indent; |
|
365
|
|
|
|
|
|
|
# it is "inline" context if non-whitespace occurs on this line already |
|
366
|
133
|
|
|
|
|
231
|
my $is_inline= !!($cur_line =~ /\S/); |
|
367
|
133
|
|
|
|
|
157
|
local $CodeGen::Cpppp::CURRENT_IS_INLINE= $is_inline; |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# Avoid using $_ up to this point so that $_ pases through |
|
370
|
|
|
|
|
|
|
# from the surrounding code into the evals |
|
371
|
133
|
|
|
|
|
213
|
my @out= $fn->($self, $out); |
|
372
|
|
|
|
|
|
|
# Expand arrayref and coderefs in the returned list |
|
373
|
133
|
50
|
66
|
|
|
456
|
@out= @{$out[0]} if @out == 1 && ref $out[0] eq 'ARRAY'; |
|
|
0
|
|
|
|
|
0
|
|
|
374
|
133
|
|
33
|
|
|
289
|
ref eq 'CODE' && ($_= $_->($self, $out)) for @out; |
|
375
|
133
|
|
|
|
|
268
|
@out= grep defined, @out; |
|
376
|
|
|
|
|
|
|
# Now decide how to join this into the code template. |
|
377
|
|
|
|
|
|
|
# If this interpolation does not occur at the beginning of the line, |
|
378
|
133
|
|
|
|
|
156
|
my $join_sep= $"; |
|
379
|
|
|
|
|
|
|
# Special handling if the user requested a list substitution |
|
380
|
133
|
100
|
|
|
|
262
|
if (ord $s->{eval} == ord '@') { |
|
381
|
11
|
50
|
|
|
|
24
|
$last_char= '' unless defined $last_char; |
|
382
|
11
|
100
|
100
|
|
|
107
|
if ($self->{autostatementline} && ($last_char eq '{' || $last_char eq ';') |
|
|
|
50
|
66
|
|
|
|
|
|
|
|
0
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
383
|
|
|
|
|
|
|
&& substr($text, $s->{pos}+$s->{len}, 1) eq ';' |
|
384
|
|
|
|
|
|
|
) { |
|
385
|
3
|
|
|
|
|
16
|
@out= grep /\S/, @out; # remove items that are only whitespace |
|
386
|
3
|
50
|
33
|
|
|
13
|
if (!$is_inline && substr($text, $s->{pos}+$s->{len}, 2) eq ";\n") { |
|
387
|
3
|
|
|
|
|
6
|
$join_sep= ";\n"; |
|
388
|
|
|
|
|
|
|
# If no elements, remove the whole line. |
|
389
|
3
|
100
|
|
|
|
6
|
if (!@out) { |
|
390
|
2
|
|
|
|
|
23
|
$$out =~ s/[ \t]+\Z//; |
|
391
|
2
|
|
|
|
|
3
|
$at+= 2; # skip over ";\n" |
|
392
|
|
|
|
|
|
|
} |
|
393
|
|
|
|
|
|
|
} else { |
|
394
|
0
|
|
|
|
|
0
|
$join_sep= "; "; |
|
395
|
|
|
|
|
|
|
} |
|
396
|
|
|
|
|
|
|
} |
|
397
|
|
|
|
|
|
|
elsif ($self->{autocomma} && ($last_char eq ',' || $last_char eq '(' || $last_char eq '{')) { |
|
398
|
8
|
|
|
|
|
32
|
@out= grep /\S/, @out; # remove items that are only whitespace |
|
399
|
8
|
100
|
|
|
|
17
|
$join_sep= $is_inline? ', ' : ",\n"; |
|
400
|
|
|
|
|
|
|
# If no items, or the first nonwhitespace character is a comma, |
|
401
|
|
|
|
|
|
|
# remove the previous comma |
|
402
|
8
|
100
|
66
|
|
|
33
|
if (!@out || $out[0] =~ /^\s*,/) { |
|
403
|
2
|
|
|
|
|
9
|
$$out =~ s/,(\s*)\Z/$1/; |
|
404
|
|
|
|
|
|
|
} |
|
405
|
|
|
|
|
|
|
} |
|
406
|
|
|
|
|
|
|
elsif ($self->{autoindent} && !$is_inline && $join_sep !~ /\n/) { |
|
407
|
0
|
|
|
|
|
0
|
$join_sep .= "\n"; |
|
408
|
|
|
|
|
|
|
} |
|
409
|
|
|
|
|
|
|
} |
|
410
|
133
|
100
|
|
|
|
220
|
if (@out) { |
|
411
|
|
|
|
|
|
|
# 'join' doesn't respect concat magic on AntiCharacter :-( |
|
412
|
128
|
|
|
|
|
168
|
my $str= shift @out; |
|
413
|
128
|
|
|
|
|
178
|
$str .= $join_sep . $_ for @out; |
|
414
|
|
|
|
|
|
|
# Autoindent: if new text contains newline, add current indent to start of each line. |
|
415
|
128
|
100
|
66
|
|
|
315
|
if ($self->{autoindent} && length $indent_prefix) { |
|
416
|
120
|
|
|
|
|
204
|
$str =~ s/\n/\n$indent_prefix/g; |
|
417
|
|
|
|
|
|
|
} |
|
418
|
128
|
|
|
|
|
381
|
$$out .= $str; |
|
419
|
|
|
|
|
|
|
} |
|
420
|
|
|
|
|
|
|
} |
|
421
|
|
|
|
|
|
|
} |
|
422
|
50
|
|
|
|
|
366
|
$$out .= substr($text, $at); |
|
423
|
|
|
|
|
|
|
} |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
1; |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
__END__ |