line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#!/usr/bin/perl |
2
|
|
|
|
|
|
|
|
3
|
21
|
|
|
21
|
|
108
|
use strict; |
|
21
|
|
|
|
|
31
|
|
|
21
|
|
|
|
|
815
|
|
4
|
21
|
|
|
21
|
|
102
|
use warnings; |
|
21
|
|
|
|
|
31
|
|
|
21
|
|
|
|
|
832
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package WWW::Shopify::Liquid::Parser; |
7
|
21
|
|
|
21
|
|
111
|
use base 'WWW::Shopify::Liquid::Pipeline'; |
|
21
|
|
|
|
|
35
|
|
|
21
|
|
|
|
|
7892
|
|
8
|
21
|
|
|
21
|
|
129
|
use Module::Find; |
|
21
|
|
|
|
|
65
|
|
|
21
|
|
|
|
|
1438
|
|
9
|
21
|
|
|
21
|
|
115
|
use List::MoreUtils qw(firstidx part); |
|
21
|
|
|
|
|
35
|
|
|
21
|
|
|
|
|
1169
|
|
10
|
21
|
|
|
21
|
|
113
|
use List::Util qw(first); |
|
21
|
|
|
|
|
412
|
|
|
21
|
|
|
|
|
1301
|
|
11
|
21
|
|
|
21
|
|
10184
|
use WWW::Shopify::Liquid::Exception; |
|
21
|
|
|
|
|
61
|
|
|
21
|
|
|
|
|
16598
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
useall WWW::Shopify::Liquid::Operator; |
14
|
|
|
|
|
|
|
useall WWW::Shopify::Liquid::Tag; |
15
|
|
|
|
|
|
|
useall WWW::Shopify::Liquid::Filter; |
16
|
|
|
|
|
|
|
|
17
|
23
|
|
|
23
|
0
|
330
|
sub new { return bless { |
18
|
|
|
|
|
|
|
order_of_operations => [], |
19
|
|
|
|
|
|
|
operators => {}, |
20
|
|
|
|
|
|
|
enclosing_tags => {}, |
21
|
|
|
|
|
|
|
free_tags => {}, |
22
|
|
|
|
|
|
|
filters => {}, |
23
|
|
|
|
|
|
|
inner_tags => {} |
24
|
|
|
|
|
|
|
}, $_[0]; } |
25
|
601
|
|
|
601
|
0
|
2036
|
sub operators { return $_[0]->{operators}; } |
26
|
247
|
|
|
247
|
0
|
229
|
sub order_of_operations { return @{$_[0]->{order_of_operations}}; } |
|
247
|
|
|
|
|
926
|
|
27
|
178
|
|
|
178
|
0
|
805
|
sub free_tags { return $_[0]->{free_tags}; } |
28
|
856
|
|
|
856
|
0
|
3227
|
sub enclosing_tags { return $_[0]->{enclosing_tags}; } |
29
|
141
|
|
|
141
|
0
|
533
|
sub inner_tags { return $_[0]->{inner_tags}; } |
30
|
1311
|
|
|
1311
|
0
|
6575
|
sub filters { return $_[0]->{filters}; } |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub register_tag { |
33
|
322
|
100
|
|
322
|
0
|
1735
|
$_[0]->free_tags->{$_[1]->name} = $_[1] if $_[1]->is_free; |
34
|
322
|
100
|
|
|
|
792
|
if ($_[1]->is_enclosing) { |
35
|
230
|
|
|
|
|
439
|
$_[0]->enclosing_tags->{$_[1]->name} = $_[1]; |
36
|
230
|
|
|
|
|
1380
|
foreach my $tag ($_[1]->inner_tags) { |
37
|
138
|
|
|
|
|
259
|
$_[0]->inner_tags->{$tag} = 1; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub register_operator { |
44
|
460
|
|
|
460
|
0
|
1031
|
$_[0]->operators->{$_} = $_[1] for($_[1]->symbol); |
45
|
460
|
|
|
|
|
669
|
my $ooo = $_[0]->{order_of_operations}; |
46
|
460
|
|
|
1771
|
|
1872
|
my $element = first { $_->[0]->priority == $_[1]->priority } @$ooo; |
|
1771
|
|
|
|
|
4179
|
|
47
|
460
|
100
|
|
|
|
1271
|
if ($element) { |
48
|
230
|
|
|
|
|
403
|
push(@$element, $_[1]); |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
else { |
51
|
230
|
|
|
|
|
495
|
push(@$ooo, [$_[1]]); |
52
|
|
|
|
|
|
|
} |
53
|
460
|
|
|
|
|
1085
|
$_[0]->{order_of_operations} = [sort { $b->[0]->priority <=> $a->[0]->priority } @$ooo]; |
|
4370
|
|
|
|
|
8837
|
|
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
sub register_filter { |
56
|
1311
|
|
|
1311
|
0
|
1964
|
$_[0]->filters->{$_[1]->name} = $_[1]; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub parse_filter_tokens { |
62
|
29
|
|
|
29
|
0
|
75
|
my ($self, $initial, @tokens) = @_; |
63
|
29
|
|
|
|
|
52
|
my $filter = shift(@tokens); |
64
|
29
|
|
|
|
|
136
|
my $filter_name = $filter->{core}->[0]->{core}; |
65
|
|
|
|
|
|
|
# TODO God, this is stupid, but temporary patch. |
66
|
29
|
|
|
|
|
42
|
my $filter_package; |
67
|
29
|
100
|
|
|
|
115
|
if ($filter_name =~ m/::/) { |
68
|
1
|
|
|
|
|
2
|
$filter_package = $filter_name; |
69
|
1
|
|
|
|
|
3
|
eval { $filter_package->name }; |
|
1
|
|
|
|
|
7
|
|
70
|
1
|
50
|
|
|
|
4
|
die new WWW::Shopify::Liquid::Exception::Parser::UnknownFilter($filter) if $@; |
71
|
|
|
|
|
|
|
} else { |
72
|
28
|
50
|
|
|
|
126
|
die new WWW::Shopify::Liquid::Exception::Parser::UnknownFilter($filter) unless $self->{filters}->{$filter_name}; |
73
|
28
|
|
|
|
|
69
|
$filter_package = $self->{filters}->{$filter_name}; |
74
|
|
|
|
|
|
|
} |
75
|
29
|
50
|
66
|
|
|
189
|
die new WWW::Shopify::Liquid::Exception::Parser::Arguments($filter, "In order to have arguments, filter must be followed by a colon.") if int(@tokens) > 0 && $tokens[0]->{core} ne ":"; |
76
|
|
|
|
|
|
|
|
77
|
29
|
|
|
|
|
56
|
my @arguments = (); |
78
|
|
|
|
|
|
|
# Get rid of our colon. |
79
|
29
|
100
|
|
|
|
85
|
if (shift(@tokens)) { |
80
|
16
|
|
|
|
|
30
|
my $i = 0; |
81
|
16
|
100
|
66
|
18
|
|
94
|
@arguments = map { $self->parse_argument_tokens(grep { !$_->isa('WWW::Shopify::Liquid::Token::Separator') } @{$_}) } part { $i++ if $_->isa('WWW::Shopify::Liquid::Token::Separator') && $_->{core} eq ","; $i; } @tokens; |
|
17
|
|
|
|
|
31
|
|
|
18
|
|
|
|
|
133
|
|
|
17
|
|
|
|
|
50
|
|
|
18
|
|
|
|
|
136
|
|
|
18
|
|
|
|
|
51
|
|
82
|
|
|
|
|
|
|
} |
83
|
29
|
|
|
|
|
452
|
$filter = $filter_package->new($initial->{line}, $initial, @arguments); |
84
|
29
|
|
|
|
|
183
|
$filter->verify; |
85
|
28
|
|
|
|
|
82
|
return $filter; |
86
|
|
|
|
|
|
|
} |
87
|
21
|
|
|
21
|
|
144
|
use List::MoreUtils qw(part); |
|
21
|
|
|
|
|
34
|
|
|
21
|
|
|
|
|
43904
|
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# Similar, but doesn't deal with tags; deals solely with order of operations. |
90
|
|
|
|
|
|
|
sub parse_argument_tokens { |
91
|
271
|
|
|
271
|
0
|
533
|
my ($self, @argument_tokens) = @_; |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
# Preprocess all variant filters. |
94
|
271
|
|
|
|
|
420
|
for my $variable (grep { $_->isa('WWW::Shopify::Liquid::Token::Variable') } @argument_tokens) { |
|
579
|
|
|
|
|
2491
|
|
95
|
283
|
|
|
|
|
269
|
my @core = @{$variable->{core}}; |
|
283
|
|
|
|
|
724
|
|
96
|
283
|
|
|
|
|
509
|
($variable->{core}->[$_]) = $self->parse_argument_tokens($core[$_]->members) for (grep { $core[$_]->isa('WWW::Shopify::Liquid::Token::Grouping') } 0..$#core); |
|
398
|
|
|
|
|
2596
|
|
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# First, pull together filters. These are the highest priority operators, after parentheses. They also have their own weird syntax. |
100
|
271
|
|
|
|
|
370
|
my $top = undef; |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# Don't partition if we have any pipes. Pipes and multiple arguments don't play well together. |
103
|
271
|
|
|
|
|
280
|
my @partitions; |
104
|
271
|
|
|
|
|
283
|
my $has_pipe = 0; |
105
|
271
|
100
|
|
|
|
404
|
if (int(grep { $_->isa('WWW::Shopify::Liquid::Token::Operator') && $_->{core} eq "|" } @argument_tokens) == 0) { |
|
579
|
100
|
|
|
|
3458
|
|
106
|
246
|
|
|
|
|
282
|
my $i = 0; |
107
|
246
|
|
|
|
|
269
|
$has_pipe = 1; |
108
|
246
|
50
|
|
442
|
|
1368
|
@partitions = part { $i++ if $_->isa('WWW::Shopify::Liquid::Token::Separator'); $i; } @argument_tokens; |
|
442
|
|
|
|
|
2103
|
|
|
442
|
|
|
|
|
866
|
|
109
|
|
|
|
|
|
|
} else { |
110
|
25
|
|
|
|
|
79
|
@partitions = (\@argument_tokens); |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
271
|
|
|
|
|
676
|
my @tops; |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
|
116
|
271
|
|
|
|
|
421
|
foreach my $partition (@partitions) { |
117
|
247
|
|
|
|
|
427
|
my @tokens = @$partition; |
118
|
|
|
|
|
|
|
#@tokens = (grep { !$_->isa('WWW::Shopify::Liquid::Token::Separator') } @tokens) if !$has_pipe; |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# Use the order of operations to create a binary tree structure. |
121
|
247
|
|
|
|
|
559
|
foreach my $operators ($self->order_of_operations) { |
122
|
|
|
|
|
|
|
# If we have pipes, we deal with those, and parse their lower level arguments. |
123
|
2457
|
|
|
|
|
3395
|
foreach my $operator (@$operators) { |
124
|
4915
|
|
|
|
|
16851
|
my %ops = map { $_ => 1 } $operator->symbol; |
|
5160
|
|
|
|
|
11271
|
|
125
|
4915
|
100
|
|
|
|
8356
|
if ($operator eq 'WWW::Shopify::Liquid::Operator::Pipe') { |
126
|
246
|
100
|
|
428
|
|
880
|
if ((my $idx = firstidx { $_->isa('WWW::Shopify::Liquid::Token::Operator') && $_->{core} eq "|" } @tokens) != -1) { |
|
428
|
100
|
|
|
|
3228
|
|
127
|
25
|
50
|
|
|
|
73
|
die new WWW::Shopify::Liquid::Exception::Parser($tokens[0]) if $idx == 0; |
128
|
25
|
|
|
|
|
39
|
my $i = 0; |
129
|
|
|
|
|
|
|
# Part should consist of the first token before a pipe, and then split on all pipes after this., |
130
|
25
|
100
|
66
|
117
|
|
247
|
my @parts = map { shift(@{$_}) if $_->[0]->{core} eq "|"; $_ } part { $i++ if $_->isa('WWW::Shopify::Liquid::Token::Operator') && $_->{core} eq "|"; $i; } splice(@tokens, $idx-1); |
|
54
|
100
|
|
|
|
191
|
|
|
29
|
|
|
|
|
51
|
|
|
54
|
|
|
|
|
120
|
|
|
117
|
|
|
|
|
656
|
|
|
117
|
|
|
|
|
196
|
|
131
|
25
|
|
|
|
|
133
|
my $next = undef; |
132
|
25
|
|
|
|
|
47
|
$top = $self->parse_filter_tokens($self->parse_argument_tokens(@{shift(@parts)}), @{shift(@parts)}); |
|
25
|
|
|
|
|
126
|
|
|
25
|
|
|
|
|
107
|
|
133
|
24
|
|
|
|
|
105
|
while (my $part = shift(@parts)) { |
134
|
4
|
|
|
|
|
16
|
$top = $self->parse_filter_tokens($top, @$part); |
135
|
|
|
|
|
|
|
} |
136
|
24
|
|
|
|
|
146
|
push(@tokens, $top); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
else { |
140
|
4669
|
100
|
|
7921
|
|
14924
|
while ((my $idx = firstidx { $_->isa('WWW::Shopify::Liquid::Token::Operator') && exists $ops{$_->{core}} } @tokens) != -1) { |
|
7921
|
|
|
|
|
53286
|
|
141
|
119
|
|
|
|
|
416
|
my ($op1, $op, $op2) = @tokens[$idx-1..$idx+1]; |
142
|
|
|
|
|
|
|
# The one exception would be if we have a - operator, and nothing before, this is unary negative operator, i.e. 0 - number. |
143
|
119
|
100
|
33
|
|
|
2724
|
die new WWW::Shopify::Liquid::Exception::Parser::Operands($tokens[0]) unless |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
33
|
|
|
|
|
144
|
|
|
|
|
|
|
$idx > 0 && $idx < $#tokens && |
145
|
|
|
|
|
|
|
($op1->isa('WWW::Shopify::Liquid::Operator') || $op1->isa('WWW::Shopify::Liquid::Token::Operand') || $op1->isa('WWW::Shopify::Liquid::Filter')) && |
146
|
|
|
|
|
|
|
($op2->isa('WWW::Shopify::Liquid::Operator') || $op2->isa('WWW::Shopify::Liquid::Token::Operand') || $op2->isa('WWW::Shopify::Liquid::Filter')); |
147
|
118
|
50
|
|
|
|
667
|
($op1) = $self->parse_argument_tokens($op1->members) if $op1->isa('WWW::Shopify::Liquid::Token::Grouping'); |
148
|
118
|
100
|
|
|
|
580
|
($op2) = $self->parse_argument_tokens($op2->members) if $op2->isa('WWW::Shopify::Liquid::Token::Grouping'); |
149
|
118
|
|
|
|
|
484
|
splice(@tokens, $idx-1, 3, $self->operators->{$op->{core}}->new($op->{core}, $op1, $op2)); |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
245
|
100
|
66
|
|
|
856
|
die new WWW::Shopify::Liquid::Exception::Parser::Operands($tokens[0]) unless int(@tokens) == 1 || int(@tokens) == 0; |
156
|
244
|
|
|
|
|
639
|
push(@tops, $tokens[0]); |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
268
|
|
|
|
|
1840
|
return @tops; |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub parse_tokens { |
163
|
203
|
|
|
203
|
0
|
1044
|
my ($self, @tokens) = @_; |
164
|
|
|
|
|
|
|
|
165
|
203
|
100
|
|
|
|
511
|
return () if int(@tokens) == 0; |
166
|
|
|
|
|
|
|
|
167
|
189
|
|
|
|
|
297
|
my @tags = (); |
168
|
|
|
|
|
|
|
# First we take a look and start matching up opening and ending tags. Those which are free tags we can leave as is. |
169
|
189
|
|
|
|
|
724
|
while (my $token = shift(@tokens)) { |
170
|
367
|
|
|
|
|
572
|
my $line = $token->{line}; |
171
|
367
|
100
|
|
|
|
2517
|
if ($token->isa('WWW::Shopify::Liquid::Token::Tag')) { |
|
|
100
|
|
|
|
|
|
172
|
124
|
|
|
|
|
150
|
my $tag = undef; |
173
|
124
|
100
|
|
|
|
339
|
if ($self->enclosing_tags->{$token->tag}) { |
|
|
100
|
|
|
|
|
|
174
|
79
|
|
|
|
|
145
|
my @internal = (); |
175
|
79
|
|
|
|
|
133
|
my @contents = (); |
176
|
79
|
|
|
|
|
173
|
my %allowed_internal_tags = map { $_ => 1 } $self->enclosing_tags->{$token->tag}->inner_tags; |
|
104
|
|
|
|
|
343
|
|
177
|
79
|
|
|
|
|
165
|
my $level = 1; |
178
|
79
|
|
|
|
|
119
|
my $closed = undef; |
179
|
79
|
|
|
|
|
237
|
for (0..$#tokens) { |
180
|
478
|
100
|
|
|
|
2028
|
if ($tokens[$_]->isa('WWW::Shopify::Liquid::Token::Tag')) { |
181
|
240
|
100
|
100
|
|
|
448
|
if ($self->enclosing_tags->{$tokens[$_]->tag}) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
182
|
42
|
|
|
|
|
75
|
++$level; |
183
|
|
|
|
|
|
|
} elsif (exists $allowed_internal_tags{$tokens[$_]->tag} && $level == 1) { |
184
|
29
|
|
|
|
|
46
|
$tokens[$_]->{arguments} = [$self->parse_argument_tokens(@{$tokens[$_]->{arguments}})]; |
|
29
|
|
|
|
|
107
|
|
185
|
29
|
|
|
|
|
81
|
push(@internal, $_); |
186
|
|
|
|
|
|
|
} elsif ($tokens[$_]->tag eq "end" . $token->tag && $level == 1) { |
187
|
77
|
|
|
|
|
98
|
--$level; |
188
|
77
|
|
|
|
|
102
|
my $last_int = 0; |
189
|
77
|
|
|
|
|
154
|
foreach my $int (@internal, $_) { |
190
|
106
|
|
|
|
|
361
|
push(@contents, [splice(@tokens, 0, $int-$last_int)]); |
191
|
106
|
100
|
66
|
|
|
295
|
shift(@{$contents[0]}) if $self->enclosing_tags->{$token->tag}->inner_ignore_whitespace && int(@contents) > 0 && int(@{$contents[0]}) > 0 && $contents[0]->[0]->isa('WWW::Shopify::Liquid::Token::Text::Whitespace'); |
|
1
|
|
100
|
|
|
3
|
|
|
11
|
|
66
|
|
|
60
|
|
192
|
143
|
|
|
|
|
280
|
@contents = map { |
193
|
106
|
|
|
|
|
217
|
my @array = @$_; |
194
|
143
|
100
|
100
|
|
|
1278
|
if (int(@array) > 0 && $array[0]->isa('WWW::Shopify::Liquid::Token::Tag') && $allowed_internal_tags{$array[0]->tag}) { |
|
|
|
100
|
|
|
|
|
195
|
37
|
|
|
|
|
136
|
[$array[0], $self->parse_tokens(@array[1..$#array])]; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
else { |
198
|
106
|
|
|
|
|
529
|
[$self->parse_tokens(@array)] |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
} @contents; |
201
|
105
|
|
|
|
|
244
|
$last_int = $int; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
# Remove the endtag. |
204
|
76
|
|
|
|
|
109
|
shift(@tokens); |
205
|
76
|
|
|
|
|
108
|
$closed = 1; |
206
|
76
|
|
|
|
|
151
|
last; |
207
|
|
|
|
|
|
|
} elsif ($tokens[$_]->tag =~ m/^end/) { |
208
|
42
|
|
|
|
|
73
|
--$level; |
209
|
|
|
|
|
|
|
# TODO: Fix this whole thing; right now, no close tags are being spit out for the wrong tag. We do this to avoid an {% unless %}{% if %}{% else %}{% endif %}{% endunless%} situtation. |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
} |
213
|
78
|
100
|
|
|
|
257
|
die new WWW::Shopify::Liquid::Exception::Parser::NoClose($token) unless $closed; |
214
|
76
|
|
|
|
|
208
|
$tag = $self->enclosing_tags->{$token->tag}->new($line, $token->tag, [$self->parse_argument_tokens(@{$token->{arguments}})], \@contents); |
|
76
|
|
|
|
|
238
|
|
215
|
76
|
|
|
|
|
484
|
$tag->verify; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
elsif ($self->free_tags->{$token->tag}) { |
218
|
41
|
|
|
|
|
97
|
$tag = $self->free_tags->{$token->tag}->new($line, $token->tag, [$self->parse_argument_tokens(@{$token->{arguments}})]); |
|
41
|
|
|
|
|
151
|
|
219
|
41
|
|
|
|
|
247
|
$tag->verify; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
else { |
222
|
4
|
100
|
66
|
|
|
14
|
die new WWW::Shopify::Liquid::Exception::Parser::NoOpen($token) if ($token->tag =~ m/^end(\w+)$/ && $self->enclosing_tags->{$1}); |
223
|
3
|
100
|
|
|
|
20
|
die new WWW::Shopify::Liquid::Exception::Parser::NakedInnerTag($token) if (exists $self->inner_tags->{$token->tag}); |
224
|
2
|
|
|
|
|
38
|
die new WWW::Shopify::Liquid::Exception::Parser::UnknownTag($token); |
225
|
|
|
|
|
|
|
} |
226
|
116
|
|
|
|
|
503
|
push(@tags, $tag); |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
elsif ($token->isa('WWW::Shopify::Liquid::Token::Output')) { |
229
|
66
|
|
|
|
|
115
|
push(@tags, WWW::Shopify::Liquid::Tag::Output->new($line, [$self->parse_argument_tokens(@{$token->{core}})])); |
|
66
|
|
|
|
|
243
|
|
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
else { |
232
|
177
|
|
|
|
|
594
|
push(@tags, $token); |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
|
236
|
178
|
|
|
|
|
237
|
my $top = undef; |
237
|
178
|
100
|
|
|
|
382
|
if (int(@tags) > 1) { |
238
|
61
|
|
|
|
|
249
|
$top = WWW::Shopify::Liquid::Operator::Concatenate->new; |
239
|
61
|
|
|
|
|
281
|
$top->{operands}->[0] = shift(@tags); |
240
|
61
|
|
|
|
|
90
|
my $next = $top; |
241
|
61
|
|
|
|
|
220
|
while (my $tag = shift(@tags)) { |
242
|
167
|
100
|
|
|
|
324
|
if (int(@tags) == 0) { |
243
|
61
|
|
|
|
|
208
|
$next->{operands}->[1] = $tag; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
else { |
246
|
106
|
|
|
|
|
299
|
$next->{operands}->[1] = WWW::Shopify::Liquid::Operator::Concatenate->new; |
247
|
106
|
|
|
|
|
163
|
$next = $next->{operands}->[1]; |
248
|
106
|
|
|
|
|
473
|
$next->{operands}->[0] = $tag; |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
else { |
253
|
117
|
|
|
|
|
181
|
($top) = @tags; |
254
|
|
|
|
|
|
|
} |
255
|
178
|
|
|
|
|
831
|
return $top; |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
sub unparse_argument_tokens { |
259
|
11
|
|
|
11
|
0
|
8
|
my ($self, $ast) = @_; |
260
|
11
|
100
|
|
|
|
46
|
return $ast if $ast->isa('WWW::Shopify::Liquid::Token'); |
261
|
2
|
|
|
|
|
8
|
my @optokens = ($self->unparse_argument_tokens($ast->{operands}->[0]), WWW::Shopify::Liquid::Token::Operator->new([0,0,0], $ast->{core}), $self->unparse_argument_tokens($ast->{operands}->[1])); |
262
|
2
|
100
|
|
|
|
18
|
return WWW::Shopify::Liquid::Token::Grouping->new([0,0,0], @optokens) if $ast->requires_grouping; |
263
|
1
|
|
|
|
|
5
|
return @optokens; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
sub unparse_tokens { |
267
|
14
|
|
|
14
|
0
|
667
|
my ($self, $ast) = @_; |
268
|
14
|
100
|
|
|
|
65
|
return $ast if $ast->isa('WWW::Shopify::Liquid::Token'); |
269
|
9
|
100
|
|
|
|
25
|
if ($ast->isa('WWW::Shopify::Liquid::Tag')) { |
270
|
5
|
50
|
|
|
|
10
|
my @arguments = $ast->{arguments} ? $self->unparse_argument_tokens(@{$ast->{arguments}}) : (); |
|
5
|
|
|
|
|
9
|
|
271
|
5
|
100
|
|
|
|
25
|
if ($ast->isa('WWW::Shopify::Liquid::Tag::Enclosing')) { |
|
|
50
|
|
|
|
|
|
272
|
3
|
100
|
|
|
|
12
|
if ($ast->isa('WWW::Shopify::Liquid::Tag::If')) { |
273
|
2
|
50
|
|
|
|
5
|
return (WWW::Shopify::Liquid::Token::Tag->new([0,0,0], 'if', \@arguments), $self->unparse_tokens($ast->{true_path}), WWW::Shopify::Liquid::Token::Tag->new([0,0,0], 'endif')) if !$ast->{false_path}; |
274
|
2
|
|
|
|
|
7
|
return (WWW::Shopify::Liquid::Token::Tag->new([0,0,0], 'if', \@arguments), $self->unparse_tokens($ast->{true_path}), WWW::Shopify::Liquid::Token::Tag->new([0,0,0], 'else'), $self->unparse_tokens($ast->{false_path}), WWW::Shopify::Liquid::Token::Tag->new([0,0,0], 'endif')); |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
else { |
277
|
1
|
|
|
|
|
14
|
return (WWW::Shopify::Liquid::Token::Tag->new([0,0,0], $ast->{core}, \@arguments), $self->unparse_tokens($ast->{contents}), WWW::Shopify::Liquid::Token::Tag->new([0,0,0], 'end' . $ast->{core})); |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
elsif ($ast->isa('WWW::Shopify::Liquid::Tag::Output')) { |
281
|
2
|
|
|
|
|
4
|
return (WWW::Shopify::Liquid::Token::Output->new([0,0,0], [$self->unparse_argument_tokens(@{$ast->{arguments}})])); |
|
2
|
|
|
|
|
5
|
|
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
else { |
284
|
0
|
|
|
|
|
0
|
return (WWW::Shopify::Liquid::Token::Tag->new([0,0,0], $ast->{core}, \@arguments)); |
285
|
|
|
|
|
|
|
} |
286
|
0
|
|
|
|
|
0
|
return $ast; |
287
|
|
|
|
|
|
|
} |
288
|
4
|
50
|
|
|
|
17
|
if ($ast->isa('WWW::Shopify::Liquid::Filter')) { |
289
|
0
|
|
|
|
|
0
|
return $ast; |
290
|
|
|
|
|
|
|
} |
291
|
4
|
50
|
|
|
|
19
|
return ($self->unparse_tokens($ast->{operands}->[0]), $self->unparse_tokens($ast->{operands}->[1])) if ($ast->isa('WWW::Shopify::Liquid::Operator::Concatenate')); |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
1; |