File Coverage

blib/lib/Jmespath/Parser.pm
Criterion Covered Total %
statement 329 347 94.8
branch 77 82 93.9
condition 8 9 88.8
subroutine 67 69 97.1
pod 0 3 0.0
total 481 510 94.3


line stmt bran cond sub pod time code
1             package Jmespath::Parser;
2 2     2   15856 use strict;
  2         3  
  2         43  
3 2     2   6 use warnings;
  2         2  
  2         35  
4 2     2   292 use Jmespath;
  2         2  
  2         48  
5 2     2   736 use Jmespath::Lexer;
  2         4  
  2         60  
6 2     2   631 use Jmespath::Ast;
  2         3  
  2         42  
7 2     2   284 use Jmespath::Visitor;
  2         2  
  2         36  
8 2     2   592 use Jmespath::ParsedResult;
  2         5  
  2         54  
9 2     2   614 use Jmespath::IncompleteExpressionException;
  2         4  
  2         74  
10 2     2   10 use List::Util qw(any);
  2         2  
  2         124  
11 2     2   10 use Try::Tiny;
  2         2  
  2         5622  
12              
13             my $BINDING_POWER = { 'eof' => 0,
14             'unquoted_identifier' => 0,
15             'quoted_identifier' => 0,
16             'literal' => 0,
17             'rbracket' => 0,
18             'rparen' => 0,
19             'comma' => 0,
20             'rbrace' => 0,
21             'number' => 0,
22             'current' => 0,
23             'expref' => 0,
24             'colon' => 0,
25             'pipe' => 1,
26             'or' => 2,
27             'and' => 3,
28             'eq' => 5,
29             'gt' => 5,
30             'lt' => 5,
31             'gte' => 5,
32             'lte' => 5,
33             'ne' => 5,
34             'flatten' => 9,
35             # Everything above stops a projection.
36             'star' => 20,
37             'filter' => 21,
38             'dot' => 40,
39             'not' => 45,
40             'lbrace' => 50,
41             'lbracket' => 55,
42             'lparen' => 60 };
43              
44             # The maximum binding power for a token that can stop
45             # a projection.
46             my $PROJECTION_STOP = 10;
47             # The _MAX_SIZE most recent expressions are cached in
48             # _CACHE hash.
49             my $CACHE = {};
50             my $MAX_SIZE = 128;
51              
52             sub new {
53 862     862 0 866 my ( $class, $lookahead ) = @_;
54 862         1117 my $self = bless {}, $class;
55 862 50       1704 $lookahead = 2 if not defined $lookahead;
56 862         1337 $self->{ tokenizer } = undef;
57 862         1789 $self->{ tokens } = [ undef ] * $lookahead;
58 862         1140 $self->{ buffer_size } = $lookahead;
59 862         906 $self->{ index } = 0;
60 862         1811 return $self;
61             }
62              
63             sub parse {
64 861     861 0 820 my ($self, $expression) = @_;
65              
66 861         1030 my $cached = $self->{_CACHE}->{$expression};
67 861 50       1288 return $cached if defined $cached;
68              
69 861         1192 my $parsed_result = $self->_do_parse($expression);
70              
71 760         995 $self->{_CACHE}->{expression} = $parsed_result;
72 760 50       510 if (scalar keys %{$self->{_CACHE}} > $MAX_SIZE) {
  760         1814  
73 0         0 $self->_free_cache_entries;
74             }
75 760         1804 return $parsed_result;
76             }
77              
78             sub _do_parse {
79 861     861   685 my ( $self, $expression ) = @_;
80 861         589 my $parsed;
81             try {
82 861     861   14611 $parsed = $self->_parse($expression);
83             } catch {
84 101 100   101   74593 if ($_->isa('Jmespath::LexerException')) {
    100          
    50          
85 10         261 $_->expression($self->{_expression});
86 10         16 $_->throw;
87             }
88             elsif ($_->isa('Jmespath::IncompleteExpressionException')) {
89 11         322 $_->expression($self->{_expression});
90 11         17 $_->throw;
91             }
92             elsif ($_->isa('Jmespath::ParseException')) {
93 80         2084 $_->expression($self->{_expression});
94 80         141 $_->throw;
95             }
96             else {
97 0         0 $_->throw;
98             }
99 861         3248 };
100 760         7600 return $parsed;
101             }
102              
103             sub _parse {
104 861     861   818 my ( $self, $expression ) = @_;
105 861         976 $self->{_expression} = $expression;
106 861         794 $self->{_index} = 0;
107 861         1997 $self->{_tokens} = Jmespath::Lexer->new->tokenize($expression);
108              
109 851         3041 my $parsed = $self->_expression(0); #binding_power = 0
110 764 100       898 if ($self->_current_token_type ne 'eof') {
111 4         5 my $t = $self->_lookahead_token(0);
112             return Jmespath::ParseException->new(lex_position => $t->{start},
113             token_value => $t->{value},
114             token_type => $t->{type},
115 4         14 message => "Unexpected token: " . $t->{value})->throw;
116             }
117              
118 760         1754 return Jmespath::ParsedResult->new($expression, $parsed);
119             }
120              
121              
122             sub _expression {
123 1899     1899   1759 my ( $self, $binding_power ) = @_;
124 1899 100       2103 $binding_power = defined $binding_power ? $binding_power : 0;
125              
126             # Get the current token under evaluation
127 1899         2172 my $left_token = $self->_lookahead_token(0);
128              
129             # Advance the token index
130 1899         2350 $self->_advance;
131              
132 1899         1216 my $nud_function = \&{'_token_nud_' . $left_token->{type}};
  1899         3290  
133 1899 100       2862 if ( not defined &$nud_function ) { $self->_error_nud_token($left_token); }
  27         38  
134              
135 1872         2078 my $left_ast = &$nud_function($self, $left_token);
136 1852         2472 my $current_token = $self->_current_token_type;
137              
138 1852         3452 while ( $binding_power < $BINDING_POWER->{$current_token} ) {
139 991         653 my $led = \&{'_token_led_' . $current_token};
  991         1469  
140              
141 991 100       1214 if (not defined &$led) {
142 10         17 $self->_error_led_token($self->_lookahead_token(0));
143             }
144             else {
145 981         1065 $self->_advance;
146 981         1109 $left_ast = &$led($self, $left_ast);
147 918         1239 $current_token = $self->_current_token_type;
148             }
149             }
150 1779         1895 return $left_ast;
151             }
152              
153             sub _token_nud_literal {
154 226     226   181 my ($self, $token) = @_;
155 226         428 return Jmespath::Ast->literal($token->{value});
156             }
157              
158             sub _token_nud_unquoted_identifier {
159 1356     1356   1022 my ($self, $token) = @_;
160 1356         2886 return Jmespath::Ast->field($token->{value});
161             }
162              
163             sub _token_nud_quoted_identifier {
164 97     97   95 my ($self, $token) = @_;
165              
166 97         268 my $field = Jmespath::Ast->field($token->{value});
167              
168             # You can't have a quoted identifier as a function name.
169 97 100       157 if ( $self->_current_token_type eq 'lparen' ) {
170 2         5 my $t = $self->_lookahead_token(0);
171             Jmespath::ParseException
172             ->new( lex_position => 0,
173             token_value => $t->{value},
174             token_type => $t->{type},
175 2         15 message => 'Quoted identifier not allowed for function names.')
176             ->throw;
177             }
178 95         102 return $field;
179             }
180              
181             sub _token_nud_star {
182 36     36   30 my ($self, $token) = @_;
183 36         83 my $left = Jmespath::Ast->identity;
184 36         33 my $right;
185 36 100       40 if ( $self->_current_token_type eq 'rbracket' ) {
186 3         8 $right = Jmespath::Ast->identity;
187             }
188             else {
189 33         60 $right = $self->_parse_projection_rhs( $BINDING_POWER->{ star } );
190             }
191 35         79 return Jmespath::Ast->value_projection($left, $right);
192             }
193              
194             sub _token_nud_filter {
195 3     3   5 my ($self, $token) = @_;
196 3         9 return $self->_token_led_filter(Jmespath::Ast->identity);
197             }
198              
199             sub _token_nud_lbrace {
200 12     12   14 my ($self, $token) = @_;
201 12         23 return $self->_parse_multi_select_hash;
202             }
203              
204             sub _token_nud_lparen {
205 16     16   17 my ($self, $token) = @_;
206 16         25 my $expression = $self->_expression;
207 12         19 $self->_match('rparen');
208 11         11 return $expression;
209             }
210              
211             sub _token_nud_flatten {
212 2     2   3 my ($self, $token) = @_;
213 2         8 my $left = Jmespath::Ast->flatten(Jmespath::Ast->identity);
214 2         7 my $right = $self->_parse_projection_rhs( $BINDING_POWER->{ flatten } );
215 2         7 return Jmespath::Ast->projection($left, $right);
216             }
217              
218             sub _token_nud_not {
219 18     18   15 my ($self, $token) = @_;
220 18         49 my $expr = $self->_expression( $BINDING_POWER->{ not } );
221 14         30 return Jmespath::Ast->not_expression($expr);
222             }
223              
224             sub _token_nud_lbracket {
225 57     57   54 my ($self, $token) = @_;
226 57 100 100 80   170 if (any { $_ eq $self->_current_token_type } qw(number colon)) {
  80 100       98  
227 42         72 my $right = $self->_parse_index_expression;
228 38         85 return $self->_project_if_slice(Jmespath::Ast->identity, $right);
229             }
230             elsif ($self->_current_token_type eq 'star' and
231             $self->_lookahead(1) eq 'rbracket') {
232 10         14 $self->_advance;
233 10         15 $self->_advance;
234 10         19 my $right = $self->_parse_projection_rhs( $BINDING_POWER->{ star } );
235 10         27 return Jmespath::Ast->projection(Jmespath::Ast->identity, $right);
236             }
237             else {
238 5         15 return $self->_parse_multi_select_list;
239             }
240             }
241              
242             sub _parse_index_expression {
243 158     158   155 my ($self) = @_;
244             # We're here:
245             # [<current>
246             # ^
247             # | current token
248 158 100 100     186 if ($self->_lookahead(0) eq 'colon' or
249             $self->_lookahead(1) eq 'colon') {
250 45         69 return $self->_parse_slice_expression;
251             }
252             else {
253             #parse the syntax [number]
254 113         152 my $node = Jmespath::Ast->index_of($self->_lookahead_token(0)->{value});
255 113         138 $self->_advance;
256 113         128 $self->_match('rbracket');
257 109         118 return $node;
258             }
259             }
260              
261             sub _parse_slice_expression {
262 45     45   36 my ($self) = @_;
263             # [start:end:step]
264             # Where start, end, and step are optional.
265             # The last colon is optional as well.
266 45         54 my @parts = (undef, undef, undef);
267 45         27 my $index = 0;
268 45         59 my $current_token = $self->_current_token_type;
269 45   66     160 while ($current_token ne 'rbracket' and $index < 3) {
270 143 100       187 if ($current_token eq 'colon') {
    100          
271 70         38 $index += 1;
272 70 100       92 if ( $index == 3 ) {
273 2         5 $self->_raise_parse_error_for_token($self->_lookahead_token(0),
274             'syntax error');
275             }
276 68         72 $self->_advance;
277             }
278             elsif ($current_token eq 'number') {
279 68         75 $parts[$index] = $self->_lookahead_token(0)->{value};
280 68         87 $self->_advance;
281             }
282             else {
283 5         7 $self->_raise_parse_error_for_token( $self->_lookahead_token(0),
284             'syntax error');
285 0         0 $current_token = $self->_current_token_type;
286             }
287 136         125 $current_token = $self->_current_token_type;
288             }
289 38         63 $self->_match('rbracket');
290 38         91 return Jmespath::Ast->slice(@parts);
291             }
292              
293             sub _token_nud_current {
294 20     20   20 my ($self, $token) = @_;
295 20         56 return Jmespath::Ast->current_node;
296             }
297              
298             sub _token_nud_expref {
299 29     29   31 my ($self, $token) = @_;
300 29         52 my $expression = $self->_expression( $BINDING_POWER->{ expref } );
301 28         50 return Jmespath::Ast->expref($expression);
302             }
303              
304             sub _token_led_dot {
305 221     221   179 my ($self, $left) = @_;
306              
307 221 100       219 if ($self->_current_token_type ne 'star') {
308              
309             # Begin the evaluation of the subexpression.
310 201         323 my $right = $self->_parse_dot_rhs( $BINDING_POWER->{ dot } );
311              
312 174 100       385 if ($left->{type} eq 'subexpression') {
313 21         17 push @{$left->{children}}, $right;
  21         36  
314 21         25 return $left;
315             }
316              
317             # We have identified a subexpression, but the current AST is not a
318             # subexpression. Convert to a subexpression here.
319 153         337 return Jmespath::Ast->subexpression([$left, $right]);
320             }
321 20         31 $self->_advance;
322 20         35 my $right = $self->_parse_projection_rhs( $BINDING_POWER->{ dot } );
323 20         55 return Jmespath::Ast->value_projection($left, $right);
324             }
325              
326             sub _token_led_pipe {
327 22     22   22 my ($self, $left) = @_;
328 22         36 my $right = $self->_expression( $BINDING_POWER->{ pipe } );
329 22         45 return Jmespath::Ast->pipe_oper($left, $right);
330             }
331              
332             sub _token_led_or {
333 51     51   42 my ($self, $left) = @_;
334 51         65 my $right = $self->_expression( $BINDING_POWER->{ or } );
335 48         90 return Jmespath::Ast->or_expression($left, $right);
336             }
337              
338             sub _token_led_and {
339 30     30   25 my ($self, $left) = @_;
340 30         45 my $right = $self->_expression( $BINDING_POWER->{ and } );
341 30         62 return Jmespath::Ast->and_expression($left, $right);
342             }
343              
344             sub _token_led_lparen {
345 178     178   149 my ($self, $left) = @_;
346 178 100       316 if ( $left->{type} ne 'field' ) {
347             # 0 - first func arg or closing paren.
348             # -1 - '(' token
349             # -2 - invalid function "name".
350 1         2 my $prev_t = $self->_lookahead_token(-2);
351 1         3 my $message = "Invalid function name '" . $prev_t->{value} ."'";
352             Jmespath::ParseException
353             ->new( lex_position => $prev_t->{start},
354             token_value => $prev_t->{value},
355             token_type => $prev_t->{type},
356 1         5 message => $message)
357             ->throw;
358             }
359 177         153 my $name = $left->{value};
360 177         131 my $args = [];
361 177         204 while (not $self->_current_token_type eq 'rparen') {
362 252         372 my $expression = $self->_expression;
363 252 100       293 if ( $self->_current_token_type eq 'comma') {
364 77         95 $self->_match('comma');
365             }
366 252         388 push @$args, $expression;
367             }
368 177         223 $self->_match('rparen');
369 177         301 return Jmespath::Ast->function_expression($name, $args);
370             }
371              
372             sub _token_led_filter {
373 86     86   70 my ($self, $left) = @_;
374 86         71 my $right;
375 86         102 my $condition = $self->_expression(0);
376 82         107 $self->_match('rbracket');
377 81 100       89 if ( $self->_current_token_type eq 'flatten' ) {
378 1         4 $right = Jmespath::Ast->identity;
379             }
380             else {
381 80         127 $right = $self->_parse_projection_rhs( $BINDING_POWER->{ filter } );
382             }
383              
384 81         161 return Jmespath::Ast->filter_projection($left, $right, $condition);
385             }
386              
387             sub _token_led_eq {
388 82     82   68 my ($self, $left) = @_;
389 82         106 return $self->_parse_comparator($left, 'eq');
390             }
391              
392             sub _token_led_ne {
393 16     16   14 my ($self, $left) = @_;
394 16         24 return $self->_parse_comparator($left, 'ne');
395             }
396              
397             sub _token_led_gt {
398 8     8   8 my ($self, $left) = @_;
399 8         13 return $self->_parse_comparator($left, 'gt');
400             }
401              
402             sub _token_led_gte {
403 2     2   3 my ($self, $left) = @_;
404 2         5 return $self->_parse_comparator($left, 'gte');
405             }
406              
407             sub _token_led_lt {
408 11     11   10 my ($self, $left) = @_;
409 11         18 return $self->_parse_comparator($left, 'lt');
410             }
411              
412             sub _token_led_lte {
413 2     2   3 my ($self, $left) = @_;
414 2         4 return $self->_parse_comparator($left, 'lte');
415             }
416              
417             sub _token_led_flatten {
418 94     94   80 my ($self, $left) = @_;
419 94         180 $left = Jmespath::Ast->flatten($left);
420 94         178 my $right = $self->_parse_projection_rhs( $BINDING_POWER->{ flatten } );
421 90         286 return Jmespath::Ast->projection($left, $right);
422             }
423              
424             sub _token_led_lbracket {
425 181     181   150 my ($self, $left) = @_;
426 181         205 my $token = $self->_lookahead_token(0);
427 181 100   260   498 if ( any { $_ eq $token->{type}} qw(number colon) ) {
  260         357  
428 116         176 my $right = $self->_parse_index_expression();
429 109 100       209 if ($left->{type} eq 'index_expression') {
430 17         14 push @{$left->{children}}, $right;
  17         26  
431 17         19 return $left;
432             }
433 92         127 return $self->_project_if_slice($left, $right);
434             }
435             else {
436 65         94 $self->_match('star');
437 59         67 $self->_match('rbracket');
438 58         97 my $right = $self->_parse_projection_rhs( $BINDING_POWER->{ star } );
439 51         133 return Jmespath::Ast->projection($left, $right);
440             }
441             }
442              
443             sub _project_if_slice {
444 130     130   120 my ($self, $left, $right) = @_;
445 130         262 my $index_expr = Jmespath::Ast->index_expression([$left, $right]);
446 130 100       211 if ( $right->{type} eq 'slice' ) {
447             return Jmespath::Ast->projection( $index_expr,
448 38         60 $self->_parse_projection_rhs($BINDING_POWER->{star}));
449             }
450              
451 92         127 return $index_expr;
452             }
453              
454             sub _parse_comparator {
455 121     121   109 my ($self, $left, $comparator) = @_;
456 121         161 my $right = $self->_expression( $BINDING_POWER->{ $comparator } );
457 119         230 return Jmespath::Ast->comparator($comparator, $left, $right);
458             }
459              
460             sub _parse_multi_select_list {
461 40     40   36 my ($self) = @_;
462 40         40 my $expressions = [];
463 40         26 my $result;
464             try {
465 40     40   793 while (1) {
466 66         84 my $expression = $self->_expression;
467 58         63 push @$expressions, $expression;
468 58 100       68 last if ($self->_current_token_type eq 'rbracket');
469 27         43 $self->_match('comma');
470             }
471 31         41 $self->_match('rbracket');
472 31         65 $result = Jmespath::Ast->multi_select_list($expressions);
473             } catch {
474 9     9   6948 $_->throw;
475 40         171 };
476 31         303 return $result;
477             }
478              
479              
480             sub _parse_multi_select_hash {
481 42     42   42 my ($self) = @_;
482 42         38 my @pairs;
483 42         30 while (1) {
484 72         77 my $key_token = $self->_lookahead_token(0);
485             # Before getting the token value, verify it's
486             # an identifier.
487 72         126 $self->_match_multiple_tokens( [ 'quoted_identifier', 'unquoted_identifier' ]);
488 67         76 my $key_name = $key_token->{ value };
489 67         74 $self->_match('colon');
490 65         78 my $value = $self->_expression(0);
491 64         127 my $node = Jmespath::Ast->key_val_pair( $key_name,
492             $value );
493 64         70 push @pairs, $node;
494 64 100       71 if ( $self->_current_token_type eq 'comma' ) {
    100          
495 29         33 $self->_match('comma');
496             }
497             elsif ( $self->_current_token_type eq 'rbrace' ) {
498 34         46 $self->_match('rbrace');
499 34         45 last;
500             }
501             }
502 34         70 return Jmespath::Ast->multi_select_hash(\@pairs);
503             }
504              
505             sub _parse_projection_rhs {
506 335     335   287 my ($self, $binding_power) = @_;
507 335 100       366 if ( $BINDING_POWER->{ $self->_current_token_type } < $PROJECTION_STOP) {
    100          
    100          
    100          
508 160         307 return Jmespath::Ast->identity();
509             }
510             elsif ($self->_current_token_type eq 'lbracket') {
511 18         28 return $self->_expression( $binding_power );
512             }
513             elsif ($self->_current_token_type eq 'filter') {
514 1         3 return $self->_expression( $binding_power );
515             }
516             elsif ($self->_current_token_type eq 'dot') {
517 155         182 $self->_match('dot');
518 155         240 return $self->_parse_dot_rhs($binding_power);
519             }
520              
521 1         4 $self->_raise_parse_error_for_token($self->_lookahead_token(0),
522             'syntax error');
523 0         0 return;
524             }
525              
526             sub _parse_dot_rhs {
527 356     356   301 my ($self, $binding_power) = @_;
528             # From the grammar:
529             # expression '.' ( identifier /
530             # multi-select-list /
531             # multi-select-hash /
532             # function-expression /
533             # *
534             # In terms of tokens that means that after a '.',
535             # you can have:
536             # my $lookahead = $self->_current_token_type;
537              
538             # What token do we have next in the index
539 356         335 my $lookahead = $self->_current_token_type;
540              
541             # Common case "foo.bar", so first check for an identifier.
542 356 100   800   1037 if ( any { $_ eq $lookahead } qw(quoted_identifier unquoted_identifier star) ) {
  800 100       943  
    100          
543 273         411 return $self->_expression( $binding_power );
544             }
545             elsif ( $lookahead eq 'lbracket' ) {
546 35         56 $self->_match('lbracket');
547 35         58 return $self->_parse_multi_select_list;
548             }
549             elsif ( $lookahead eq 'lbrace' ) {
550 30         177 $self->_match('lbrace');
551 30         47 return $self->_parse_multi_select_hash;
552             }
553              
554 18         33 my $t = $self->_lookahead_token(0);
555 18         26 my @allowed = qw(quoted_identifier unquoted_identified lbracket lbrace);
556 18         50 my $msg = 'Expecting: ' . join(' ', @allowed) . ', got: ' . $t->{ type };
557 18         58 $self->_raise_parse_error_for_token( $t, $msg )->throw;
558 0         0 return;
559             }
560              
561             sub _error_nud_token {
562 27     27   23 my ($self, $token) = @_;
563 27 100       49 if ( $token->{type} eq 'eof' ) {
564             Jmespath::IncompleteExpressionException->new( lex_expression => $token->{ start },
565             token_value => $token->{ value },
566 5         17 token_type => $token->{ type } )->throw;
567             }
568 22         28 $self->_raise_parse_error_for_token($token, 'invalid token');
569 0         0 return;
570             }
571              
572             sub _error_led_token {
573 10     10   8 my ($self, $token) = @_;
574 10         15 $self->_raise_parse_error_for_token($token, 'invalid token');
575 0         0 return;
576             }
577              
578             sub _match {
579 1031     1031   850 my ($self, $token_type) = @_;
580 1031 100       967 if ($self->_current_token_type eq $token_type ) {
581 1015         1153 $self->_advance();
582             }
583             else {
584 16         22 $self->_raise_parse_error_maybe_eof( $token_type,
585             $self->_lookahead_token(0) )->throw;
586             }
587 1015         780 return;
588             }
589              
590             sub _match_multiple_tokens {
591 72     72   63 my ( $self, $token_types ) = @_;
592              
593 72 100   129   170 if ( not any { $_ eq $self->_current_token_type } @$token_types ) {
  129         135  
594 5         6 $self->_raise_parse_error_maybe_eof( $token_types,
595             $self->_lookahead_token(0) );
596             }
597              
598 67         124 $self->_advance();
599 67         52 return;
600             }
601              
602             sub _advance {
603 4251     4251   2849 my ($self) = @_;
604 4251         3143 $self->{ _index } += 1;
605 4251         3004 return;
606             }
607              
608             sub _current_token_type {
609 7422     7422   4779 my ($self) = @_;
610 7422         4997 return @{ $self->{ _tokens } }[ $self->{_index} ]->{type};
  7422         13037  
611             }
612              
613             # _lookahead
614             #
615             # retrieve the type of the token at position current + n.
616             sub _lookahead {
617 305     305   207 my ($self, $number) = @_;
618 305 50       304 $number = defined $number ? $number : 1;
619 305         232 return @{ $self->{ _tokens } }[ $self->{_index} + $number ]->{type};
  305         814  
620             }
621              
622             sub _lookahead_token {
623 2397     2397   1771 my ($self, $number) = @_;
624              
625 2397         1940 my $lookahead = @{$self->{ _tokens }}[ $self->{_index} + $number ];
  2397         2411  
626              
627 2397         2434 return $lookahead;
628             }
629              
630             sub _raise_parse_error_for_token {
631 58     58   48 my ($self, $token, $reason) = @_;
632 58         57 my $lex_position = $token->{ start };
633 58         41 my $actual_value = $token->{ value };
634 58         51 my $actual_type = $token->{ type };
635              
636 58         182 Jmespath::ParseException->new( lex_position => $lex_position,
637             token_value => $actual_value,
638             token_type => $actual_type,
639             message => $reason )->throw;
640 0         0 return;
641             }
642              
643             sub _raise_parse_error_maybe_eof {
644 21     21   17 my ($self, $expected_type, $token) = @_;
645 21         22 my $lex_position = $token->{ start };
646 21         19 my $actual_value = $token->{ value };
647 21         18 my $actual_type = $token->{ type };
648              
649 21 100       35 if ( $actual_type eq 'eof' ) {
650 6         30 Jmespath::IncompleteExpressionException
651             ->new( lex_position => $lex_position,
652             token_value => $actual_value,
653             token_type => $actual_type )
654             ->throw;
655             }
656              
657 15         25 my $message = "Expecting: $expected_type, got: $actual_type";
658              
659 15         39 Jmespath::ParseException
660             ->new( lex_position => $lex_position,
661             token_value => $actual_value,
662             token_type => $actual_type,
663             message => $message )
664             ->throw;
665 0           return;
666             }
667              
668             sub _free_cache_entries {
669 0     0     my ($self) = @_;
670 0           my $key = $self->{_CACHE}{(keys %{$self->{_CACHE}})[rand keys %{$self->{_CACHE}}]};
  0            
  0            
671 0           delete $self->{ _CACHE }->{ $key };
672 0           return;
673             }
674              
675             sub purge {
676 0     0 0   my ($self, $cls) = @_;
677 0           $cls->_CACHE->clear();
678 0           return;
679             }
680              
681             1;