| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Text::MicroMason::Base; |
|
2
|
|
|
|
|
|
|
|
|
3
|
39
|
|
|
39
|
|
125
|
use strict; |
|
|
39
|
|
|
|
|
37
|
|
|
|
39
|
|
|
|
|
1172
|
|
|
4
|
|
|
|
|
|
|
require Carp; |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
###################################################################### |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
###################################################################### |
|
9
|
|
|
|
|
|
|
|
|
10
|
39
|
|
|
39
|
|
14782
|
use Class::MixinFactory -hasafactory; |
|
|
39
|
|
|
|
|
100470
|
|
|
|
39
|
|
|
|
|
244
|
|
|
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
|
145
|
|
|
145
|
1
|
4651
|
my $callee = shift; |
|
22
|
145
|
|
|
|
|
126
|
my ( @traits, @attribs ); |
|
23
|
145
|
|
|
|
|
312
|
while ( scalar @_ ) { |
|
24
|
247
|
100
|
|
|
|
760
|
if ( $_[0] =~ /^\-(\w+)$/ ) { |
|
25
|
217
|
|
|
|
|
515
|
push @traits, $1; |
|
26
|
217
|
|
|
|
|
356
|
shift; |
|
27
|
|
|
|
|
|
|
} else { |
|
28
|
30
|
|
|
|
|
72
|
push @attribs, splice(@_, 0, 2); |
|
29
|
|
|
|
|
|
|
} |
|
30
|
|
|
|
|
|
|
} |
|
31
|
145
|
100
|
|
|
|
221
|
if ( scalar @traits ) { |
|
32
|
135
|
50
|
|
|
|
283
|
die("Adding moxins to an existing class not supported yet!") |
|
33
|
|
|
|
|
|
|
unless ( $callee eq __PACKAGE__ ); |
|
34
|
135
|
|
|
|
|
424
|
$callee->class( @traits )->create( @attribs ) |
|
35
|
|
|
|
|
|
|
} else { |
|
36
|
10
|
|
|
|
|
23
|
$callee->create( @attribs ) |
|
37
|
|
|
|
|
|
|
} |
|
38
|
|
|
|
|
|
|
} |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
###################################################################### |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# $mason = $class->create( %options ); |
|
43
|
|
|
|
|
|
|
# $clone = $object->create( %options ); |
|
44
|
|
|
|
|
|
|
sub create { |
|
45
|
185
|
|
|
185
|
1
|
6210
|
my $referent = shift; |
|
46
|
185
|
100
|
|
|
|
324
|
if ( ! ref $referent ) { |
|
47
|
136
|
|
|
|
|
284
|
bless { $referent->defaults(), @_ }, $referent; |
|
48
|
|
|
|
|
|
|
} else { |
|
49
|
49
|
|
|
|
|
71
|
bless { $referent->defaults(), %$referent, @_ }, ref $referent; |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub defaults { |
|
54
|
|
|
|
|
|
|
return () |
|
55
|
185
|
|
|
185
|
1
|
1409
|
} |
|
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
|
292
|
|
|
292
|
1
|
41885
|
my ( $self, $src_type, $src_data, %options ) = @_; |
|
66
|
|
|
|
|
|
|
|
|
67
|
292
|
|
|
|
|
652
|
($self, $src_type, $src_data) = $self->prepare($src_type, $src_data,%options); |
|
68
|
|
|
|
|
|
|
|
|
69
|
292
|
|
|
|
|
549
|
my $code = $self->interpret( $src_type, $src_data ); |
|
70
|
|
|
|
|
|
|
|
|
71
|
292
|
100
|
|
|
|
521
|
$self->eval_sub( $code ) |
|
72
|
|
|
|
|
|
|
or $self->croak_msg( "MicroMason compilation failed: $@\n". _number_lines($code)."\n" ); |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# Internal helper to number the lines in the compiled template when compilation croaks |
|
77
|
|
|
|
|
|
|
sub _number_lines { |
|
78
|
14
|
|
|
14
|
|
979
|
my $code = shift; |
|
79
|
|
|
|
|
|
|
|
|
80
|
14
|
|
|
|
|
15
|
my $n = 0; |
|
81
|
14
|
|
|
|
|
54
|
return join("\n", map { sprintf("%4d %s", $n++, $_) } split(/\n/, $code)). |
|
|
174
|
|
|
|
|
358
|
|
|
82
|
|
|
|
|
|
|
"\n** Please use Text::MicroMason->new\(-LineNumbers\) for better diagnostics!"; |
|
83
|
|
|
|
|
|
|
} |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
###################################################################### |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# $result = $mason->execute( code => $subref, @arguments ); |
|
89
|
|
|
|
|
|
|
# $result = $mason->execute( $src_type, $src_data, @arguments ); |
|
90
|
|
|
|
|
|
|
# $result = $mason->execute( $src_type, $src_data, \%options, @arguments ); |
|
91
|
|
|
|
|
|
|
sub execute { |
|
92
|
249
|
|
|
249
|
1
|
150331
|
my $self = shift; |
|
93
|
4
|
|
|
|
|
4
|
my $sub = ( $_[0] eq 'code' ) ? do { shift; shift } : |
|
|
4
|
|
|
|
|
10
|
|
|
94
|
249
|
100
|
|
|
|
857
|
$self->compile( shift, shift, ref($_[0]) ? %{ shift() } : () ) |
|
|
1
|
100
|
|
|
|
15
|
|
|
|
|
100
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
or $self->croak_msg("MicroMason compilation failed: $@"); |
|
96
|
242
|
|
|
|
|
3883
|
&$sub( @_ ); |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
###################################################################### |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
###################################################################### |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# ($self, $src_type, $src_data) = $self->prepare($src_type, $src_data, %options) |
|
104
|
|
|
|
|
|
|
sub prepare { |
|
105
|
292
|
|
|
292
|
1
|
1672
|
my ( $self, $src_type, $src_data, %options ) = @_; |
|
106
|
292
|
100
|
|
|
|
620
|
$self = $self->create( %options ) if ( scalar keys %options ); |
|
107
|
292
|
|
|
|
|
701
|
return ( $self, $src_type, $src_data ); |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
###################################################################### |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# $perl_code = $mason->interpret( $src_type, $src_data ); |
|
113
|
|
|
|
|
|
|
sub interpret { |
|
114
|
294
|
|
|
294
|
1
|
301
|
my ( $self, $src_type, $src_data ) = @_; |
|
115
|
294
|
|
|
|
|
475
|
my $template = $self->read( $src_type, $src_data ); |
|
116
|
294
|
|
|
|
|
573
|
my @tokens = $self->lex( $template ); |
|
117
|
294
|
|
|
|
|
690
|
my $code = $self->assemble( @tokens ); |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# Source file and line number |
|
120
|
294
|
|
|
|
|
777
|
my $source_line = $self->source_file_line_label( $src_type, $src_data ); |
|
121
|
|
|
|
|
|
|
|
|
122
|
294
|
|
|
|
|
738
|
return $source_line . "\n" . $code; |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# $line_number_comment = $mason->source_file_line_label( $src_type, $src_data ); |
|
126
|
|
|
|
|
|
|
sub source_file_line_label { |
|
127
|
294
|
|
|
294
|
0
|
316
|
my ( $self, $src_type, $src_data ) = @_; |
|
128
|
|
|
|
|
|
|
|
|
129
|
294
|
100
|
|
|
|
491
|
if ( $src_type eq 'file' ) { |
|
130
|
47
|
|
|
|
|
93
|
return qq(# line 1 "$src_data"); |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
|
|
133
|
247
|
|
|
|
|
171
|
my @caller; |
|
134
|
|
|
|
|
|
|
my $call_level; |
|
135
|
247
|
|
100
|
|
|
175
|
do { @caller = caller( ++ $call_level ) } |
|
|
828
|
|
|
|
|
6902
|
|
|
136
|
|
|
|
|
|
|
while ( $caller[0] =~ /^Text::MicroMason/ or $self->isa($caller[0]) ); |
|
137
|
247
|
|
33
|
|
|
427
|
my $package = ( $caller[1] || $0 ); |
|
138
|
247
|
|
|
|
|
720
|
qq{# line 1 "text template (compiled at $package line $caller[2])"} |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
###################################################################### |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# $code_ref = $mason->eval_sub( $perl_code ); |
|
145
|
|
|
|
|
|
|
sub eval_sub { |
|
146
|
291
|
|
|
291
|
1
|
267
|
my $m = shift; |
|
147
|
|
|
|
|
|
|
package Text::MicroMason::Commands; |
|
148
|
|
|
|
|
|
|
eval( shift ) |
|
149
|
291
|
|
|
1
|
|
63889
|
} |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
43
|
|
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
###################################################################### |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
###################################################################### |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# $template = $mason->read( $src_type, $src_data ); |
|
156
|
|
|
|
|
|
|
sub read { |
|
157
|
294
|
|
|
294
|
1
|
546
|
my ( $self, $src_type, $src_data ) = @_; |
|
158
|
|
|
|
|
|
|
|
|
159
|
294
|
|
|
|
|
372
|
my $src_method = "read_$src_type"; |
|
160
|
294
|
50
|
|
|
|
1040
|
$self->can($src_method) |
|
161
|
|
|
|
|
|
|
or $self->croak_msg("Unsupported source type '$src_type'"); |
|
162
|
294
|
|
|
|
|
507
|
$self->$src_method( $src_data ); |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# $template = $mason->read_text( $template ); |
|
166
|
|
|
|
|
|
|
sub read_text { |
|
167
|
244
|
50
|
|
244
|
1
|
650
|
ref($_[1]) ? $$_[1] : $_[1]; |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# $contents = $mason->read_file( $filename ); |
|
171
|
|
|
|
|
|
|
sub read_file { |
|
172
|
47
|
|
|
47
|
1
|
748
|
my ( $self, $file ) = @_; |
|
173
|
47
|
|
|
|
|
81
|
local *FILE; |
|
174
|
47
|
50
|
|
|
|
1165
|
open FILE, "$file" or $self->croak_msg("MicroMason can't open $file: $!"); |
|
175
|
47
|
|
|
|
|
147
|
local $/ = undef; |
|
176
|
47
|
|
|
|
|
573
|
local $_ = ; |
|
177
|
47
|
50
|
|
|
|
304
|
close FILE or $self->croak_msg("MicroMason can't close $file: $!");; |
|
178
|
47
|
|
|
|
|
253
|
return $_; |
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# $contents = $mason->read_handle( $filehandle ); |
|
182
|
|
|
|
|
|
|
sub read_handle { |
|
183
|
3
|
|
|
3
|
1
|
4
|
my ( $self, $handle ) = @_; |
|
184
|
3
|
50
|
|
|
|
10
|
my $fh = (ref $handle eq 'GLOB') ? $handle : $$handle; |
|
185
|
3
|
|
|
|
|
8
|
local $/ = undef; |
|
186
|
|
|
|
|
|
|
<$fh> |
|
187
|
3
|
|
|
|
|
53
|
} |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
###################################################################### |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
# @token_pairs = $mason->lex( $template ); |
|
192
|
|
|
|
|
|
|
sub lex { |
|
193
|
280
|
|
|
280
|
1
|
257
|
my $self = shift; |
|
194
|
280
|
|
|
|
|
391
|
local $_ = "$_[0]"; |
|
195
|
280
|
|
|
|
|
217
|
my @tokens; |
|
196
|
280
|
50
|
|
|
|
725
|
my $lexer = $self->can('lex_token') |
|
197
|
|
|
|
|
|
|
or $self->croak_msg('Unable to lex_token(); must select a syntax mixin'); |
|
198
|
|
|
|
|
|
|
# warn "Lexing: " . pos($_) . " of " . length($_) . "\n"; |
|
199
|
280
|
|
|
|
|
753
|
until ( /\G\z/gc ) { |
|
200
|
1118
|
50
|
0
|
|
|
1694
|
my @parsed = &$lexer( $self ) or |
|
201
|
|
|
|
|
|
|
/\G ( .{0,20} ) /gcxs |
|
202
|
|
|
|
|
|
|
&& die "MicroMason parsing halted at '$1'\n"; |
|
203
|
1118
|
|
|
|
|
2773
|
push @tokens, @parsed; |
|
204
|
|
|
|
|
|
|
} |
|
205
|
280
|
|
|
|
|
882
|
return @tokens; |
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# ( $type, $value ) = $mason->lex_token(); |
|
209
|
|
|
|
|
|
|
sub lex_token { |
|
210
|
0
|
|
|
0
|
1
|
0
|
die "The lex_token() method is abstract and must be provided by a subclass"; |
|
211
|
|
|
|
|
|
|
} |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
###################################################################### |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
###################################################################### |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
# Text elements used for subroutine assembly |
|
218
|
|
|
|
|
|
|
sub assembler_rules { |
|
219
|
|
|
|
|
|
|
template => [ qw( $sub_start $init_errs $init_output |
|
220
|
|
|
|
|
|
|
$init_args @perl $return_output $sub_end ) ], |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# Subroutine scafolding |
|
223
|
|
|
|
|
|
|
sub_start => 'sub { ', |
|
224
|
|
|
|
|
|
|
sub_end => '}', |
|
225
|
|
|
|
|
|
|
init_errs => |
|
226
|
|
|
|
|
|
|
'local $SIG{__DIE__} = sub { die "MicroMason execution failed: ", @_ };', |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# Argument processing elements |
|
229
|
|
|
|
|
|
|
init_args => 'my %ARGS = @_ if ($#_ % 2);', |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# Output generation |
|
232
|
289
|
50
|
|
289
|
|
230
|
init_output => sub { my $m = shift; my $sub = $m->{output_sub} ? '$m->{output_sub}' : 'sub {push @OUT, @_}'; 'my @OUT; my $_out = ' . $sub . ';' }, |
|
|
289
|
|
|
|
|
425
|
|
|
|
289
|
|
|
|
|
773
|
|
|
233
|
289
|
50
|
|
289
|
|
222
|
add_output => sub { my $m = shift; $m->{output_sub} ? '&$_out' : 'push @OUT,' }, |
|
|
289
|
|
|
|
|
746
|
|
|
234
|
294
|
|
|
294
|
1
|
9100
|
return_output => 'join("", @OUT)', |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# Mapping between token types |
|
237
|
|
|
|
|
|
|
text_token => 'perl OUT( QUOTED );', |
|
238
|
|
|
|
|
|
|
expr_token => "perl OUT( \"\".do{\nTOKEN\n} );", |
|
239
|
|
|
|
|
|
|
# the "". here forces string context, and should hopefully make |
|
240
|
|
|
|
|
|
|
# 'uninitialized' warnings appear closer to their source, rather |
|
241
|
|
|
|
|
|
|
# than at the big join "", @OUT; at the end |
|
242
|
|
|
|
|
|
|
file_token => "perl OUT( \$m->execute( file => do {\nTOKEN\n} ) );", |
|
243
|
|
|
|
|
|
|
# Note that we need newline after TOKEN here in case it ends with a comment. |
|
244
|
|
|
|
|
|
|
} |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub assembler_vars { |
|
247
|
294
|
|
|
294
|
0
|
224
|
my $self = shift; |
|
248
|
294
|
|
|
|
|
558
|
my %assembler = $self->assembler_rules(); |
|
249
|
|
|
|
|
|
|
|
|
250
|
294
|
|
|
|
|
543
|
my @assembly = @{ delete $assembler{ template } }; |
|
|
294
|
|
|
|
|
719
|
|
|
251
|
|
|
|
|
|
|
|
|
252
|
990
|
|
|
|
|
2725
|
my %token_map = map { ( /^(.*?)_token$/ )[0] => delete $assembler{$_} } |
|
253
|
294
|
|
|
|
|
762
|
grep { /_token$/ } keys %assembler; |
|
|
3076
|
|
|
|
|
3555
|
|
|
254
|
|
|
|
|
|
|
|
|
255
|
294
|
100
|
|
|
|
684
|
my %fragments = map { $_ => map { ref($_) ? &{$_}( $self ) : $_ } $assembler{$_} } keys %assembler; |
|
|
2086
|
|
|
|
|
1567
|
|
|
|
2086
|
|
|
|
|
2978
|
|
|
|
578
|
|
|
|
|
764
|
|
|
256
|
|
|
|
|
|
|
|
|
257
|
294
|
|
|
|
|
1474
|
return( \@assembly, \%fragments, \%token_map ); |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
# $perl_code = $mason->assemble( @tokens ); |
|
261
|
|
|
|
|
|
|
sub assemble { |
|
262
|
294
|
|
|
294
|
1
|
1506
|
my $self = shift; |
|
263
|
294
|
|
|
|
|
497
|
my @tokens = @_; |
|
264
|
|
|
|
|
|
|
|
|
265
|
294
|
|
|
|
|
476
|
my ( $order, $fragments, $token_map ) = $self->assembler_vars(); |
|
266
|
|
|
|
|
|
|
|
|
267
|
294
|
|
|
|
|
382
|
my %token_streams = map { $_ => [] } map { ( /^\W?\@(\w+)$/ ) } @$order; |
|
|
1402
|
|
|
|
|
1782
|
|
|
|
3194
|
|
|
|
|
3572
|
|
|
268
|
|
|
|
|
|
|
|
|
269
|
294
|
|
|
|
|
798
|
while ( scalar @tokens ) { |
|
270
|
1185
|
|
|
|
|
1359
|
my ( $type, $token ) = splice( @tokens, 0, 2 ); |
|
271
|
|
|
|
|
|
|
|
|
272
|
1185
|
100
|
66
|
|
|
2566
|
unless ( $token_streams{$type} or $token_map->{$type} ) { |
|
273
|
39
|
|
|
|
|
49
|
my $method = "assemble_$type"; |
|
274
|
39
|
50
|
|
|
|
122
|
my $sub = $self->can( $method ) |
|
275
|
|
|
|
|
|
|
or $self->croak_msg( "Unexpected token type '$type': '$token'" ); |
|
276
|
39
|
|
|
|
|
70
|
($type, $token) = &$sub( $self, $token ); |
|
277
|
|
|
|
|
|
|
} |
|
278
|
|
|
|
|
|
|
|
|
279
|
1185
|
100
|
|
|
|
1734
|
if ( my $typedef = $token_map->{ $type } ) { |
|
280
|
|
|
|
|
|
|
# Perform token map substitution in a single pass so that uses of |
|
281
|
|
|
|
|
|
|
# OUT in the token text are not improperly converted to output calls. |
|
282
|
|
|
|
|
|
|
# -- Simon, 2009-11-14 |
|
283
|
|
|
|
|
|
|
my %substitution_map = ( |
|
284
|
|
|
|
|
|
|
'OUT' => $fragments->{add_output}, |
|
285
|
917
|
|
|
|
|
2302
|
'TOKEN' => $token, |
|
286
|
|
|
|
|
|
|
'QUOTED' => "qq(\Q$token\E)", |
|
287
|
|
|
|
|
|
|
); |
|
288
|
917
|
|
|
|
|
4789
|
$typedef =~ s/\b(OUT|TOKEN|QUOTED)\b/$substitution_map{$1}/g; |
|
289
|
|
|
|
|
|
|
|
|
290
|
917
|
|
|
|
|
1965
|
( $type, $token ) = split ' ', $typedef, 2; |
|
291
|
|
|
|
|
|
|
} |
|
292
|
|
|
|
|
|
|
|
|
293
|
1185
|
50
|
|
|
|
1828
|
my $ary = $token_streams{$type} |
|
294
|
|
|
|
|
|
|
or $self->croak_msg( "Unexpected token type '$type': '$token'" ); |
|
295
|
|
|
|
|
|
|
|
|
296
|
1185
|
|
|
|
|
2296
|
push @$ary, $token |
|
297
|
|
|
|
|
|
|
} |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
join( "\n", map { |
|
300
|
294
|
50
|
|
|
|
360
|
/^(\W+)(\w+)$/ or $self->croak_msg("Can't assemble $_"); |
|
|
3194
|
|
|
|
|
5439
|
|
|
301
|
3194
|
100
|
|
|
|
4653
|
if ( $1 eq '$' ) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
302
|
1792
|
|
|
|
|
2169
|
$fragments->{ $2 } |
|
303
|
|
|
|
|
|
|
} elsif ( $1 eq '@' ) { |
|
304
|
848
|
|
|
|
|
529
|
@{ $token_streams{ $2 } } |
|
|
848
|
|
|
|
|
1390
|
|
|
305
|
|
|
|
|
|
|
} elsif ( $1 eq '!@' ) { |
|
306
|
277
|
|
|
|
|
181
|
reverse @{ $token_streams{ $2 } } |
|
|
277
|
|
|
|
|
426
|
|
|
307
|
|
|
|
|
|
|
} elsif ( $1 eq '-@' ) { |
|
308
|
|
|
|
|
|
|
() |
|
309
|
277
|
|
|
|
|
1716
|
} else { |
|
310
|
0
|
|
|
|
|
0
|
$self->croak_msg("Can't assemble $_"); |
|
311
|
|
|
|
|
|
|
} |
|
312
|
|
|
|
|
|
|
} @$order ); |
|
313
|
|
|
|
|
|
|
} |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
###################################################################### |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
###################################################################### |
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
sub croak_msg { |
|
320
|
16
|
|
|
16
|
1
|
17
|
local $Carp::CarpLevel = 2; |
|
321
|
16
|
50
|
|
|
|
2764
|
shift and Carp::croak( ( @_ == 1 ) ? $_[0] : join(' ', map _printable(), @_) ) |
|
|
|
50
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
} |
|
323
|
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
my %Escape = ( |
|
325
|
|
|
|
|
|
|
( map { chr($_), unpack('H2', chr($_)) } (0..255) ), |
|
326
|
|
|
|
|
|
|
"\\"=>'\\', "\r"=>'r', "\n"=>'n', "\t"=>'t', "\""=>'"' |
|
327
|
|
|
|
|
|
|
); |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
# $special_characters_escaped = _printable( $source_string ); |
|
330
|
|
|
|
|
|
|
sub _printable { |
|
331
|
0
|
0
|
|
0
|
|
0
|
local $_ = scalar(@_) ? (shift) : $_; |
|
332
|
0
|
0
|
|
|
|
0
|
return "(undef)" unless defined; |
|
333
|
0
|
|
|
|
|
0
|
s/([\r\n\t\"\\\x00-\x1f\x7F-\xFF])/\\$Escape{$1}/sgo; |
|
334
|
0
|
0
|
|
|
|
0
|
/[^\w\d\-\:\.\']/ ? "q($_)" : $_; |
|
335
|
|
|
|
|
|
|
} |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
###################################################################### |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
sub cache_key { |
|
341
|
52
|
|
|
52
|
0
|
83
|
my $self = shift; |
|
342
|
52
|
|
|
|
|
49
|
my ($src_type, $src_data, %options) = @_; |
|
343
|
|
|
|
|
|
|
|
|
344
|
52
|
|
|
|
|
80
|
return $src_data; |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
1; |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
__END__ |