| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
8
|
|
|
8
|
|
62
|
use strict; |
|
|
8
|
|
|
|
|
21
|
|
|
|
8
|
|
|
|
|
358
|
|
|
2
|
8
|
|
|
8
|
|
42
|
use warnings; |
|
|
8
|
|
|
|
|
44
|
|
|
|
8
|
|
|
|
|
632
|
|
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Data::ZPath::_Parser; |
|
5
|
|
|
|
|
|
|
|
|
6
|
8
|
|
|
8
|
|
49
|
use Carp qw(croak); |
|
|
8
|
|
|
|
|
14
|
|
|
|
8
|
|
|
|
|
556
|
|
|
7
|
8
|
|
|
8
|
|
46
|
use Data::ZPath::_Lexer; |
|
|
8
|
|
|
|
|
15
|
|
|
|
8
|
|
|
|
|
23116
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = '0.001000'; |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
sub _parse_top_level_terms { |
|
12
|
376
|
|
|
376
|
|
780
|
my ( $src ) = @_; |
|
13
|
|
|
|
|
|
|
|
|
14
|
376
|
|
|
|
|
867
|
my @parts = _split_top_level_commas($src); |
|
15
|
376
|
|
|
|
|
553
|
my @terms; |
|
16
|
|
|
|
|
|
|
|
|
17
|
376
|
|
|
|
|
828
|
for my $p (@parts) { |
|
18
|
431
|
|
|
|
|
1937
|
my $lexer = Data::ZPath::_Lexer->new($p); |
|
19
|
426
|
|
|
|
|
1016
|
my $expr = _parse_expression($lexer); |
|
20
|
426
|
|
|
|
|
1294
|
$lexer->expect('EOF'); |
|
21
|
422
|
|
|
|
|
3100
|
push @terms, $expr; |
|
22
|
|
|
|
|
|
|
} |
|
23
|
|
|
|
|
|
|
|
|
24
|
367
|
|
|
|
|
2389
|
return \@terms; |
|
25
|
|
|
|
|
|
|
} |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub _split_top_level_commas { |
|
28
|
376
|
|
|
376
|
|
754
|
my ( $src ) = @_; |
|
29
|
376
|
|
|
|
|
607
|
my @out; |
|
30
|
|
|
|
|
|
|
|
|
31
|
376
|
|
|
|
|
642
|
my $depth_paren = 0; |
|
32
|
376
|
|
|
|
|
574
|
my $depth_brack = 0; |
|
33
|
376
|
|
|
|
|
633
|
my $in_string = 0; |
|
34
|
376
|
|
|
|
|
562
|
my $escape = 0; |
|
35
|
|
|
|
|
|
|
|
|
36
|
376
|
|
|
|
|
644
|
my $buf = ''; |
|
37
|
376
|
|
|
|
|
2080
|
my @chars = split //, $src; |
|
38
|
|
|
|
|
|
|
|
|
39
|
376
|
|
|
|
|
1150
|
for ( my $i = 0; $i < @chars; $i++ ) { |
|
40
|
6199
|
|
|
|
|
8333
|
my $c = $chars[$i]; |
|
41
|
|
|
|
|
|
|
|
|
42
|
6199
|
100
|
|
|
|
10047
|
if ( $in_string ) { |
|
43
|
857
|
|
|
|
|
916
|
$buf .= $c; |
|
44
|
857
|
50
|
|
|
|
1296
|
if ( $escape ) { |
|
45
|
0
|
|
|
|
|
0
|
$escape = 0; |
|
46
|
0
|
|
|
|
|
0
|
next; |
|
47
|
|
|
|
|
|
|
} |
|
48
|
857
|
50
|
|
|
|
1217
|
if ( $c eq '\\' ) { $escape = 1; next; } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
49
|
857
|
100
|
|
|
|
1251
|
if ( $c eq '"' ) { $in_string = 0; next; } |
|
|
104
|
|
|
|
|
173
|
|
|
|
104
|
|
|
|
|
236
|
|
|
50
|
753
|
|
|
|
|
1235
|
next; |
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
|
|
53
|
5342
|
100
|
|
|
|
8860
|
if ( $c eq '"' ) { $in_string = 1; $buf .= $c; next; } |
|
|
104
|
|
|
|
|
162
|
|
|
|
104
|
|
|
|
|
146
|
|
|
|
104
|
|
|
|
|
230
|
|
|
54
|
5238
|
100
|
|
|
|
8661
|
if ( $c eq '(') { $depth_paren++; $buf .= $c; next; } |
|
|
121
|
|
|
|
|
222
|
|
|
|
121
|
|
|
|
|
312
|
|
|
|
121
|
|
|
|
|
333
|
|
|
55
|
5117
|
100
|
|
|
|
8332
|
if ( $c eq ')') { $depth_paren--; $buf .= $c; next; } |
|
|
121
|
|
|
|
|
192
|
|
|
|
121
|
|
|
|
|
203
|
|
|
|
121
|
|
|
|
|
277
|
|
|
56
|
4996
|
100
|
|
|
|
8336
|
if ( $c eq '[' ) { $depth_brack++; $buf .= $c; next; } |
|
|
96
|
|
|
|
|
175
|
|
|
|
96
|
|
|
|
|
178
|
|
|
|
96
|
|
|
|
|
303
|
|
|
57
|
4900
|
100
|
|
|
|
8020
|
if ( $c eq ']' ) { $depth_brack--; $buf .= $c; next; } |
|
|
96
|
|
|
|
|
145
|
|
|
|
96
|
|
|
|
|
173
|
|
|
|
96
|
|
|
|
|
224
|
|
|
58
|
|
|
|
|
|
|
|
|
59
|
4804
|
100
|
100
|
|
|
8855
|
if ( $c eq ',' && $depth_paren == 0 && $depth_brack == 0 ) { |
|
|
|
|
66
|
|
|
|
|
|
60
|
55
|
|
|
|
|
117
|
push @out, _trim($buf); |
|
61
|
55
|
|
|
|
|
100
|
$buf = ''; |
|
62
|
55
|
|
|
|
|
125
|
next; |
|
63
|
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
|
|
65
|
4749
|
|
|
|
|
9629
|
$buf .= $c; |
|
66
|
|
|
|
|
|
|
} |
|
67
|
|
|
|
|
|
|
|
|
68
|
376
|
50
|
|
|
|
942
|
push @out, _trim($buf) if length _trim($buf); |
|
69
|
376
|
|
|
|
|
1804
|
return @out; |
|
70
|
|
|
|
|
|
|
} |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub _trim { |
|
73
|
807
|
|
|
807
|
|
1530
|
my ( $s ) = @_; |
|
74
|
807
|
|
|
|
|
5553
|
$s =~ s/^\s+//; |
|
75
|
807
|
|
|
|
|
2017
|
$s =~ s/\s+$//; |
|
76
|
807
|
|
|
|
|
2534
|
return $s; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# Expression grammar (recursive descent): |
|
80
|
|
|
|
|
|
|
# expr := ternary |
|
81
|
|
|
|
|
|
|
# ternary := or ( WS? '?' WS? expr WS? ':' WS? expr )? |
|
82
|
|
|
|
|
|
|
# or := and ( '||' and )* |
|
83
|
|
|
|
|
|
|
# and := bit_or ( '&&' bit_or )* |
|
84
|
|
|
|
|
|
|
# bit_or := bit_xor ( '|' bit_xor )* |
|
85
|
|
|
|
|
|
|
# bit_xor := bit_and ( '^' bit_and )* |
|
86
|
|
|
|
|
|
|
# bit_and := equality ( '&' equality )* |
|
87
|
|
|
|
|
|
|
# equality := rel ( ('=='|'!=' ) rel )* |
|
88
|
|
|
|
|
|
|
# rel := add ( ('>='|'<='|'>'|'<') add )* |
|
89
|
|
|
|
|
|
|
# add := mul (('+'|'-') mul)* |
|
90
|
|
|
|
|
|
|
# mul := unary (('*'|'/'|'%') unary)* |
|
91
|
|
|
|
|
|
|
# unary := ('!'|'~') unary | primary |
|
92
|
|
|
|
|
|
|
# primary := number | string | function | path | '(' expr ')' |
|
93
|
|
|
|
|
|
|
# |
|
94
|
|
|
|
|
|
|
# NOTE: per zpath.me, binary ops require whitespace around them. |
|
95
|
|
|
|
|
|
|
# We enforce this at lexer-time: a binary op token is only produced if |
|
96
|
|
|
|
|
|
|
# it has whitespace before and after in source. |
|
97
|
|
|
|
|
|
|
|
|
98
|
672
|
|
|
672
|
|
1501
|
sub _parse_expression { _parse_ternary(@_) } |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub _parse_ternary { |
|
101
|
672
|
|
|
672
|
|
1175
|
my ( $lx ) = @_; |
|
102
|
672
|
|
|
|
|
1395
|
my $cond = _parse_or($lx); |
|
103
|
|
|
|
|
|
|
|
|
104
|
672
|
100
|
|
|
|
1609
|
if ( $lx->peek_kind eq 'QMARK' ) { |
|
105
|
7
|
|
|
|
|
13
|
$lx->next_tok; # ? |
|
106
|
7
|
|
|
|
|
24
|
my $then = _parse_expression($lx); |
|
107
|
7
|
|
|
|
|
37
|
$lx->expect('COLON'); |
|
108
|
7
|
|
|
|
|
10
|
my $els = _parse_expression($lx); |
|
109
|
7
|
|
|
|
|
24
|
return { t => 'ternary', c => $cond, a => $then, b => $els }; |
|
110
|
|
|
|
|
|
|
} |
|
111
|
|
|
|
|
|
|
|
|
112
|
665
|
|
|
|
|
1514
|
return $cond; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub _bin_left_assoc { |
|
116
|
6405
|
|
|
6405
|
|
10413
|
my ( $lx, $next_parser, $ops ) = @_; |
|
117
|
6405
|
|
|
|
|
12686
|
my $left = $next_parser->($lx); |
|
118
|
|
|
|
|
|
|
|
|
119
|
6405
|
|
|
|
|
11187
|
while ( 1 ) { |
|
120
|
6530
|
|
|
|
|
11209
|
my $k = $lx->peek_kind; |
|
121
|
6530
|
100
|
|
|
|
12958
|
last unless $ops->{$k}; |
|
122
|
125
|
|
|
|
|
269
|
my $op = $lx->next_tok->{v}; |
|
123
|
125
|
|
|
|
|
276
|
my $right = $next_parser->($lx); |
|
124
|
125
|
|
|
|
|
621
|
$left = { t => 'bin', op => $op, l => $left, r => $right }; |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
6405
|
|
|
|
|
18091
|
return $left; |
|
128
|
|
|
|
|
|
|
} |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub _parse_or { |
|
131
|
672
|
|
|
672
|
|
1216
|
my ( $lx ) = @_; |
|
132
|
672
|
|
|
|
|
2330
|
return _bin_left_assoc($lx, \&_parse_and, { OROR => 1 }); |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub _parse_and { |
|
136
|
676
|
|
|
676
|
|
1097
|
my ( $lx ) = @_; |
|
137
|
676
|
|
|
|
|
1900
|
return _bin_left_assoc($lx, \&_parse_bitor, { ANDAND => 1 }); |
|
138
|
|
|
|
|
|
|
} |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub _parse_bitor { |
|
141
|
684
|
|
|
684
|
|
1104
|
my ( $lx ) = @_; |
|
142
|
684
|
|
|
|
|
1906
|
return _bin_left_assoc($lx, \&_parse_bitxor, { BOR => 1 }); |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub _parse_bitxor { |
|
146
|
685
|
|
|
685
|
|
1154
|
my ( $lx ) = @_; |
|
147
|
685
|
|
|
|
|
1900
|
return _bin_left_assoc($lx, \&_parse_bitand, { BXOR => 1 }); |
|
148
|
|
|
|
|
|
|
} |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub _parse_bitand { |
|
151
|
686
|
|
|
686
|
|
1106
|
my ( $lx ) = @_; |
|
152
|
686
|
|
|
|
|
1872
|
return _bin_left_assoc($lx, \&_parse_equality, { BAND => 1 }); |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub _parse_equality { |
|
156
|
688
|
|
|
688
|
|
1280
|
my ( $lx ) = @_; |
|
157
|
688
|
|
|
|
|
4570
|
return _bin_left_assoc($lx, \&_parse_rel, { EQEQ => 1, NEQ => 1 }); |
|
158
|
|
|
|
|
|
|
} |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
sub _parse_rel { |
|
161
|
766
|
|
|
766
|
|
1287
|
my ( $lx ) = @_; |
|
162
|
766
|
|
|
|
|
3952
|
return _bin_left_assoc($lx, \&_parse_add, { GE => 1, LE => 1, GT => 1, LT => 1 }); |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub _parse_add { |
|
166
|
769
|
|
|
769
|
|
1337
|
my ( $lx ) = @_; |
|
167
|
769
|
|
|
|
|
2703
|
return _bin_left_assoc($lx, \&_parse_mul, { PLUS => 1, MINUS => 1 }); |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub _parse_mul { |
|
171
|
779
|
|
|
779
|
|
1309
|
my ( $lx ) = @_; |
|
172
|
779
|
|
|
|
|
2736
|
return _bin_left_assoc($lx, \&_parse_unary, { STAR => 1, SLASH => 1, PCT => 1 }); |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub _parse_unary { |
|
176
|
805
|
|
|
805
|
|
1950
|
my ( $lx ) = @_; |
|
177
|
805
|
|
|
|
|
2191
|
my $k = $lx->peek_kind; |
|
178
|
805
|
100
|
100
|
|
|
3490
|
if ( $k eq 'NOT' || $k eq 'BNOT' ) { |
|
179
|
8
|
|
|
|
|
51
|
my $op = $lx->next_tok->{v}; |
|
180
|
8
|
|
|
|
|
29
|
my $e = _parse_unary($lx); |
|
181
|
8
|
|
|
|
|
50
|
return { t => 'un', op => $op, e => $e }; |
|
182
|
|
|
|
|
|
|
} |
|
183
|
797
|
|
|
|
|
1728
|
return _parse_primary($lx); |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
sub _parse_primary { |
|
187
|
797
|
|
|
797
|
|
1259
|
my ( $lx ) = @_; |
|
188
|
797
|
|
|
|
|
1719
|
my $k = $lx->peek_kind; |
|
189
|
|
|
|
|
|
|
|
|
190
|
797
|
100
|
|
|
|
1801
|
if ( $k eq 'NUMBER' ) { |
|
191
|
143
|
|
|
|
|
390
|
return { t => 'num', v => $lx->next_tok->{v} }; |
|
192
|
|
|
|
|
|
|
} |
|
193
|
654
|
100
|
|
|
|
1289
|
if ( $k eq 'STRING' ) { |
|
194
|
137
|
|
|
|
|
370
|
return { t => 'str', v => $lx->next_tok->{v} }; |
|
195
|
|
|
|
|
|
|
} |
|
196
|
517
|
100
|
|
|
|
1059
|
if ( $k eq 'LPAREN' ) { |
|
197
|
5
|
|
|
|
|
19
|
$lx->next_tok; |
|
198
|
5
|
|
|
|
|
16
|
my $e = _parse_expression($lx); |
|
199
|
5
|
|
|
|
|
20
|
$lx->expect('RPAREN'); |
|
200
|
5
|
|
|
|
|
11
|
return $e; |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# Function: NAME '(' ... |
|
204
|
512
|
100
|
100
|
|
|
1498
|
if ( $k eq 'NAME' && $lx->peek_kind_n(1) eq 'LPAREN' ) { |
|
205
|
109
|
|
|
|
|
252
|
my $name = $lx->next_tok->{v}; |
|
206
|
109
|
|
|
|
|
363
|
$lx->expect('LPAREN'); |
|
207
|
109
|
|
|
|
|
158
|
my @args; |
|
208
|
109
|
100
|
|
|
|
265
|
if ( $lx->peek_kind ne 'RPAREN' ) { |
|
209
|
78
|
|
|
|
|
250
|
push @args, _parse_expression($lx); |
|
210
|
78
|
|
|
|
|
238
|
while ( $lx->peek_kind eq 'COMMA' ) { |
|
211
|
45
|
|
|
|
|
184
|
$lx->next_tok; |
|
212
|
45
|
|
|
|
|
109
|
push @args, _parse_expression($lx); |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
} |
|
215
|
109
|
|
|
|
|
323
|
$lx->expect('RPAREN'); |
|
216
|
109
|
|
|
|
|
568
|
return { t => 'fn', n => $name, a => \@args }; |
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
# Otherwise treat it as a path-expression |
|
220
|
403
|
|
|
|
|
1063
|
return _parse_path_expr($lx); |
|
221
|
|
|
|
|
|
|
} |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub _parse_path_expr { |
|
224
|
403
|
|
|
403
|
|
801
|
my ( $lx ) = @_; |
|
225
|
|
|
|
|
|
|
|
|
226
|
403
|
|
|
|
|
621
|
my @segs; |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# path can start with "/" or with a segment. |
|
229
|
403
|
100
|
|
|
|
2048
|
if ( $lx->peek_kind eq 'SLASH_PATH' ) { |
|
|
|
100
|
|
|
|
|
|
|
230
|
132
|
|
|
|
|
414
|
$lx->next_tok; # consume '/' |
|
231
|
132
|
|
|
|
|
591
|
push @segs, { k => 'root', q => [] }; |
|
232
|
|
|
|
|
|
|
|
|
233
|
132
|
100
|
|
|
|
387
|
if ( $lx->peek_kind eq 'LBRACK' ) { |
|
234
|
1
|
|
|
|
|
5
|
$segs[-1]->{q} = _parse_qualifiers($lx); |
|
235
|
|
|
|
|
|
|
} |
|
236
|
|
|
|
|
|
|
|
|
237
|
132
|
50
|
66
|
|
|
306
|
if ( |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
238
|
|
|
|
|
|
|
$lx->peek_kind eq 'EOF' |
|
239
|
|
|
|
|
|
|
or $lx->peek_kind eq 'COMMA' |
|
240
|
|
|
|
|
|
|
or $lx->peek_kind eq 'RPAREN' |
|
241
|
|
|
|
|
|
|
or $lx->peek_kind eq 'RBRACK' |
|
242
|
|
|
|
|
|
|
or $lx->peek_kind eq 'QMARK' |
|
243
|
|
|
|
|
|
|
or $lx->peek_kind eq 'COLON' |
|
244
|
|
|
|
|
|
|
or $lx->peek_kind eq 'EQEQ' |
|
245
|
|
|
|
|
|
|
or $lx->peek_kind eq 'NEQ' |
|
246
|
|
|
|
|
|
|
or $lx->peek_kind eq 'GE' |
|
247
|
|
|
|
|
|
|
or $lx->peek_kind eq 'LE' |
|
248
|
|
|
|
|
|
|
or $lx->peek_kind eq 'GT' |
|
249
|
|
|
|
|
|
|
or $lx->peek_kind eq 'LT' |
|
250
|
|
|
|
|
|
|
or $lx->peek_kind eq 'ANDAND' |
|
251
|
|
|
|
|
|
|
or $lx->peek_kind eq 'OROR' |
|
252
|
|
|
|
|
|
|
or $lx->peek_kind eq 'PLUS' |
|
253
|
|
|
|
|
|
|
or $lx->peek_kind eq 'MINUS' |
|
254
|
|
|
|
|
|
|
or $lx->peek_kind eq 'STAR' |
|
255
|
|
|
|
|
|
|
or $lx->peek_kind eq 'SLASH' |
|
256
|
|
|
|
|
|
|
or $lx->peek_kind eq 'PCT' |
|
257
|
|
|
|
|
|
|
or $lx->peek_kind eq 'BAND' |
|
258
|
|
|
|
|
|
|
or $lx->peek_kind eq 'BOR' |
|
259
|
|
|
|
|
|
|
or $lx->peek_kind eq 'BXOR' |
|
260
|
|
|
|
|
|
|
) { |
|
261
|
10
|
|
|
|
|
56
|
return { t => 'path', s => \@segs }; |
|
262
|
|
|
|
|
|
|
} |
|
263
|
|
|
|
|
|
|
} |
|
264
|
|
|
|
|
|
|
elsif ( $lx->peek_kind eq 'LBRACK' ) { |
|
265
|
2
|
|
|
|
|
9
|
my $seg = { k => 'dot', q => _parse_qualifiers($lx) }; |
|
266
|
2
|
|
|
|
|
5
|
push @segs, $seg; |
|
267
|
2
|
0
|
33
|
|
|
7
|
return { t => 'path', s => \@segs } |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
268
|
|
|
|
|
|
|
if $lx->peek_kind eq 'EOF' || $lx->peek_kind eq 'COMMA' || $lx->peek_kind eq 'RPAREN' || $lx->peek_kind eq 'RBRACK'; |
|
269
|
|
|
|
|
|
|
} |
|
270
|
|
|
|
|
|
|
|
|
271
|
391
|
50
|
33
|
|
|
2227
|
if ( $lx->peek_kind ne 'SLASH_PATH' |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
272
|
|
|
|
|
|
|
&& $lx->peek_kind ne 'EOF' |
|
273
|
|
|
|
|
|
|
&& $lx->peek_kind ne 'COMMA' |
|
274
|
|
|
|
|
|
|
&& $lx->peek_kind ne 'RPAREN' |
|
275
|
|
|
|
|
|
|
&& $lx->peek_kind ne 'RBRACK' ) { |
|
276
|
391
|
|
|
|
|
1118
|
push @segs, _parse_path_segment($lx); |
|
277
|
|
|
|
|
|
|
} |
|
278
|
|
|
|
|
|
|
|
|
279
|
391
|
|
|
|
|
1006
|
while ( $lx->peek_kind eq 'SLASH_PATH' ) { |
|
280
|
271
|
|
|
|
|
699
|
$lx->next_tok; |
|
281
|
271
|
100
|
|
|
|
551
|
if ( $lx->peek_kind eq 'LBRACK' ) { |
|
282
|
|
|
|
|
|
|
# "list/[expr]" implies "*" |
|
283
|
1
|
|
|
|
|
6
|
my $seg = { k => 'star', q => [] }; |
|
284
|
1
|
|
|
|
|
3
|
$seg->{q} = _parse_qualifiers($lx); |
|
285
|
1
|
|
|
|
|
3
|
push @segs, $seg; |
|
286
|
1
|
|
|
|
|
4
|
next; |
|
287
|
|
|
|
|
|
|
} |
|
288
|
270
|
|
|
|
|
514
|
push @segs, _parse_path_segment($lx); |
|
289
|
|
|
|
|
|
|
} |
|
290
|
|
|
|
|
|
|
|
|
291
|
391
|
|
|
|
|
1853
|
return { t => 'path', s => \@segs }; |
|
292
|
|
|
|
|
|
|
} |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
sub _parse_path_segment { |
|
295
|
661
|
|
|
661
|
|
1139
|
my ( $lx ) = @_; |
|
296
|
|
|
|
|
|
|
|
|
297
|
661
|
|
|
|
|
1274
|
my $k = $lx->peek_kind; |
|
298
|
|
|
|
|
|
|
|
|
299
|
661
|
|
|
|
|
5115
|
my $seg; |
|
300
|
661
|
100
|
66
|
|
|
3830
|
if ( $k eq 'DOT' ) { $lx->next_tok; $seg = { k => 'dot' }; } |
|
|
18
|
100
|
|
|
|
66
|
|
|
|
18
|
100
|
|
|
|
58
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
301
|
11
|
|
|
|
|
36
|
elsif ( $k eq 'DOTDOT' ) { $lx->next_tok; $seg = { k => 'parent' }; } |
|
|
11
|
|
|
|
|
38
|
|
|
302
|
2
|
|
|
|
|
9
|
elsif ( $k eq 'DOTDOTSTAR' ) { $lx->next_tok; $seg = { k => 'ancestors' }; } |
|
|
2
|
|
|
|
|
8
|
|
|
303
|
44
|
|
|
|
|
122
|
elsif ( $k eq 'STAR_PATH' ) { $lx->next_tok; $seg = { k => 'star' }; } |
|
|
44
|
|
|
|
|
121
|
|
|
304
|
85
|
|
|
|
|
290
|
elsif ( $k eq 'STARSTAR' ) { $lx->next_tok; $seg = { k => 'desc' }; } |
|
|
85
|
|
|
|
|
281
|
|
|
305
|
6
|
|
|
|
|
19
|
elsif ( $k eq 'INDEX' ) { my $i = $lx->next_tok->{v}; $seg = { k => 'index', i => $i }; } |
|
|
6
|
|
|
|
|
24
|
|
|
306
|
22
|
|
|
|
|
78
|
elsif ( $k eq 'NUMBER' ) { my $i = $lx->next_tok->{v}; $seg = { k => 'index', i => $i }; } |
|
|
22
|
|
|
|
|
65
|
|
|
307
|
|
|
|
|
|
|
elsif ( $k eq 'NAME' && $lx->peek_kind_n(1) eq 'LPAREN' ) { |
|
308
|
7
|
|
|
|
|
21
|
my $name = $lx->next_tok->{v}; |
|
309
|
7
|
|
|
|
|
41
|
$lx->expect('LPAREN'); |
|
310
|
7
|
|
|
|
|
11
|
my @args; |
|
311
|
7
|
50
|
|
|
|
18
|
if ( $lx->peek_kind ne 'RPAREN' ) { |
|
312
|
7
|
|
|
|
|
25
|
push @args, _parse_expression($lx); |
|
313
|
7
|
|
|
|
|
22
|
while ( $lx->peek_kind eq 'COMMA' ) { |
|
314
|
1
|
|
|
|
|
3
|
$lx->next_tok; |
|
315
|
1
|
|
|
|
|
3
|
push @args, _parse_expression($lx); |
|
316
|
|
|
|
|
|
|
} |
|
317
|
|
|
|
|
|
|
} |
|
318
|
7
|
|
|
|
|
28
|
$lx->expect('RPAREN'); |
|
319
|
7
|
|
|
|
|
34
|
$seg = { k => 'fnseg', n => $name, a => \@args }; |
|
320
|
|
|
|
|
|
|
} |
|
321
|
466
|
|
|
|
|
929
|
elsif ( $k eq 'NAME' ) { my $n = $lx->next_tok->{v}; $seg = { k => 'name', n => $n }; } |
|
|
466
|
|
|
|
|
1679
|
|
|
322
|
|
|
|
|
|
|
else { |
|
323
|
0
|
|
|
|
|
0
|
croak "Unexpected token in path segment: $k"; |
|
324
|
|
|
|
|
|
|
} |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
# optional name#index |
|
327
|
661
|
100
|
100
|
|
|
2213
|
if ( $seg->{k} eq 'name' && $lx->peek_kind eq 'INDEX' ) { |
|
328
|
1
|
|
|
|
|
4
|
$seg->{i} = $lx->next_tok->{v}; |
|
329
|
|
|
|
|
|
|
} |
|
330
|
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
# qualifiers |
|
332
|
661
|
|
|
|
|
1387
|
$seg->{q} = _parse_qualifiers($lx); |
|
333
|
|
|
|
|
|
|
|
|
334
|
661
|
|
|
|
|
1729
|
return $seg; |
|
335
|
|
|
|
|
|
|
} |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
sub _parse_qualifiers { |
|
338
|
665
|
|
|
665
|
|
2324
|
my ( $lx ) = @_; |
|
339
|
665
|
|
|
|
|
955
|
my @q; |
|
340
|
|
|
|
|
|
|
|
|
341
|
665
|
|
|
|
|
1427
|
while ( $lx->peek_kind eq 'LBRACK' ) { |
|
342
|
96
|
|
|
|
|
276
|
$lx->next_tok; |
|
343
|
96
|
|
|
|
|
216
|
my $e = _parse_expression($lx); |
|
344
|
96
|
|
|
|
|
345
|
$lx->expect('RBRACK'); |
|
345
|
96
|
|
|
|
|
289
|
push @q, $e; |
|
346
|
|
|
|
|
|
|
} |
|
347
|
|
|
|
|
|
|
|
|
348
|
665
|
|
|
|
|
1677
|
return \@q; |
|
349
|
|
|
|
|
|
|
} |
|
350
|
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
1; |