line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Text::MicroMason::Base; |
2
|
|
|
|
|
|
|
|
3
|
39
|
|
|
39
|
|
276
|
use strict; |
|
39
|
|
|
|
|
79
|
|
|
39
|
|
|
|
|
1663
|
|
4
|
|
|
|
|
|
|
require Carp; |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
###################################################################### |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
###################################################################### |
9
|
|
|
|
|
|
|
|
10
|
39
|
|
|
39
|
|
16515
|
use Class::MixinFactory -hasafactory; |
|
39
|
|
|
|
|
130715
|
|
|
39
|
|
|
|
|
241
|
|
11
|
|
|
|
|
|
|
for my $factory ( (__PACKAGE__)->mixin_factory ) { |
12
|
|
|
|
|
|
|
$factory->base_class( "Text::MicroMason::Base" ); |
13
|
|
|
|
|
|
|
$factory->mixin_prefix( "Text::MicroMason" ); |
14
|
|
|
|
|
|
|
} |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
###################################################################### |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
###################################################################### |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub new { |
21
|
163
|
|
|
163
|
1
|
8123
|
my $callee = shift; |
22
|
163
|
|
|
|
|
271
|
my ( @traits, @attribs ); |
23
|
163
|
|
|
|
|
461
|
while ( scalar @_ ) { |
24
|
302
|
100
|
|
|
|
1635
|
if ( $_[0] =~ /^\-(\w+)$/ ) { |
25
|
264
|
|
|
|
|
711
|
push @traits, $1; |
26
|
264
|
|
|
|
|
563
|
shift; |
27
|
|
|
|
|
|
|
} else { |
28
|
38
|
|
|
|
|
139
|
push @attribs, splice(@_, 0, 2); |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
} |
31
|
163
|
100
|
|
|
|
352
|
if ( scalar @traits ) { |
32
|
153
|
50
|
|
|
|
389
|
die("Adding moxins to an existing class not supported yet!") |
33
|
|
|
|
|
|
|
unless ( $callee eq __PACKAGE__ ); |
34
|
153
|
|
|
|
|
653
|
$callee->class( @traits )->create( @attribs ) |
35
|
|
|
|
|
|
|
} else { |
36
|
10
|
|
|
|
|
35
|
$callee->create( @attribs ) |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
###################################################################### |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# $mason = $class->create( %options ); |
43
|
|
|
|
|
|
|
# $clone = $object->create( %options ); |
44
|
|
|
|
|
|
|
sub create { |
45
|
203
|
|
|
203
|
1
|
11755
|
my $referent = shift; |
46
|
203
|
100
|
|
|
|
513
|
if ( ! ref $referent ) { |
47
|
154
|
|
|
|
|
475
|
bless { $referent->defaults(), @_ }, $referent; |
48
|
|
|
|
|
|
|
} else { |
49
|
49
|
|
|
|
|
119
|
bless { $referent->defaults(), %$referent, @_ }, ref $referent; |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub defaults { |
54
|
|
|
|
|
|
|
return () |
55
|
203
|
|
|
203
|
1
|
2206
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
###################################################################### |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
###################################################################### |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# $code_ref = $mason->compile( text => $template, %options ); |
62
|
|
|
|
|
|
|
# $code_ref = $mason->compile( file => $filename, %options ); |
63
|
|
|
|
|
|
|
# $code_ref = $mason->compile( handle => $filehandle, %options ); |
64
|
|
|
|
|
|
|
sub compile { |
65
|
311
|
|
|
311
|
1
|
97747
|
my ( $self, $src_type, $src_data, %options ) = @_; |
66
|
|
|
|
|
|
|
|
67
|
311
|
|
|
|
|
1029
|
($self, $src_type, $src_data) = $self->prepare($src_type, $src_data,%options); |
68
|
|
|
|
|
|
|
|
69
|
311
|
|
|
|
|
883
|
my $code = $self->interpret( $src_type, $src_data ); |
70
|
|
|
|
|
|
|
|
71
|
311
|
100
|
|
|
|
887
|
unless ( $self->eval_sub($code) ) { |
72
|
17
|
50
|
|
|
|
198
|
ref($@) and die $@; |
73
|
17
|
|
|
|
|
72
|
$self->croak_msg( "MicroMason compilation failed: $@\n" . _number_lines($code) . "\n" ); |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# Internal helper to number the lines in the compiled template when compilation croaks |
79
|
|
|
|
|
|
|
sub _number_lines { |
80
|
17
|
|
|
17
|
|
59
|
my $code = shift; |
81
|
|
|
|
|
|
|
|
82
|
17
|
|
|
|
|
56
|
my $n = 0; |
83
|
17
|
|
|
|
|
99
|
return join("\n", map { sprintf("%4d %s", $n++, $_) } split(/\n/, $code)). |
|
204
|
|
|
|
|
674
|
|
84
|
|
|
|
|
|
|
"\n** Please use Text::MicroMason->new\(-LineNumbers\) for better diagnostics!"; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
###################################################################### |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# $result = $mason->execute( code => $subref, @arguments ); |
91
|
|
|
|
|
|
|
# $result = $mason->execute( $src_type, $src_data, @arguments ); |
92
|
|
|
|
|
|
|
# $result = $mason->execute( $src_type, $src_data, \%options, @arguments ); |
93
|
|
|
|
|
|
|
sub execute { |
94
|
262
|
|
|
262
|
1
|
290843
|
my $self = shift; |
95
|
262
|
100
|
|
|
|
1191
|
my $sub = ( $_[0] eq 'code' ) ? do { shift; shift } : $self->compile( shift, shift, ref( $_[0] ) ? %{ shift() } : () ); |
|
4
|
100
|
|
|
|
5
|
|
|
4
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
4
|
|
96
|
257
|
100
|
|
|
|
8858
|
unless ($sub) { |
97
|
5
|
50
|
|
|
|
15
|
ref($@) and die $@; |
98
|
5
|
|
|
|
|
21
|
$self->croak_msg("MicroMason compilation failed: $@"); |
99
|
|
|
|
|
|
|
} |
100
|
252
|
|
|
|
|
843
|
&$sub( @_ ); |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
###################################################################### |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
###################################################################### |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# ($self, $src_type, $src_data) = $self->prepare($src_type, $src_data, %options) |
108
|
|
|
|
|
|
|
sub prepare { |
109
|
311
|
|
|
311
|
1
|
2765
|
my ( $self, $src_type, $src_data, %options ) = @_; |
110
|
311
|
100
|
|
|
|
887
|
$self = $self->create( %options ) if ( scalar keys %options ); |
111
|
311
|
|
|
|
|
1046
|
return ( $self, $src_type, $src_data ); |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
###################################################################### |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# $perl_code = $mason->interpret( $src_type, $src_data ); |
117
|
|
|
|
|
|
|
sub interpret { |
118
|
313
|
|
|
313
|
1
|
685
|
my ( $self, $src_type, $src_data ) = @_; |
119
|
313
|
|
|
|
|
874
|
my $template = $self->read( $src_type, $src_data ); |
120
|
313
|
|
|
|
|
866
|
my @tokens = $self->lex( $template ); |
121
|
313
|
|
|
|
|
1000
|
my $code = $self->assemble( @tokens ); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# Source file and line number |
124
|
313
|
|
|
|
|
1144
|
my $source_line = $self->source_file_line_label( $src_type, $src_data ); |
125
|
|
|
|
|
|
|
|
126
|
313
|
|
|
|
|
1286
|
return $source_line . "\n" . $code; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# $line_number_comment = $mason->source_file_line_label( $src_type, $src_data ); |
130
|
|
|
|
|
|
|
sub source_file_line_label { |
131
|
313
|
|
|
313
|
0
|
663
|
my ( $self, $src_type, $src_data ) = @_; |
132
|
|
|
|
|
|
|
|
133
|
313
|
100
|
|
|
|
770
|
if ( $src_type eq 'file' ) { |
134
|
47
|
|
|
|
|
182
|
return qq(# line 1 "$src_data"); |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
266
|
|
|
|
|
419
|
my @caller; |
138
|
|
|
|
|
|
|
my $call_level; |
139
|
266
|
|
100
|
|
|
374
|
do { @caller = caller( ++ $call_level ) } |
|
951
|
|
|
|
|
8639
|
|
140
|
|
|
|
|
|
|
while ( $caller[0] =~ /^Text::MicroMason/ or $self->isa($caller[0]) ); |
141
|
266
|
|
33
|
|
|
726
|
my $package = ( $caller[1] || $0 ); |
142
|
266
|
|
|
|
|
1086
|
qq{# line 1 "text template (compiled at $package line $caller[2])"} |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
###################################################################### |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# $code_ref = $mason->eval_sub( $perl_code ); |
149
|
|
|
|
|
|
|
sub eval_sub { |
150
|
292
|
|
|
292
|
1
|
606
|
my $m = shift; |
151
|
|
|
|
|
|
|
package Text::MicroMason::Commands; |
152
|
|
|
|
|
|
|
eval( shift ) |
153
|
292
|
|
|
1
|
|
88623
|
} |
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
63
|
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
###################################################################### |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
###################################################################### |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# $template = $mason->read( $src_type, $src_data ); |
160
|
|
|
|
|
|
|
sub read { |
161
|
313
|
|
|
313
|
1
|
924
|
my ( $self, $src_type, $src_data ) = @_; |
162
|
|
|
|
|
|
|
|
163
|
313
|
|
|
|
|
611
|
my $src_method = "read_$src_type"; |
164
|
313
|
50
|
|
|
|
1446
|
$self->can($src_method) |
165
|
|
|
|
|
|
|
or $self->croak_msg("Unsupported source type '$src_type'"); |
166
|
313
|
|
|
|
|
796
|
$self->$src_method( $src_data ); |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# $template = $mason->read_text( $template ); |
170
|
|
|
|
|
|
|
sub read_text { |
171
|
263
|
50
|
|
263
|
1
|
972
|
ref($_[1]) ? $$_[1] : $_[1]; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# $contents = $mason->read_file( $filename ); |
175
|
|
|
|
|
|
|
sub read_file { |
176
|
47
|
|
|
47
|
1
|
1225
|
my ( $self, $file ) = @_; |
177
|
47
|
|
|
|
|
124
|
local *FILE; |
178
|
47
|
50
|
|
|
|
1933
|
open FILE, "$file" or $self->croak_msg("MicroMason can't open $file: $!"); |
179
|
47
|
|
|
|
|
290
|
local $/ = undef; |
180
|
47
|
|
|
|
|
1055
|
local $_ = ; |
181
|
47
|
50
|
|
|
|
472
|
close FILE or $self->croak_msg("MicroMason can't close $file: $!");; |
182
|
47
|
|
|
|
|
403
|
return $_; |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# $contents = $mason->read_handle( $filehandle ); |
186
|
|
|
|
|
|
|
sub read_handle { |
187
|
3
|
|
|
3
|
1
|
10
|
my ( $self, $handle ) = @_; |
188
|
3
|
50
|
|
|
|
18
|
my $fh = (ref $handle eq 'GLOB') ? $handle : $$handle; |
189
|
3
|
|
|
|
|
32
|
local $/ = undef; |
190
|
|
|
|
|
|
|
<$fh> |
191
|
3
|
|
|
|
|
108
|
} |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
###################################################################### |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
# @token_pairs = $mason->lex( $template ); |
196
|
|
|
|
|
|
|
sub lex { |
197
|
299
|
|
|
299
|
1
|
504
|
my $self = shift; |
198
|
299
|
|
|
|
|
649
|
local $_ = "$_[0]"; |
199
|
299
|
|
|
|
|
440
|
my @tokens; |
200
|
299
|
50
|
|
|
|
976
|
my $lexer = $self->can('lex_token') |
201
|
|
|
|
|
|
|
or $self->croak_msg('Unable to lex_token(); must select a syntax mixin'); |
202
|
|
|
|
|
|
|
# warn "Lexing: " . pos($_) . " of " . length($_) . "\n"; |
203
|
299
|
|
|
|
|
1216
|
until ( /\G\z/gc ) { |
204
|
1161
|
50
|
0
|
|
|
2440
|
my @parsed = &$lexer( $self ) or |
205
|
|
|
|
|
|
|
/\G ( .{0,20} ) /gcxs |
206
|
|
|
|
|
|
|
&& die "MicroMason parsing halted at '$1'\n"; |
207
|
1161
|
|
|
|
|
4089
|
push @tokens, @parsed; |
208
|
|
|
|
|
|
|
} |
209
|
299
|
|
|
|
|
1228
|
return @tokens; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# ( $type, $value ) = $mason->lex_token(); |
213
|
|
|
|
|
|
|
sub lex_token { |
214
|
0
|
|
|
0
|
1
|
0
|
die "The lex_token() method is abstract and must be provided by a subclass"; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
###################################################################### |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
###################################################################### |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
# Text elements used for subroutine assembly |
222
|
|
|
|
|
|
|
sub assembler_rules { |
223
|
|
|
|
|
|
|
template => [ qw( $sub_start $init_errs $init_output |
224
|
|
|
|
|
|
|
$init_args @perl $return_output $sub_end ) ], |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# Subroutine scafolding |
227
|
|
|
|
|
|
|
sub_start => 'sub { ', |
228
|
|
|
|
|
|
|
sub_end => '}', |
229
|
|
|
|
|
|
|
init_errs => |
230
|
|
|
|
|
|
|
'local $SIG{__DIE__} = sub { ref($_[0]) and die $_[0]; die "MicroMason execution failed: ", @_ };', |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
# Argument processing elements |
233
|
|
|
|
|
|
|
init_args => 'my %ARGS = @_ if ($#_ % 2);', |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
# Output generation |
236
|
308
|
50
|
|
308
|
|
492
|
init_output => sub { my $m = shift; my $sub = $m->{output_sub} ? '$m->{output_sub}' : 'sub {push @OUT, @_}'; 'my @OUT; my $_out = ' . $sub . ';' }, |
|
308
|
|
|
|
|
697
|
|
|
308
|
|
|
|
|
1138
|
|
237
|
308
|
50
|
|
308
|
|
488
|
add_output => sub { my $m = shift; $m->{output_sub} ? '&$_out' : 'push @OUT,' }, |
|
308
|
|
|
|
|
1049
|
|
238
|
313
|
|
|
313
|
1
|
15273
|
return_output => 'join("", @OUT)', |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# Mapping between token types |
241
|
|
|
|
|
|
|
text_token => 'perl OUT( QUOTED );', |
242
|
|
|
|
|
|
|
expr_token => "perl OUT( \"\".do{\nTOKEN\n} );", |
243
|
|
|
|
|
|
|
# the "". here forces string context, and should hopefully make |
244
|
|
|
|
|
|
|
# 'uninitialized' warnings appear closer to their source, rather |
245
|
|
|
|
|
|
|
# than at the big join "", @OUT; at the end |
246
|
|
|
|
|
|
|
file_token => "perl OUT( \$m->execute( file => do {\nTOKEN\n} ) );", |
247
|
|
|
|
|
|
|
# Note that we need newline after TOKEN here in case it ends with a comment. |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
sub assembler_vars { |
251
|
313
|
|
|
313
|
0
|
457
|
my $self = shift; |
252
|
313
|
|
|
|
|
839
|
my %assembler = $self->assembler_rules(); |
253
|
|
|
|
|
|
|
|
254
|
313
|
|
|
|
|
902
|
my @assembly = @{ delete $assembler{ template } }; |
|
313
|
|
|
|
|
1174
|
|
255
|
|
|
|
|
|
|
|
256
|
1047
|
|
|
|
|
4204
|
my %token_map = map { ( /^(.*?)_token$/ )[0] => delete $assembler{$_} } |
257
|
313
|
|
|
|
|
1167
|
grep { /_token$/ } keys %assembler; |
|
3266
|
|
|
|
|
6869
|
|
258
|
|
|
|
|
|
|
|
259
|
313
|
100
|
|
|
|
1131
|
my %fragments = map { $_ => map { ref($_) ? &{$_}( $self ) : $_ } $assembler{$_} } keys %assembler; |
|
2219
|
|
|
|
|
3170
|
|
|
2219
|
|
|
|
|
4805
|
|
|
616
|
|
|
|
|
1202
|
|
260
|
|
|
|
|
|
|
|
261
|
313
|
|
|
|
|
2316
|
return( \@assembly, \%fragments, \%token_map ); |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
# $perl_code = $mason->assemble( @tokens ); |
265
|
|
|
|
|
|
|
sub assemble { |
266
|
313
|
|
|
313
|
1
|
2470
|
my $self = shift; |
267
|
313
|
|
|
|
|
883
|
my @tokens = @_; |
268
|
|
|
|
|
|
|
|
269
|
313
|
|
|
|
|
858
|
my ( $order, $fragments, $token_map ) = $self->assembler_vars(); |
270
|
|
|
|
|
|
|
|
271
|
313
|
|
|
|
|
683
|
my %token_streams = map { $_ => [] } map { ( /^\W?\@(\w+)$/ ) } @$order; |
|
1497
|
|
|
|
|
3088
|
|
|
3403
|
|
|
|
|
6559
|
|
272
|
|
|
|
|
|
|
|
273
|
313
|
|
|
|
|
1055
|
while ( scalar @tokens ) { |
274
|
1228
|
|
|
|
|
2567
|
my ( $type, $token ) = splice( @tokens, 0, 2 ); |
275
|
|
|
|
|
|
|
|
276
|
1228
|
100
|
100
|
|
|
4106
|
unless ( $token_streams{$type} or $token_map->{$type} ) { |
277
|
40
|
|
|
|
|
75
|
my $method = "assemble_$type"; |
278
|
40
|
50
|
|
|
|
156
|
my $sub = $self->can( $method ) |
279
|
|
|
|
|
|
|
or $self->croak_msg( "Unexpected token type '$type': '$token'" ); |
280
|
40
|
|
|
|
|
100
|
($type, $token) = &$sub( $self, $token ); |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
1228
|
100
|
|
|
|
11937
|
if ( my $typedef = $token_map->{ $type } ) { |
284
|
|
|
|
|
|
|
# Perform token map substitution in a single pass so that uses of |
285
|
|
|
|
|
|
|
# OUT in the token text are not improperly converted to output calls. |
286
|
|
|
|
|
|
|
# -- Simon, 2009-11-14 |
287
|
|
|
|
|
|
|
my %substitution_map = ( |
288
|
|
|
|
|
|
|
'OUT' => $fragments->{add_output}, |
289
|
959
|
|
|
|
|
3599
|
'TOKEN' => $token, |
290
|
|
|
|
|
|
|
'QUOTED' => "qq(\Q$token\E)", |
291
|
|
|
|
|
|
|
); |
292
|
959
|
|
|
|
|
7149
|
$typedef =~ s/\b(OUT|TOKEN|QUOTED)\b/$substitution_map{$1}/g; |
293
|
|
|
|
|
|
|
|
294
|
959
|
|
|
|
|
3576
|
( $type, $token ) = split ' ', $typedef, 2; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
1228
|
50
|
|
|
|
2844
|
my $ary = $token_streams{$type} |
298
|
|
|
|
|
|
|
or $self->croak_msg( "Unexpected token type '$type': '$token'" ); |
299
|
|
|
|
|
|
|
|
300
|
1228
|
|
|
|
|
3312
|
push @$ary, $token |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
join( "\n", map { |
304
|
313
|
50
|
|
|
|
663
|
/^(\W+)(\w+)$/ or $self->croak_msg("Can't assemble $_"); |
|
3403
|
|
|
|
|
8880
|
|
305
|
3403
|
100
|
|
|
|
7879
|
if ( $1 eq '$' ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
306
|
1906
|
|
|
|
|
4245
|
$fragments->{ $2 } |
307
|
|
|
|
|
|
|
} elsif ( $1 eq '@' ) { |
308
|
905
|
|
|
|
|
1133
|
@{ $token_streams{ $2 } } |
|
905
|
|
|
|
|
2166
|
|
309
|
|
|
|
|
|
|
} elsif ( $1 eq '!@' ) { |
310
|
296
|
|
|
|
|
449
|
reverse @{ $token_streams{ $2 } } |
|
296
|
|
|
|
|
612
|
|
311
|
|
|
|
|
|
|
} elsif ( $1 eq '-@' ) { |
312
|
|
|
|
|
|
|
() |
313
|
296
|
|
|
|
|
2665
|
} else { |
314
|
0
|
|
|
|
|
0
|
$self->croak_msg("Can't assemble $_"); |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
} @$order ); |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
###################################################################### |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
###################################################################### |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub croak_msg { |
324
|
22
|
|
|
22
|
1
|
53
|
local $Carp::CarpLevel = 2; |
325
|
22
|
50
|
|
|
|
4399
|
shift and Carp::croak( ( @_ == 1 ) ? $_[0] : join(' ', map _printable(), @_) ) |
|
|
50
|
|
|
|
|
|
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
my %Escape = ( |
329
|
|
|
|
|
|
|
( map { chr($_), unpack('H2', chr($_)) } (0..255) ), |
330
|
|
|
|
|
|
|
"\\"=>'\\', "\r"=>'r', "\n"=>'n', "\t"=>'t', "\""=>'"' |
331
|
|
|
|
|
|
|
); |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
# $special_characters_escaped = _printable( $source_string ); |
334
|
|
|
|
|
|
|
sub _printable { |
335
|
0
|
0
|
|
0
|
|
0
|
local $_ = scalar(@_) ? (shift) : $_; |
336
|
0
|
0
|
|
|
|
0
|
return "(undef)" unless defined; |
337
|
0
|
|
|
|
|
0
|
s/([\r\n\t\"\\\x00-\x1f\x7F-\xFF])/\\$Escape{$1}/sgo; |
338
|
0
|
0
|
|
|
|
0
|
/[^\w\d\-\:\.\']/ ? "q($_)" : $_; |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
###################################################################### |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
sub cache_key { |
345
|
52
|
|
|
52
|
0
|
182
|
my $self = shift; |
346
|
52
|
|
|
|
|
85
|
my ($src_type, $src_data, %options) = @_; |
347
|
|
|
|
|
|
|
|
348
|
52
|
|
|
|
|
114
|
return $src_data; |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
1; |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
__END__ |