line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#!/usr/bin/perl |
2
|
|
|
|
|
|
|
|
3
|
37
|
|
|
37
|
|
271
|
use strict; |
|
37
|
|
|
|
|
114
|
|
|
37
|
|
|
|
|
1213
|
|
4
|
37
|
|
|
37
|
|
239
|
use warnings; |
|
37
|
|
|
|
|
95
|
|
|
37
|
|
|
|
|
1566
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token; |
7
|
37
|
|
|
37
|
|
254
|
use base 'WWW::Shopify::Liquid::Element'; |
|
37
|
|
|
|
|
97
|
|
|
37
|
|
|
|
|
7292
|
|
8
|
3377
|
|
|
3377
|
|
16747
|
sub new { return bless { line => $_[1], core => $_[2] }, $_[0]; }; |
9
|
1
|
|
|
1
|
|
10
|
sub stringify { return $_[0]->{core}; } |
10
|
94
|
|
|
94
|
|
413
|
sub tokens { return $_[0]; } |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Operator; |
13
|
37
|
|
|
37
|
|
286
|
use base 'WWW::Shopify::Liquid::Token'; |
|
37
|
|
|
|
|
93
|
|
|
37
|
|
|
|
|
11109
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Operand; |
16
|
37
|
|
|
37
|
|
297
|
use base 'WWW::Shopify::Liquid::Token'; |
|
37
|
|
|
|
|
92
|
|
|
37
|
|
|
|
|
7448
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::String; |
19
|
37
|
|
|
37
|
|
290
|
use base 'WWW::Shopify::Liquid::Token::Operand'; |
|
37
|
|
|
|
|
100
|
|
|
37
|
|
|
|
|
12763
|
|
20
|
1123
|
|
|
1123
|
|
2366
|
sub process { my ($self, $hash) = @_; return $self->{core}; } |
|
1123
|
|
|
|
|
3766
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Number; |
23
|
37
|
|
|
37
|
|
326
|
use base 'WWW::Shopify::Liquid::Token::Operand'; |
|
37
|
|
|
|
|
115
|
|
|
37
|
|
|
|
|
9234
|
|
24
|
212
|
|
|
212
|
|
498
|
sub process { my ($self, $hash) = @_; return $self->{core}; } |
|
212
|
|
|
|
|
746
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::NULL; |
27
|
37
|
|
|
37
|
|
309
|
use base 'WWW::Shopify::Liquid::Token::Operand'; |
|
37
|
|
|
|
|
114
|
|
|
37
|
|
|
|
|
7802
|
|
28
|
5
|
|
|
5
|
|
18
|
sub process { return undef; } |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Bool; |
31
|
37
|
|
|
37
|
|
292
|
use base 'WWW::Shopify::Liquid::Token::Operand'; |
|
37
|
|
|
|
|
119
|
|
|
37
|
|
|
|
|
8852
|
|
32
|
0
|
|
|
0
|
|
0
|
sub process { my ($self, $hash) = @_; return $self->{core}; } |
|
0
|
|
|
|
|
0
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::FunctionCall; |
35
|
37
|
|
|
37
|
|
291
|
use base 'WWW::Shopify::Liquid::Token::Operand'; |
|
37
|
|
|
|
|
103
|
|
|
37
|
|
|
|
|
7118
|
|
36
|
|
|
|
|
|
|
|
37
|
37
|
|
|
37
|
|
2817
|
use Scalar::Util qw(looks_like_number reftype blessed); |
|
37
|
|
|
|
|
109
|
|
|
37
|
|
|
|
|
13611
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub new { |
40
|
3
|
|
|
3
|
|
9
|
my $package = shift; |
41
|
3
|
|
|
|
|
26
|
return bless { |
42
|
|
|
|
|
|
|
line => shift, |
43
|
|
|
|
|
|
|
method => shift, |
44
|
|
|
|
|
|
|
self => shift, |
45
|
|
|
|
|
|
|
arguments => [@_] |
46
|
|
|
|
|
|
|
}, $package; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub process { |
50
|
0
|
|
|
0
|
|
0
|
my ($self, $hash, $action, $pipeline) = @_; |
51
|
0
|
0
|
|
|
|
0
|
if ($action eq "render") { |
52
|
0
|
0
|
|
|
|
0
|
die new WWW::Shopify::Liquid::Exception::Renderer::Forbidden($self->{line}) unless $pipeline->make_method_calls; |
53
|
|
|
|
|
|
|
|
54
|
0
|
0
|
|
|
|
0
|
my @arguments = map { $self->is_processed($_) ? $_ : $_->render($pipeline, $hash) } @{$self->{arguments}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
55
|
0
|
0
|
|
|
|
0
|
my $inner_self = $self->is_processed($self->{self}) ? $self->{self} : $self->{self}->render($pipeline, $hash); |
56
|
0
|
0
|
|
|
|
0
|
my $method = $self->is_processed($self->{method}) ? $self->{method} : $self->{method}->render($pipeline, $hash); |
57
|
0
|
0
|
0
|
|
|
0
|
die new WWW::Shopify::Liquid::Exception::Renderer($self->{line}, "Can't find method $method on $inner_self.") unless $inner_self && blessed($inner_self) && !ref($method); |
|
|
|
0
|
|
|
|
|
58
|
0
|
|
|
|
|
0
|
return $inner_self->$method(@arguments); |
59
|
|
|
|
|
|
|
} |
60
|
0
|
|
|
|
|
0
|
return $self; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Variable; |
65
|
37
|
|
|
37
|
|
306
|
use base 'WWW::Shopify::Liquid::Token::Operand'; |
|
37
|
|
|
|
|
102
|
|
|
37
|
|
|
|
|
7404
|
|
66
|
|
|
|
|
|
|
|
67
|
37
|
|
|
37
|
|
305
|
use Scalar::Util qw(looks_like_number reftype blessed); |
|
37
|
|
|
|
|
103
|
|
|
37
|
|
|
|
|
27500
|
|
68
|
|
|
|
|
|
|
|
69
|
1289
|
|
|
1289
|
|
2819
|
sub new { my $package = shift; return bless { line => shift, core => [@_] }, $package; }; |
|
1289
|
|
|
|
|
7391
|
|
70
|
|
|
|
|
|
|
sub process { |
71
|
2224
|
|
|
2224
|
|
6125
|
my ($self, $hash, $action, $pipeline) = @_; |
72
|
2224
|
|
|
|
|
4425
|
my $place = $hash; |
73
|
|
|
|
|
|
|
|
74
|
2224
|
|
|
|
|
3988
|
my @inner = @{$self->{core}}; |
|
2224
|
|
|
|
|
7164
|
|
75
|
2224
|
|
|
|
|
4939
|
my $unprocessed = 0; |
76
|
2224
|
|
|
|
|
7427
|
foreach my $part_idx (0..$#inner) { |
77
|
3071
|
|
|
|
|
6407
|
my $part = $inner[$part_idx]; |
78
|
3071
|
100
|
|
|
|
10632
|
if (ref($part) eq 'WWW::Shopify::Liquid::Token::Variable::Processing') { |
79
|
33
|
|
|
|
|
153
|
$place = $part->$action($pipeline, $hash, $place); |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
else { |
82
|
3038
|
100
|
|
|
|
8706
|
my $key = $self->is_processed($part) ? $part : $part->$action($pipeline, $hash); |
83
|
|
|
|
|
|
|
|
84
|
3038
|
50
|
33
|
|
|
14106
|
return $self unless defined $key && $key ne ''; |
85
|
3038
|
100
|
100
|
|
|
8785
|
$self->{core}->[$part_idx] = $key if $self->is_processed($key) && $action eq "optimize"; |
86
|
3038
|
100
|
|
|
|
9705
|
if (defined $place) { |
87
|
2947
|
100
|
66
|
|
|
24971
|
if (blessed($place) && $place->isa('WWW::Shopify::Liquid::Resolver')) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
50
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
88
|
2
|
|
|
|
|
6
|
$place = $place->resolver->($place, $hash, $key); |
89
|
|
|
|
|
|
|
} elsif (reftype($place) && reftype($place) eq "HASH" && exists $place->{$key}) { |
90
|
2747
|
|
|
|
|
9172
|
$place = $place->{$key}; |
91
|
|
|
|
|
|
|
} elsif (reftype($place) && reftype($place) eq "ARRAY" && looks_like_number($key) && defined $place->[$key]) { |
92
|
21
|
|
|
|
|
60
|
$place = $place->[$key]; |
93
|
|
|
|
|
|
|
} elsif ($pipeline->make_method_calls && blessed($place) && $place->can($key)) { |
94
|
0
|
|
|
|
|
0
|
$place = $place->$key; |
95
|
|
|
|
|
|
|
} else { |
96
|
177
|
|
|
|
|
347
|
$unprocessed = 1; |
97
|
177
|
|
|
|
|
472
|
$place = undef; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
} |
103
|
2224
|
100
|
|
|
|
6776
|
return $self if $unprocessed; |
104
|
2047
|
100
|
100
|
|
|
7025
|
return $place->resolver->($place, $hash) if (blessed($place) && $place->isa('WWW::Shopify::Liquid::Resolver')); |
105
|
2046
|
|
|
|
|
8361
|
return $place; |
106
|
|
|
|
|
|
|
} |
107
|
1
|
|
|
1
|
|
2
|
sub stringify { return join(".", map { $_->stringify } @{$_[0]->{core}}); } |
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
4
|
|
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub set { |
110
|
0
|
|
|
0
|
|
0
|
my ($self, $pipeline, $hash, $value) = @_; |
111
|
0
|
0
|
|
|
|
0
|
my @vars = map { $self->is_processed($_) ? $_ : $_->render($pipeline, $hash) } @{$self->{core}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
112
|
0
|
|
|
|
|
0
|
my ($reference) = $pipeline->variable_reference($hash, \@vars); |
113
|
0
|
|
|
|
|
0
|
$$reference = $value; |
114
|
0
|
|
|
|
|
0
|
return 1; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub get { |
119
|
0
|
|
|
0
|
|
0
|
my ($self, $pipeline, $hash) = @_; |
120
|
0
|
0
|
|
|
|
0
|
my @vars = map { $self->is_processed($_) ? $_ : $_->render($pipeline, $hash) } @{$self->{core}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
121
|
0
|
|
|
|
|
0
|
my ($reference) = $pipeline->variable_reference($hash, \@vars, 1); |
122
|
0
|
0
|
|
|
|
0
|
return $reference ? $$reference : undef; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Variable::Processing; |
126
|
37
|
|
|
37
|
|
329
|
use base 'WWW::Shopify::Liquid::Token::Operand'; |
|
37
|
|
|
|
|
119
|
|
|
37
|
|
|
|
|
11764
|
|
127
|
|
|
|
|
|
|
sub process { |
128
|
33
|
|
|
33
|
|
95
|
my ($self, $hash, $argument, $action, $pipeline) = @_; |
129
|
33
|
50
|
|
|
|
106
|
return $self if !$self->is_processed($argument); |
130
|
33
|
|
|
|
|
243
|
my $result = $self->{core}->operate($hash, $argument); |
131
|
33
|
50
|
|
|
|
103
|
return $self if !$self->is_processed($result); |
132
|
33
|
|
|
|
|
104
|
return $result; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Variable::Named; |
136
|
37
|
|
|
37
|
|
306
|
use base 'WWW::Shopify::Liquid::Token::Operand'; |
|
37
|
|
|
|
|
104
|
|
|
37
|
|
|
|
|
10467
|
|
137
|
|
|
|
|
|
|
|
138
|
18
|
|
|
18
|
|
42
|
sub new { my $package = shift; return bless { line => shift, name => shift, core => shift }, $package; }; |
|
18
|
|
|
|
|
85
|
|
139
|
|
|
|
|
|
|
sub process { |
140
|
2
|
|
|
2
|
|
6
|
my ($self, $hash, $action, $pipeline) = @_; |
141
|
2
|
|
|
|
|
8
|
return { $self->{name} => $self->{core}->$action($pipeline, $hash) }; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Grouping; |
146
|
37
|
|
|
37
|
|
293
|
use base 'WWW::Shopify::Liquid::Token::Operand'; |
|
37
|
|
|
|
|
100
|
|
|
37
|
|
|
|
|
9642
|
|
147
|
86
|
|
|
86
|
|
205
|
sub new { my $package = shift; return bless { line => shift, members => [@_] }, $package; }; |
|
86
|
|
|
|
|
526
|
|
148
|
74
|
|
|
74
|
|
166
|
sub members { return @{$_[0]->{members}}; } |
|
74
|
|
|
|
|
611
|
|
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# Parentheses |
151
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Grouping::Parenthetical; |
152
|
37
|
|
|
37
|
|
309
|
use base 'WWW::Shopify::Liquid::Token::Grouping'; |
|
37
|
|
|
|
|
103
|
|
|
37
|
|
|
|
|
9026
|
|
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# Like a grouping, but not really. |
155
|
|
|
|
|
|
|
# Square brackets |
156
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Array; |
157
|
37
|
|
|
37
|
|
306
|
use base 'WWW::Shopify::Liquid::Token::Operand'; |
|
37
|
|
|
|
|
104
|
|
|
37
|
|
|
|
|
21134
|
|
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
sub new { |
160
|
7
|
|
|
7
|
|
28
|
my ($package, $line, @members) = @_; |
161
|
|
|
|
|
|
|
# Check to see whether or not the incoming member array is separated by commas. |
162
|
|
|
|
|
|
|
# Should never begin with a comma, should never end with a comma, should always be |
163
|
|
|
|
|
|
|
# 101010101 in terms of data and separators. If this is not the case, then we |
164
|
|
|
|
|
|
|
# Should throw a lexing exception. |
165
|
|
|
|
|
|
|
die new WWW::Shopify::Liquid::Exception::Lexer::InvalidSeparator($line) unless |
166
|
16
|
100
|
|
|
|
103
|
int(grep { ($_ % 2) == 0 && $members[$_]->isa('WWW::Shopify::Liquid::Token::Separator') } (0..$#members)) == 0 && |
167
|
7
|
100
|
33
|
|
|
42
|
int(grep { ($_ % 2) == 1 && (!$members[$_]->isa('WWW::Shopify::Liquid::Token::Separator') || $members[$_]->{core} ne ",") } (0..$#members)) == 0; |
|
16
|
50
|
33
|
|
|
104
|
|
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
my $self = bless { |
170
|
|
|
|
|
|
|
line => $line, |
171
|
7
|
|
|
|
|
32
|
members => [grep { !$_->isa('WWW::Shopify::Liquid::Token::Separator') } @members] |
|
16
|
|
|
|
|
73
|
|
172
|
|
|
|
|
|
|
}, $package; |
173
|
7
|
|
|
|
|
44
|
return $self; |
174
|
|
|
|
|
|
|
}; |
175
|
|
|
|
|
|
|
|
176
|
6
|
|
|
6
|
|
13
|
sub members { return @{$_[0]->{members}}; } |
|
6
|
|
|
|
|
20
|
|
177
|
|
|
|
|
|
|
sub process { |
178
|
3
|
|
|
3
|
|
12
|
my ($self, $hash, $action, $pipeline) = @_; |
179
|
3
|
|
|
|
|
9
|
my @members = $self->members; |
180
|
3
|
|
|
|
|
12
|
$members[$_] = $members[$_]->$action($pipeline, $hash) for (grep { !$self->is_processed($members[$_]) } (0..$#members)); |
|
8
|
|
|
|
|
30
|
|
181
|
3
|
50
|
|
|
|
12
|
if ($action eq "optimize") { |
182
|
0
|
|
|
|
|
0
|
$self->{members}->[$_] = $_ for (grep { $self->is_processed($members[$_]) } 0..$#members); |
|
0
|
|
|
|
|
0
|
|
183
|
|
|
|
|
|
|
} |
184
|
3
|
|
|
|
|
15
|
return [@members]; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# Curly brackets |
188
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Hash; |
189
|
37
|
|
|
37
|
|
322
|
use base 'WWW::Shopify::Liquid::Token::Operand'; |
|
37
|
|
|
|
|
115
|
|
|
37
|
|
|
|
|
23944
|
|
190
|
|
|
|
|
|
|
|
191
|
16
|
|
|
16
|
|
27
|
sub members { return @{$_[0]->{members}}; } |
|
16
|
|
|
|
|
54
|
|
192
|
|
|
|
|
|
|
sub new { |
193
|
14
|
|
|
14
|
|
48
|
my ($package, $line, @members) = @_; |
194
|
|
|
|
|
|
|
|
195
|
14
|
|
|
|
|
32
|
@members = map { $_->isa('WWW::Shopify::Liquid::Token::Variable::Named') ? ( |
196
|
|
|
|
|
|
|
WWW::Shopify::Liquid::Token::String->new($_->{line}, $_->{name}), |
197
|
|
|
|
|
|
|
WWW::Shopify::Liquid::Token::Separator->new($_->{line}, ':'), |
198
|
|
|
|
|
|
|
$_->{core} |
199
|
32
|
100
|
|
|
|
139
|
) : $_ } @members; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
die new WWW::Shopify::Liquid::Exception::Lexer::InvalidSeparator($line) unless |
202
|
48
|
100
|
|
|
|
206
|
int(grep { ($_ % 2) == 0 && $members[$_]->isa('WWW::Shopify::Liquid::Token::Separator') } (0..$#members)) == 0 && |
203
|
|
|
|
|
|
|
int(grep { |
204
|
|
|
|
|
|
|
($_ % 4) == 1 && (!$members[$_]->isa('WWW::Shopify::Liquid::Token::Separator') || $members[$_]->{core} ne ":") || |
205
|
48
|
50
|
33
|
|
|
251
|
($_ % 4) == 3 && (!$members[$_]->isa('WWW::Shopify::Liquid::Token::Separator') || $members[$_]->{core} ne ",") |
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
66
|
|
|
|
|
206
|
|
|
|
|
|
|
} (0..$#members)) == 0 && |
207
|
14
|
50
|
33
|
|
|
91
|
int(grep { !$_->isa('WWW::Shopify::Liquid::Token::Separator') } @members) % 2 == 0; |
|
48
|
|
33
|
|
|
118
|
|
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
return bless { |
210
|
|
|
|
|
|
|
line => $line, |
211
|
14
|
|
|
|
|
55
|
members => [grep { !$_->isa('WWW::Shopify::Liquid::Token::Separator') } @members] |
|
48
|
|
|
|
|
148
|
|
212
|
|
|
|
|
|
|
}, $package; |
213
|
|
|
|
|
|
|
}; |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
sub process { |
216
|
4
|
|
|
4
|
|
11
|
my ($self, $hash, $action, $pipeline) = @_; |
217
|
4
|
|
|
|
|
13
|
my @members = $self->members; |
218
|
4
|
|
|
|
|
16
|
$members[$_] = $members[$_]->$action($pipeline, $hash) for (grep { !$self->is_processed($members[$_]) } (0..$#members)); |
|
10
|
|
|
|
|
22
|
|
219
|
4
|
50
|
|
|
|
15
|
if ($action eq "optimize") { |
220
|
0
|
|
|
|
|
0
|
$self->{members}->[$_] = $_ for (grep { $self->is_processed($members[$_]) } 0..$#members); |
|
0
|
|
|
|
|
0
|
|
221
|
|
|
|
|
|
|
} |
222
|
4
|
|
|
|
|
18
|
return { @members }; |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Text; |
227
|
37
|
|
|
37
|
|
310
|
use base 'WWW::Shopify::Liquid::Token::Operand'; |
|
37
|
|
|
|
|
100
|
|
|
37
|
|
|
|
|
12204
|
|
228
|
|
|
|
|
|
|
sub new { |
229
|
797
|
|
|
797
|
|
3173
|
my $self = { line => $_[1], core => $_[2] }; |
230
|
797
|
|
|
|
|
1621
|
my $package = $_[0]; |
231
|
797
|
100
|
66
|
|
|
5237
|
$package = 'WWW::Shopify::Liquid::Token::Text::Whitespace' if !defined $_[2] || $_[2] =~ m/^\s*$/; |
232
|
797
|
|
|
|
|
2894
|
return bless $self, $package; |
233
|
|
|
|
|
|
|
}; |
234
|
259
|
|
|
259
|
|
761
|
sub process { my ($self, $hash) = @_; return $self->{core}; } |
|
259
|
|
|
|
|
1042
|
|
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Text::Whitespace; |
237
|
37
|
|
|
37
|
|
309
|
use base 'WWW::Shopify::Liquid::Token::Text'; |
|
37
|
|
|
|
|
107
|
|
|
37
|
|
|
|
|
9107
|
|
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Tag; |
240
|
37
|
|
|
37
|
|
305
|
use base 'WWW::Shopify::Liquid::Token'; |
|
37
|
|
|
|
|
95
|
|
|
37
|
|
|
|
|
12148
|
|
241
|
1113
|
|
|
1113
|
|
8537
|
sub new { return bless { line => $_[1], tag => $_[2], arguments => $_[3], strip_left => $_[4], strip_right => $_[5] }, $_[0] }; |
242
|
6105
|
|
|
6105
|
|
26982
|
sub tag { return $_[0]->{tag}; } |
243
|
11
|
|
|
11
|
|
37
|
sub stringify { return $_[0]->tag; } |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Output; |
246
|
37
|
|
|
37
|
|
314
|
use base 'WWW::Shopify::Liquid::Token'; |
|
37
|
|
|
|
|
108
|
|
|
37
|
|
|
|
|
8699
|
|
247
|
389
|
|
|
389
|
|
2360
|
sub new { return bless { line => $_[1], core => $_[2], strip_left => $_[3], strip_right => $_[4] }, $_[0]; }; |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Token::Separator; |
250
|
37
|
|
|
37
|
|
300
|
use base 'WWW::Shopify::Liquid::Token'; |
|
37
|
|
|
|
|
108
|
|
|
37
|
|
|
|
|
7256
|
|
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Lexer; |
254
|
37
|
|
|
37
|
|
314
|
use base 'WWW::Shopify::Liquid::Pipeline'; |
|
37
|
|
|
|
|
104
|
|
|
37
|
|
|
|
|
4182
|
|
255
|
37
|
|
|
37
|
|
298
|
use Scalar::Util qw(looks_like_number blessed); |
|
37
|
|
|
|
|
98
|
|
|
37
|
|
|
|
|
42849
|
|
256
|
|
|
|
|
|
|
|
257
|
85
|
|
|
85
|
0
|
1292
|
sub new { return bless { operators => {}, lexing_halters => {}, transparent_filters => {}, unparse_spaces => 0, parse_escaped_characters => 1 }, $_[0]; } |
258
|
3776
|
|
|
3776
|
0
|
22202
|
sub operators { return $_[0]->{operators}; } |
259
|
461
|
100
|
|
461
|
0
|
1123
|
sub unparse_spaces { $_[0]->{unparse_spaces} = $_[1] if defined $_[1]; return $_[0]->{unparse_spaces}; } |
|
461
|
|
|
|
|
1250
|
|
260
|
286
|
100
|
|
286
|
0
|
1944
|
sub parse_escaped_characters { $_[0]->{parse_escaped_characters} = $_[1] if defined $_[1]; return $_[0]->{parse_escaped_characters}; } |
|
286
|
|
|
|
|
912
|
|
261
|
2380
|
|
|
2380
|
0
|
10136
|
sub register_operator { $_[0]->{operators}->{$_} = $_[1] for ($_[1]->symbol); } |
262
|
|
|
|
|
|
|
sub register_tag { |
263
|
1801
|
|
|
1801
|
0
|
4207
|
my ($self, $package) = @_; |
264
|
1801
|
100
|
100
|
|
|
6557
|
$self->{lexing_halters}->{$package->name} = $package if $package->is_enclosing && $package->inner_halt_lexing; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
sub register_filter { |
267
|
5226
|
|
|
5226
|
0
|
12333
|
my ($self, $package) = @_; |
268
|
5226
|
100
|
|
|
|
47471
|
$self->{transparent_filters}->{$package->name} = $package if ($package->transparent); |
269
|
|
|
|
|
|
|
} |
270
|
1714
|
|
|
1714
|
0
|
8405
|
sub transparent_filters { return $_[0]->{transparent_filters}; } |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
sub parse_token { |
273
|
2741
|
|
|
2741
|
0
|
7250
|
my ($self, $line, $token) = @_; |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
# Strip token of whitespace. |
276
|
2741
|
50
|
|
|
|
6974
|
return undef unless defined $token; |
277
|
2741
|
|
|
|
|
16712
|
$token =~ s/^\s*(.*?)\s*$/$1/; |
278
|
2741
|
100
|
|
|
|
7595
|
return WWW::Shopify::Liquid::Token::Operator->new($line, $token) if $self->operators->{$token}; |
279
|
2037
|
100
|
100
|
|
|
9378
|
return WWW::Shopify::Liquid::Token::String->new($line, do { |
280
|
285
|
|
|
|
|
800
|
my $string = $1; |
281
|
285
|
100
|
|
|
|
906
|
if ($self->parse_escaped_characters) { |
282
|
284
|
|
|
|
|
764
|
$string =~ s/\\r/\r/g; |
283
|
284
|
|
|
|
|
565
|
$string =~ s/\\n/\n/g; |
284
|
284
|
|
|
|
|
617
|
$string =~ s/\\t/\t/g; |
285
|
|
|
|
|
|
|
} |
286
|
285
|
|
|
|
|
1154
|
$string; |
287
|
|
|
|
|
|
|
}) if $token =~ m/^'(.*)'$/s || $token =~ m/^"(.*)"$/s; |
288
|
1752
|
100
|
|
|
|
8652
|
return WWW::Shopify::Liquid::Token::Number->new($line, $1) if looks_like_number($token); |
289
|
1476
|
100
|
66
|
|
|
5865
|
return WWW::Shopify::Liquid::Token::NULL->new() if $token eq '' || $token eq 'null'; |
290
|
1465
|
100
|
100
|
|
|
7286
|
return WWW::Shopify::Liquid::Token::Separator->new($line, $token) if ($token eq ":" || $token eq "," || $token eq "."); |
|
|
|
66
|
|
|
|
|
291
|
1280
|
100
|
|
|
|
2959
|
return WWW::Shopify::Liquid::Token::Array->new($line) if ($token eq "[]"); |
292
|
1277
|
100
|
|
|
|
2848
|
return WWW::Shopify::Liquid::Token::Hash->new($line) if ($token eq "{}"); |
293
|
|
|
|
|
|
|
# We're a variable. Let's see what's going on. Split along non quoted . and [ ] fields. |
294
|
1271
|
|
|
|
|
3084
|
my ($squot, $dquot, $start, @parts) = (0,0,0); |
295
|
|
|
|
|
|
|
# customer['test']['b'] |
296
|
1271
|
|
|
|
|
2137
|
my $open_square_bracket = 0; |
297
|
1271
|
|
|
|
|
2046
|
my $open_curly_bracket = 0; |
298
|
1271
|
|
|
|
|
8529
|
while ($token =~ m/(\.|\[|\]|\{|\}|(?<!\\)\"|(?<!\\)\'|\b$)/g) { |
299
|
1863
|
|
|
|
|
4510
|
my $sym = $&; |
300
|
1863
|
|
|
|
|
4563
|
my $begin = $-[0]; |
301
|
1863
|
|
|
|
|
4532
|
my $end = $+[0]; |
302
|
1863
|
50
|
33
|
|
|
7068
|
if (!$squot && !$dquot) { |
303
|
1863
|
100
|
100
|
|
|
5397
|
$open_square_bracket-- if ($sym && $sym eq "]"); |
304
|
1863
|
100
|
100
|
|
|
4860
|
$open_curly_bracket-- if ($sym && $sym eq "}"); |
305
|
1863
|
100
|
100
|
|
|
16868
|
if (($sym eq "." || $sym eq "]" || $sym eq "[" || $sym eq "{" || $sym eq "}" || !$sym) && $open_square_bracket == 0 && $open_curly_bracket == 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
306
|
1773
|
|
|
|
|
4459
|
my $contents = substr($token, $start, $begin - $start); |
307
|
|
|
|
|
|
|
|
308
|
1773
|
100
|
66
|
|
|
8345
|
if (defined $contents && $contents !~ m/^\s*$/) { |
309
|
1743
|
|
|
|
|
3518
|
my @variables = (); |
310
|
1743
|
100
|
100
|
|
|
6475
|
if (!$sym || $sym eq "." || $sym eq "[") { |
|
|
100
|
100
|
|
|
|
|
|
|
50
|
|
|
|
|
|
311
|
1677
|
100
|
|
|
|
4628
|
@variables = $self->transparent_filters->{$contents} ? WWW::Shopify::Liquid::Token::Variable::Processing->new($line, $self->transparent_filters->{$contents}) : WWW::Shopify::Liquid::Token::String->new($line, $contents); |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
elsif ($sym eq "]") { |
314
|
58
|
|
|
|
|
242
|
@variables = $self->parse_expression($line, $contents); |
315
|
58
|
100
|
|
|
|
213
|
return WWW::Shopify::Liquid::Token::Array->new($line, @variables) if (int(@parts) == 0); |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
elsif ($sym eq "}") { |
318
|
8
|
|
|
|
|
45
|
@variables = $self->parse_expression($line, $contents); |
319
|
8
|
50
|
|
|
|
50
|
return WWW::Shopify::Liquid::Token::Hash->new($line, @variables) if (int(@parts) == 0); |
320
|
|
|
|
|
|
|
} |
321
|
1731
|
50
|
|
|
|
5058
|
if (int(@variables) > 0) { |
322
|
1731
|
100
|
|
|
|
3785
|
if (int(@variables) == 1) { |
323
|
1718
|
|
|
|
|
4009
|
push(@parts, @variables); |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
else { |
326
|
13
|
|
|
|
|
48
|
push(@parts, WWW::Shopify::Liquid::Token::Grouping->new($line, @variables)) ; |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
} |
331
|
1851
|
100
|
100
|
|
|
11581
|
$start = $end if $sym ne '"' && $sym ne "'" && !$open_curly_bracket && !$open_square_bracket; |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
332
|
1851
|
100
|
100
|
|
|
5472
|
$open_square_bracket++ if ($sym && $sym eq "["); |
333
|
1851
|
100
|
100
|
|
|
4840
|
$open_curly_bracket++ if ($sym && $sym eq "{"); |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
} |
336
|
1851
|
50
|
|
|
|
3739
|
$squot = !$squot if $token eq "'"; |
337
|
1851
|
50
|
|
|
|
10523
|
$dquot = !$dquot if $token eq '"'; |
338
|
|
|
|
|
|
|
} |
339
|
1259
|
|
|
|
|
4621
|
return WWW::Shopify::Liquid::Token::Variable->new($line, @parts); |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
37
|
|
|
37
|
|
372
|
use utf8; |
|
37
|
|
|
|
|
104
|
|
|
37
|
|
|
|
|
404
|
|
343
|
|
|
|
|
|
|
# Returns a single token repsending the whole a expression. |
344
|
|
|
|
|
|
|
sub parse_expression { |
345
|
1458
|
|
|
1458
|
0
|
4665
|
my ($self, $line, $exp) = @_; |
346
|
1458
|
100
|
66
|
|
|
7256
|
return () if !defined $exp || $exp eq ''; |
347
|
1035
|
|
|
|
|
2050
|
my @tokens = (); |
348
|
1035
|
|
|
|
|
2945
|
my ($start_paren, $start_space, $level, $squot, $dquot, $start_sq, $sq_level, $start_hsh, $hsh_level) = (undef, 0, 0, 0, 0, undef, 0, undef, 0); |
349
|
|
|
|
|
|
|
# We regex along parentheses, quotation marks (both kinds), whitespace, and non-word-operators. |
350
|
|
|
|
|
|
|
# We sort along length, so that we make sure to get all the largest operators first, so that way if a larger operator is made from a smaller one (=, ==) |
351
|
|
|
|
|
|
|
# There's no confusion, we always try to match the largest first. |
352
|
1035
|
|
|
|
|
1956
|
my $non_word_operators = join("|", map { quotemeta($_) } grep { $_ =~ m/^\W+$/; } sort { length($b) <=> length($a) } keys(%{$self->operators})); |
|
24840
|
|
|
|
|
47691
|
|
|
32085
|
|
|
|
|
79502
|
|
|
111976
|
|
|
|
|
158069
|
|
|
1035
|
|
|
|
|
2706
|
|
353
|
1035
|
|
|
|
|
24168
|
while ($exp =~ m/(?:\(|\)|\]|\[|\}|\{|(?<!\\)["ââ]|(?<!\\)['ââ]|(\s+|$)|($non_word_operators|,|:))/sg) { |
354
|
5776
|
|
|
|
|
28217
|
my ($rs, $re, $rc, $whitespace, $nword_op) = ($-[0], $+[0], $&, $1, $2); |
355
|
|
|
|
|
|
|
# Specifically to allow variables to have a - in them, and be treated as a long literal, instead of a minus sign. |
356
|
|
|
|
|
|
|
# This is terrible behaviour, but mimics Shopify's lexer. |
357
|
|
|
|
|
|
|
# Only if of course the entire first half of this ISN'T a number, though. 'cause that'd be insane. |
358
|
5776
|
100
|
100
|
|
|
19759
|
next if $nword_op && $nword_op eq "-" && $rs > 0 && substr($exp, $rs-1, 1) ne " " && substr($exp, 0, $rs) !~ m/\b\d+$/; |
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
359
|
5728
|
100
|
100
|
|
|
19904
|
if (!$squot && !$dquot) { |
360
|
4932
|
100
|
100
|
|
|
11951
|
$start_paren = $re if $rc eq "(" && $level++ == 0; |
361
|
4932
|
100
|
100
|
|
|
10872
|
$start_sq = $re if $rc eq "[" && $sq_level++ == 0; |
362
|
4932
|
100
|
100
|
|
|
10759
|
$start_hsh = $re if $rc eq "{" && $hsh_level++ == 0; |
363
|
|
|
|
|
|
|
# Deal with parentheses; always the highest level of operation, except when inside a square bracket. |
364
|
4932
|
100
|
100
|
|
|
13605
|
if ($rc eq ")" && --$level == 0 && $sq_level == 0 && $hsh_level == 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
365
|
72
|
|
|
|
|
153
|
$start_space = $re; |
366
|
72
|
|
|
|
|
620
|
push(@tokens, WWW::Shopify::Liquid::Token::Grouping->new($line, $self->parse_expression($line, substr($exp, $start_paren, $rs - $start_paren)))); |
367
|
|
|
|
|
|
|
} |
368
|
4932
|
100
|
|
|
|
10155
|
--$sq_level if $rc eq "]"; |
369
|
4932
|
100
|
|
|
|
10005
|
--$hsh_level if $rc eq "}"; |
370
|
4932
|
100
|
100
|
|
|
23606
|
if (($level == 0 || ($rc eq "(" && $level == 1)) && $sq_level == 0 && $hsh_level == 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
371
|
|
|
|
|
|
|
# If we're only spaces, that means we're a new a token. |
372
|
4462
|
100
|
100
|
|
|
17112
|
if ($rc eq "(" || defined $whitespace || $nword_op) { |
|
|
|
100
|
|
|
|
|
373
|
4030
|
50
|
|
|
|
8573
|
if (defined $start_space) { |
374
|
4030
|
|
|
|
|
9863
|
my $contents = substr($exp, $start_space, $rs - $start_space); |
375
|
4030
|
100
|
|
|
|
21118
|
push(@tokens, $self->parse_token([$line->[0], $line->[1] + $start_space, $line->[2] + $start_space, $line->[4]], $contents)) if $contents !~ m/^\s*$/; |
376
|
|
|
|
|
|
|
} |
377
|
4030
|
100
|
|
|
|
11406
|
push(@tokens, $self->parse_token([$line->[0], $line->[1] + $start_space, $line->[2] + $start_space, $line->[4]], $nword_op)) if $nword_op; |
378
|
4030
|
|
|
|
|
7327
|
$start_space = $re; |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
} |
382
|
5728
|
100
|
100
|
|
|
13503
|
$squot = !$squot if ($rc eq "'" && !$dquot); |
383
|
5728
|
100
|
100
|
|
|
47477
|
$dquot = !$dquot if ($rc eq '"' && !$squot); |
384
|
|
|
|
|
|
|
} |
385
|
1035
|
50
|
|
|
|
3368
|
die WWW::Shopify::Liquid::Exception::Lexer::UnbalancedBrace->new($line) unless $level == 0; |
386
|
|
|
|
|
|
|
# Go through and combine any -1 from OP NUM to NUM. |
387
|
|
|
|
|
|
|
my @ids = grep { |
388
|
1035
|
|
|
|
|
2982
|
$tokens[$_]->isa('WWW::Shopify::Liquid::Token::Number') && |
389
|
1778
|
100
|
66
|
|
|
11760
|
$tokens[$_-1]->isa('WWW::Shopify::Liquid::Token::Operator') && $tokens[$_-1]->{core} eq "-" && |
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
390
|
|
|
|
|
|
|
($_ == 1 || $tokens[$_-2]->isa('WWW::Shopify::Liquid::Token::Separator') || $tokens[$_-2]->isa('WWW::Shopify::Liquid::Token::Operator')) |
391
|
|
|
|
|
|
|
} 1..$#tokens; |
392
|
1035
|
|
|
|
|
2878
|
for (@ids) { $tokens[$_]->{core} *= -1; $tokens[$_-1] = undef; } |
|
3
|
|
|
|
|
11
|
|
|
3
|
|
|
|
|
20
|
|
393
|
1035
|
|
|
|
|
2220
|
@tokens = grep { defined $_ } @tokens; |
|
2813
|
|
|
|
|
6811
|
|
394
|
|
|
|
|
|
|
# Go through and combine colon separated arguments into named arguments. |
395
|
|
|
|
|
|
|
@ids = grep { |
396
|
1035
|
|
|
|
|
2402
|
($_ == 2 || !$tokens[$_-3]->isa('WWW::Shopify::Liquid::Token::Operator') || $tokens[$_-3]->{core} ne "|") && |
397
|
573
|
|
|
|
|
6870
|
$tokens[$_-2]->isa('WWW::Shopify::Liquid::Token::Variable') && int(@{$tokens[$_-2]->{core}}) == 1 && $tokens[$_-2]->{core}->[0]->isa('WWW::Shopify::Liquid::Token::String') && |
398
|
1195
|
100
|
100
|
|
|
10491
|
$tokens[$_-1]->isa('WWW::Shopify::Liquid::Token::Separator') && $tokens[$_-1]->{core} eq ":" && |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
399
|
|
|
|
|
|
|
$tokens[$_]->isa('WWW::Shopify::Liquid::Token::Operand') |
400
|
|
|
|
|
|
|
} (2..$#tokens); |
401
|
1035
|
|
|
|
|
2584
|
for (@ids) { $tokens[$_] = WWW::Shopify::Liquid::Token::Variable::Named->new($line, $tokens[$_-2]->{core}->[0]->{core}, $tokens[$_]); $tokens[$_-2] = undef; $tokens[$_-1] = undef; } |
|
18
|
|
|
|
|
97
|
|
|
18
|
|
|
|
|
75
|
|
|
18
|
|
|
|
|
75
|
|
402
|
1035
|
|
|
|
|
1969
|
@tokens = grep { defined $_ } @tokens; |
|
2810
|
|
|
|
|
6167
|
|
403
|
1035
|
|
|
|
|
6169
|
return @tokens; |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
sub parse_text { |
407
|
362
|
|
|
362
|
0
|
225724
|
my ($self, $text) = @_; |
408
|
362
|
50
|
|
|
|
1425
|
return () unless defined $text; |
409
|
362
|
|
|
|
|
990
|
my @tokens = (); |
410
|
|
|
|
|
|
|
|
411
|
362
|
|
|
|
|
823
|
my $line = 1; |
412
|
362
|
|
|
|
|
773
|
my $line_position = 0; |
413
|
|
|
|
|
|
|
|
414
|
362
|
|
|
|
|
2357
|
my $lexing_halter; |
415
|
|
|
|
|
|
|
my $open_control_tag; |
416
|
362
|
|
|
|
|
0
|
my $open_output_tag; |
417
|
362
|
|
|
|
|
0
|
my $open_single_quote; |
418
|
362
|
|
|
|
|
0
|
my $open_double_quote; |
419
|
362
|
|
|
|
|
0
|
my $strip_left; |
420
|
|
|
|
|
|
|
|
421
|
362
|
|
|
|
|
728
|
my $end_offset = 0; |
422
|
362
|
|
|
|
|
1091
|
my $start_position = [1, 0, 0]; |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
# This is a substitution instead of a simple match, because very long perl native UTF8 strings, are variable length |
425
|
|
|
|
|
|
|
# meaning any substr, or index operations need to walk the string in order to complete. This is like an o(n^2) consequence |
426
|
|
|
|
|
|
|
# so it's fine at smaller lengths, but at larger lengths, it's infeasible to call substr on far offsets with any significant |
427
|
|
|
|
|
|
|
# frequency. So we eat the string as we process it. Possibly slightly slower than simple matching on byte-strings, but way |
428
|
|
|
|
|
|
|
# faster on UTF-8, and at this point in my life, I just want consistency rather than best-possible-performance (this would because |
429
|
|
|
|
|
|
|
# written in D -betterC if I was interested in best possible performance at this point.) |
430
|
362
|
|
|
|
|
904
|
my $accumulator = ''; |
431
|
|
|
|
|
|
|
# Step 1. We only care about new lines (to count what line we're on), {% and {{. |
432
|
362
|
|
|
|
|
722
|
my $count = 0; |
433
|
37
|
|
|
37
|
|
52878
|
use Time::HiRes qw(time); |
|
37
|
|
|
|
|
47432
|
|
|
37
|
|
|
|
|
210
|
|
434
|
362
|
|
|
|
|
1552
|
my $start = time; |
435
|
362
|
|
|
|
|
8485
|
while ($text =~ s/^(.*?)(?:(\{\{\-?)|({%\-?))//s) { |
436
|
1318
|
|
|
|
|
5055
|
$end_offset += $+[0]; |
437
|
|
|
|
|
|
|
# These variables are entirely boolean flags. |
438
|
1318
|
|
|
|
|
5016
|
my ($start_output_tag, $start_control_tag) = ($2, $3); |
439
|
1318
|
|
|
|
|
3627
|
$accumulator .= $1; |
440
|
1318
|
100
|
|
|
|
3559
|
if ($accumulator ne '') { |
441
|
|
|
|
|
|
|
# Count the number of lines in the accumulator, to ensure we have the approrpiate line position. |
442
|
541
|
|
|
|
|
1960
|
$line += ($accumulator =~ tr/\r?\n//); |
443
|
541
|
|
|
|
|
1611
|
$line_position = rindex($accumulator, "\n") + $start_position->[2] + 1; |
444
|
|
|
|
|
|
|
} |
445
|
1318
|
100
|
|
|
|
5865
|
$open_control_tag = [$line, $end_offset - length($start_control_tag) - $line_position, $end_offset - length($start_control_tag), $self->file_context] if $start_control_tag; |
446
|
1318
|
100
|
|
|
|
4546
|
$open_output_tag = [$line, $end_offset - length($start_output_tag) - $line_position, $end_offset - length($start_output_tag), $self->file_context] if $start_output_tag; |
447
|
1318
|
|
66
|
|
|
5015
|
$strip_left = index($start_control_tag || $start_output_tag, "-") != -1; |
448
|
|
|
|
|
|
|
|
449
|
1318
|
100
|
100
|
|
|
6022
|
$accumulator =~ s/^\s*// if int(@tokens) > 0 && $tokens[-1]->{strip_right}; |
450
|
1318
|
100
|
|
|
|
3311
|
$accumulator =~ s/\s*$// if $strip_left; |
451
|
1318
|
100
|
|
|
|
4324
|
if ($accumulator ne '') { |
452
|
|
|
|
|
|
|
# Count the number of lines in the accumulator. |
453
|
511
|
|
|
|
|
2144
|
push(@tokens, WWW::Shopify::Liquid::Token::Text->new($start_position, $accumulator)); |
454
|
511
|
|
|
|
|
1125
|
$accumulator = ''; |
455
|
|
|
|
|
|
|
} |
456
|
1318
|
50
|
|
|
|
3201
|
last if $text eq ''; |
457
|
1318
|
|
|
|
|
4053
|
$start_position = [$line, $end_offset - $line_position, $end_offset, $self->file_context]; |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
# Step 2. If we have an open tag, we parse out tokens from argument context inside that tag. |
460
|
1318
|
|
|
|
|
18951
|
while ($text =~ s/(.*?)(?:(\")|(\')|(\-?%})|(\-?\}\})|(\r?\n))//s) { |
461
|
1943
|
|
|
|
|
8332
|
my ($double_quote, $single_quote, $end_control_tag, $end_output_tag, $newline) = ($2, $3, $4, $5, $6); |
462
|
1943
|
|
|
|
|
5154
|
$end_offset += $+[0]; |
463
|
|
|
|
|
|
|
|
464
|
1943
|
100
|
100
|
|
|
12337
|
if (!$open_single_quote && !$open_double_quote && ($end_output_tag || $end_control_tag)) { |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
465
|
1318
|
|
66
|
|
|
4928
|
my $strip_right = index($end_control_tag || $end_output_tag, "-") != -1; |
466
|
1318
|
|
|
|
|
3666
|
$accumulator .= $1; |
467
|
1318
|
100
|
|
|
|
2940
|
if ($end_output_tag) { |
468
|
367
|
100
|
|
|
|
919
|
die new WWW::Shopify::Liquid::Exception::Lexer::UnbalancedControlTag($open_control_tag) if $open_control_tag; |
469
|
366
|
|
|
|
|
1320
|
push(@tokens, WWW::Shopify::Liquid::Token::Output->new($open_output_tag, [$self->parse_expression($start_position, $accumulator)], $strip_left, $strip_right)); |
470
|
366
|
|
|
|
|
923
|
$open_output_tag = undef; |
471
|
|
|
|
|
|
|
} else { |
472
|
951
|
50
|
|
|
|
2399
|
die new WWW::Shopify::Liquid::Exception::Lexer::UnbalancedOutputTag($open_output_tag) if $open_output_tag; |
473
|
951
|
50
|
|
|
|
5835
|
die new WWW::Shopify::Liquid::Exception::Lexer::Tag($start_position, $accumulator) if $accumulator !~ m/^\s*(\w+)\s*(.*?)\s*$/s; |
474
|
951
|
|
|
|
|
3392
|
push(@tokens, WWW::Shopify::Liquid::Token::Tag->new($open_control_tag, $1, [$self->parse_expression($start_position, $2)], $strip_left, $strip_right)); |
475
|
951
|
100
|
|
|
|
3659
|
$lexing_halter = $tokens[-1] if $self->{lexing_halters}->{$1}; |
476
|
951
|
|
|
|
|
1882
|
$open_control_tag = undef; |
477
|
|
|
|
|
|
|
} |
478
|
1317
|
|
|
|
|
2614
|
$accumulator = ''; |
479
|
1317
|
|
|
|
|
4738
|
$start_position = [$line, $end_offset - $line_position, $end_offset, $self->file_context]; |
480
|
1317
|
|
|
|
|
3159
|
last; |
481
|
|
|
|
|
|
|
} else { |
482
|
625
|
100
|
|
|
|
1510
|
if ($newline) { |
483
|
18
|
|
|
|
|
33
|
++$line; |
484
|
18
|
|
|
|
|
36
|
$line_position = $end_offset; |
485
|
|
|
|
|
|
|
} |
486
|
625
|
100
|
100
|
|
|
2005
|
$open_single_quote = !$open_single_quote if $single_quote && !$open_double_quote; |
487
|
625
|
100
|
100
|
|
|
2016
|
$open_double_quote = !$open_double_quote if $double_quote && !$open_single_quote; |
488
|
625
|
|
|
|
|
6115
|
$accumulator .= $&; |
489
|
|
|
|
|
|
|
} |
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
# For lexing halters, consume everything up to the next end tag explicitly. |
492
|
1317
|
100
|
|
|
|
15944
|
if ($lexing_halter) { |
493
|
11
|
|
|
|
|
25
|
my $core = $lexing_halter->{tag}; |
494
|
11
|
|
|
|
|
200
|
while ($text =~ s/(.*?)(?:({%\-?\s*end$core\s*\-?%})|(\r?\n))//s) { |
495
|
23
|
100
|
|
|
|
68
|
if ($3) { |
496
|
12
|
|
|
|
|
16
|
++$line; |
497
|
12
|
|
|
|
|
16
|
$line_position = $end_offset; |
498
|
12
|
|
|
|
|
75
|
$accumulator .= $1 . $3; |
499
|
|
|
|
|
|
|
} else { |
500
|
11
|
|
|
|
|
28
|
$accumulator .= $1; |
501
|
11
|
100
|
|
|
|
47
|
push(@tokens, WWW::Shopify::Liquid::Token::Text->new($start_position, $accumulator)) if $accumulator ne ''; |
502
|
11
|
|
|
|
|
53
|
push(@tokens, WWW::Shopify::Liquid::Token::Tag->new($start_position, "end$core", [])); |
503
|
11
|
|
|
|
|
29
|
$accumulator = ''; |
504
|
11
|
|
|
|
|
16
|
$lexing_halter = undef; |
505
|
11
|
|
|
|
|
49
|
last; |
506
|
|
|
|
|
|
|
} |
507
|
|
|
|
|
|
|
} |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
} |
510
|
361
|
50
|
|
|
|
1010
|
die new WWW::Shopify::Liquid::Exception::Lexer::UnbalancedSingleQuote($open_single_quote) if $open_single_quote; |
511
|
361
|
50
|
|
|
|
1042
|
die new WWW::Shopify::Liquid::Exception::Lexer::UnbalancedDoubleQuote($open_double_quote) if $open_double_quote; |
512
|
361
|
50
|
|
|
|
926
|
die new WWW::Shopify::Liquid::Exception::Lexer::UnbalancedLexingHalt($lexing_halter) if $lexing_halter; |
513
|
361
|
50
|
|
|
|
950
|
die new WWW::Shopify::Liquid::Exception::Lexer::UnbalancedControlTag($open_control_tag) if $open_control_tag; |
514
|
361
|
50
|
|
|
|
982
|
die new WWW::Shopify::Liquid::Exception::Lexer::UnbalancedOutputTag($open_output_tag) if $open_output_tag; |
515
|
361
|
|
|
|
|
999
|
$accumulator .= $text; |
516
|
361
|
100
|
100
|
|
|
2064
|
$accumulator =~ s/^\s*// if int(@tokens) > 0 && $tokens[-1]->{strip_right}; |
517
|
361
|
100
|
|
|
|
1272
|
push(@tokens, WWW::Shopify::Liquid::Token::Text->new($start_position, $accumulator)) if $accumulator ne ''; |
518
|
361
|
|
|
|
|
4762
|
return @tokens; |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
sub unparse_token { |
522
|
507
|
|
|
507
|
0
|
1375
|
my ($self, $token) = @_; |
523
|
507
|
50
|
|
|
|
1177
|
return "null" if !defined $token; |
524
|
507
|
50
|
|
|
|
1588
|
return '' if $token eq ''; |
525
|
507
|
50
|
66
|
|
|
1854
|
return "'" . do { $token =~ s/'/\\'/g; $token } . "'" if !blessed($token) && !looks_like_number($token); |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
8
|
|
526
|
506
|
50
|
|
|
|
1767
|
return $token unless blessed($token); |
527
|
506
|
100
|
|
|
|
2137
|
return "null" if $token->isa('WWW::Shopify::Liquid::Token::NULL'); |
528
|
501
|
100
|
|
|
|
1730
|
return '{}' if ($token->isa('WWW::Shopify::Liquid::Token::Hash')); |
529
|
500
|
50
|
|
|
|
1658
|
return '[]' if ($token->isa('WWW::Shopify::Liquid::Token::Array')); |
530
|
|
|
|
|
|
|
sub translate_variable { |
531
|
215
|
|
|
215
|
0
|
571
|
my ($self, $token) = @_; |
532
|
|
|
|
|
|
|
my $variable = join(".", map { |
533
|
|
|
|
|
|
|
!$self->is_processed($_) ? ( |
534
|
|
|
|
|
|
|
$_->isa('WWW::Shopify::Liquid::Token::Variable') ? ('[' . translate_variable($self, $_) . ']') : |
535
|
|
|
|
|
|
|
($_->isa('WWW::Shopify::Liquid::Token::Variable::Processing') ? $_->{core}->name : $_->{core}) |
536
|
273
|
100
|
|
|
|
950
|
) : $_ |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
537
|
215
|
|
|
|
|
385
|
} @{$token->{core}}); |
|
215
|
|
|
|
|
670
|
|
538
|
215
|
|
|
|
|
740
|
$variable =~ s/\.\[/\[/g; |
539
|
215
|
|
|
|
|
782
|
return $variable; |
540
|
|
|
|
|
|
|
} |
541
|
500
|
100
|
|
|
|
1738
|
return $token->{name} . ":" . $self->unparse_token($token->{core}) if ($token->isa('WWW::Shopify::Liquid::Token::Variable::Named')); |
542
|
499
|
100
|
|
|
|
1847
|
return translate_variable($self, $token) if $token->isa('WWW::Shopify::Liquid::Token::Variable'); |
543
|
285
|
100
|
|
|
|
984
|
return "(" . join("", map { $self->unparse_token($_); } @{$token->{members}}) . ")" if $token->isa('WWW::Shopify::Liquid::Token::Grouping'); |
|
3
|
|
|
|
|
17
|
|
|
1
|
|
|
|
|
3
|
|
544
|
284
|
100
|
|
|
|
1321
|
return "'" . $token->{core} . "'" if $token->isa('WWW::Shopify::Liquid::Token::String'); |
545
|
214
|
|
|
|
|
837
|
return $token->{core}; |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
sub unparse_expression { |
549
|
121
|
|
|
121
|
0
|
372
|
my ($self, @tokens) = @_; |
550
|
121
|
100
|
100
|
|
|
314
|
my $a = join("", map { ($_ eq ":" || $_ eq ",") ? $_ : " " . $_; } grep { defined $_ } map { $self->unparse_token($_) } @tokens); |
|
503
|
|
|
|
|
2551
|
|
|
503
|
|
|
|
|
1402
|
|
|
503
|
|
|
|
|
1306
|
|
551
|
121
|
|
|
|
|
662
|
$a =~ s/^ //; |
552
|
121
|
|
|
|
|
656
|
return $a; |
553
|
|
|
|
|
|
|
} |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
sub unparse_text_segment { |
556
|
454
|
|
|
454
|
0
|
1352
|
my ($self, $token) = @_; |
557
|
454
|
100
|
|
|
|
1029
|
my $space = $self->unparse_spaces ? " " : ""; |
558
|
454
|
100
|
|
|
|
1526
|
return $token if $self->is_processed($token); |
559
|
428
|
100
|
|
|
|
2200
|
if ($token->isa('WWW::Shopify::Liquid::Token::Tag')) { |
560
|
151
|
100
|
66
|
|
|
736
|
return "{%" . $space . $token->{tag} . $space . "%}" if !$token->{arguments} || int(@{$token->{arguments}}) == 0; |
|
97
|
|
|
|
|
403
|
|
561
|
97
|
|
|
|
|
366
|
return "{%" . $space . $token->{tag} . " " . $self->unparse_expression(@{$token->{arguments}}) . $space . "%}"; |
|
97
|
|
|
|
|
382
|
|
562
|
|
|
|
|
|
|
} |
563
|
277
|
100
|
|
|
|
1103
|
return "{{" . $space . $self->unparse_expression(@{$token->{core}}) . $space . "}}" if $token->isa('WWW::Shopify::Liquid::Token::Output'); |
|
24
|
|
|
|
|
116
|
|
564
|
253
|
|
|
|
|
988
|
return $token->{core}; |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
sub unparse_text { |
568
|
25
|
|
|
25
|
0
|
208
|
my ($self, @tokens) = @_; |
569
|
25
|
|
|
|
|
90
|
return join('', grep { defined $_ } map { $self->unparse_text_segment($_) } @tokens); |
|
454
|
|
|
|
|
1225
|
|
|
454
|
|
|
|
|
1224
|
|
570
|
|
|
|
|
|
|
} |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
1; |