File Coverage

lib/App/GitFind/cmdline.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             ####################################################################
2             #
3             # This file was generated using Parse::Yapp version 1.21.
4             #
5             # Don't edit this file, use source file instead.
6             #
7             # ANY CHANGE MADE HERE WILL BE LOST !
8             #
9             ####################################################################
10             package App::GitFind::cmdline;
11 4     4   429469 use vars qw ( @ISA );
  4         16  
  4         157  
12 4     4   19 use strict;
  4         7  
  4         158  
13              
14             @ISA= qw ( Parse::Yapp::Driver );
15 4     4   3584 use Parse::Yapp::Driver;
  4         8356  
  4         1002  
16              
17             #line 9 "support/cmdline.yp"
18              
19              
20             # Imports {{{1
21              
22             use 5.010;
23             use strict;
24             use warnings;
25              
26             use App::GitFind::Base;
27             use App::GitFind::Actions;
28             use Hash::Merge;
29              
30             # Debugging support
31             BEGIN {
32             if($App::GitFind::cmdline::SHOW_AST // 0) {
33             require XXX;
34             XXX->import;
35             } else { # !SHOW_AST - make YYY a passthrough
36             no strict 'refs';
37             *{'App::GitFind::cmdline::YYY'} = sub {
38             return wantarray ? @_ : $_[0];
39             };
40             }
41             } #BEGIN
42              
43             BEGIN { YYY +{ 'YYY loaded' => 1 } }
44              
45             # }}}1
46             # Documentation {{{1
47              
48             =head1 NAME
49              
50             App::GitFind::cmdline - Command-line parser for git-find
51              
52             =head1 SYNOPSIS
53              
54             Generate the .pm file:
55              
56             yapp -m App::GitFind::cmdline -o lib/App/GitFind/cmdline.pm support/cmdline.yp
57              
58             And then:
59              
60             use App::GitFind::cmdline;
61             App::GitFind::cmdline::Parse(\@ARGV);
62              
63             For debugging output, define C<$SHOW_AST> before the C<use> statement:
64              
65             BEGIN { $App::GitFind::cmdline::SHOW_AST = 1; }
66              
67             =head1 FUNCTIONS
68              
69             =cut
70              
71             # }}}1
72             # Helpers for the parser {{{1
73              
74             # Merge any number of hashrefs together and return a hashref
75             sub _merge {
76             state $merger = Hash::Merge->new('RETAINMENT_PRECEDENT');
77             $merger->set_clone_behavior(false); # No cloning
78             my $retval = {};
79             for(@_) {
80             next unless ref eq 'HASH';
81             $retval = $merger->merge($retval, $_);
82             }
83             return $retval;
84             }
85              
86             # Check for { expr => FOO }
87             sub _is_single_expr {
88             return false unless @_ eq 1;
89             my $h = $_[0];
90             return false unless ref $h eq 'HASH';
91             return false unless keys(%$h) eq 1;
92             return false unless (keys %$h)[0] eq 'expr';
93             return true;
94             }
95              
96             # }}}1
97              
98              
99              
100             sub new {
101             my($class)=shift;
102             ref($class)
103             and $class=ref($class);
104              
105             my($self)=$class->SUPER::new( yyversion => '1.21',
106             yystates =>
107             [
108             {#State 0
109             ACTIONS => {
110             'REV' => 11,
111             'TEST' => 10,
112             'SWITCH' => 5,
113             'LPAREN' => 4,
114             'NOT' => 2,
115             'ACTION' => 3
116             },
117             DEFAULT => -1,
118             GOTOS => {
119             'switches_and_revs' => 9,
120             'expr' => 6,
121             'cmdline' => 8,
122             'element' => 7,
123             'maybeexprplus' => 1
124             }
125             },
126             {#State 1
127             DEFAULT => -2
128             },
129             {#State 2
130             ACTIONS => {
131             'expr4' => 12
132             }
133             },
134             {#State 3
135             DEFAULT => -22
136             },
137             {#State 4
138             ACTIONS => {
139             'TEST' => 10,
140             'LPAREN' => 4,
141             'ACTION' => 3,
142             'NOT' => 2
143             },
144             GOTOS => {
145             'element' => 7,
146             'expr' => 13
147             }
148             },
149             {#State 5
150             DEFAULT => -4
151             },
152             {#State 6
153             ACTIONS => {
154             'SWITCH' => 5,
155             'OR' => 15,
156             'REV' => 11,
157             'TEST' => 10,
158             'ACTION' => 3,
159             'NOT' => 21,
160             'COMMA' => 20,
161             'LPAREN' => 19,
162             'AND' => 18
163             },
164             DEFAULT => -9,
165             GOTOS => {
166             'switches_and_revs' => 14,
167             'subsequent_expr' => 17,
168             'element' => 16
169             }
170             },
171             {#State 7
172             DEFAULT => -11
173             },
174             {#State 8
175             ACTIONS => {
176             '' => 22
177             }
178             },
179             {#State 9
180             ACTIONS => {
181             'ACTION' => 3,
182             'NOT' => 2,
183             'LPAREN' => 4,
184             'SWITCH' => 25,
185             'REV' => 24,
186             'TEST' => 10
187             },
188             DEFAULT => -8,
189             GOTOS => {
190             'expr' => 6,
191             'element' => 7,
192             'maybeexprplus' => 23
193             }
194             },
195             {#State 10
196             DEFAULT => -21
197             },
198             {#State 11
199             DEFAULT => -5
200             },
201             {#State 12
202             DEFAULT => -16
203             },
204             {#State 13
205             ACTIONS => {
206             'AND' => 18,
207             'LPAREN' => 19,
208             'COMMA' => 20,
209             'NOT' => 21,
210             'ACTION' => 3,
211             'OR' => 15,
212             'TEST' => 10,
213             'RPAREN' => 26
214             },
215             GOTOS => {
216             'subsequent_expr' => 17,
217             'element' => 16
218             }
219             },
220             {#State 14
221             ACTIONS => {
222             'REV' => 24,
223             'SWITCH' => 25
224             },
225             DEFAULT => -10
226             },
227             {#State 15
228             ACTIONS => {
229             'NOT' => 2,
230             'ACTION' => 3,
231             'LPAREN' => 4,
232             'TEST' => 10
233             },
234             GOTOS => {
235             'element' => 7,
236             'expr' => 27
237             }
238             },
239             {#State 16
240             DEFAULT => -18
241             },
242             {#State 17
243             DEFAULT => -14
244             },
245             {#State 18
246             ACTIONS => {
247             'LPAREN' => 4,
248             'TEST' => 10,
249             'NOT' => 2,
250             'ACTION' => 3
251             },
252             GOTOS => {
253             'element' => 7,
254             'expr' => 28
255             }
256             },
257             {#State 19
258             ACTIONS => {
259             'LPAREN' => 4,
260             'TEST' => 10,
261             'NOT' => 2,
262             'ACTION' => 3
263             },
264             GOTOS => {
265             'expr' => 29,
266             'element' => 7
267             }
268             },
269             {#State 20
270             ACTIONS => {
271             'TEST' => 10,
272             'LPAREN' => 4,
273             'ACTION' => 3,
274             'NOT' => 2
275             },
276             GOTOS => {
277             'element' => 7,
278             'expr' => 30
279             }
280             },
281             {#State 21
282             ACTIONS => {
283             'expr4' => 31
284             }
285             },
286             {#State 22
287             DEFAULT => 0
288             },
289             {#State 23
290             DEFAULT => -3
291             },
292             {#State 24
293             DEFAULT => -7
294             },
295             {#State 25
296             DEFAULT => -6
297             },
298             {#State 26
299             DEFAULT => -17
300             },
301             {#State 27
302             ACTIONS => {
303             'TEST' => 10,
304             'NOT' => 21,
305             'ACTION' => 3,
306             'LPAREN' => 19,
307             'AND' => 18
308             },
309             DEFAULT => -13,
310             GOTOS => {
311             'element' => 16,
312             'subsequent_expr' => 17
313             }
314             },
315             {#State 28
316             ACTIONS => {
317             'ACTION' => 3,
318             'NOT' => 21,
319             'LPAREN' => 19,
320             'TEST' => 10
321             },
322             DEFAULT => -15,
323             GOTOS => {
324             'subsequent_expr' => 17,
325             'element' => 16
326             }
327             },
328             {#State 29
329             ACTIONS => {
330             'COMMA' => 20,
331             'ACTION' => 3,
332             'NOT' => 21,
333             'AND' => 18,
334             'LPAREN' => 19,
335             'RPAREN' => 32,
336             'TEST' => 10,
337             'OR' => 15
338             },
339             GOTOS => {
340             'subsequent_expr' => 17,
341             'element' => 16
342             }
343             },
344             {#State 30
345             ACTIONS => {
346             'NOT' => 21,
347             'ACTION' => 3,
348             'AND' => 18,
349             'LPAREN' => 19,
350             'TEST' => 10,
351             'OR' => 15
352             },
353             DEFAULT => -12,
354             GOTOS => {
355             'subsequent_expr' => 17,
356             'element' => 16
357             }
358             },
359             {#State 31
360             DEFAULT => -19
361             },
362             {#State 32
363             DEFAULT => -20
364             }
365             ],
366             yyrules =>
367             [
368             [#Rule 0
369             '$start', 2, undef
370             ],
371             [#Rule 1
372             'cmdline', 0,
373             sub
374             #line 119 "support/cmdline.yp"
375             { YYY +{} }
376             ],
377             [#Rule 2
378             'cmdline', 1,
379             sub
380             #line 120 "support/cmdline.yp"
381             { YYY $_[1] }
382             ],
383             [#Rule 3
384             'cmdline', 2,
385             sub
386             #line 122 "support/cmdline.yp"
387             { YYY _merge($_[1], $_[2]) }
388             ],
389             [#Rule 4
390             'switches_and_revs', 1,
391             sub
392             #line 127 "support/cmdline.yp"
393             { YYY +{ switches => {$_[1]=>[true]} } }
394             ],
395             [#Rule 5
396             'switches_and_revs', 1,
397             sub
398             #line 132 "support/cmdline.yp"
399             { YYY +{ revs => [$_[1]] } }
400             ],
401             [#Rule 6
402             'switches_and_revs', 2,
403             sub
404             #line 134 "support/cmdline.yp"
405             { YYY _merge($_[1], +{ switches => {$_[2]=>[true]} }) }
406             ],
407             [#Rule 7
408             'switches_and_revs', 2,
409             sub
410             #line 136 "support/cmdline.yp"
411             { YYY _merge($_[1], +{ revs => [$_[2]] }) }
412             ],
413             [#Rule 8
414             'maybeexprplus', 0,
415             sub
416             #line 142 "support/cmdline.yp"
417             { YYY +{} }
418             ],
419             [#Rule 9
420             'maybeexprplus', 1,
421             sub
422             #line 143 "support/cmdline.yp"
423             { YYY +{ expr => $_[1] } }
424             ],
425             [#Rule 10
426             'maybeexprplus', 2,
427             sub
428             #line 145 "support/cmdline.yp"
429             { YYY +{ expr => $_[1], %{$_[2]} } }
430             ],
431             [#Rule 11
432             'expr', 1, undef
433             ],
434             [#Rule 12
435             'expr', 3,
436             sub
437             #line 152 "support/cmdline.yp"
438             { YYY +{ SEQ => [@_[1,3]] } }
439             ],
440             [#Rule 13
441             'expr', 3,
442             sub
443             #line 153 "support/cmdline.yp"
444             { YYY +{ OR => [@_[1,3]] } }
445             ],
446             [#Rule 14
447             'expr', 2,
448             sub
449             #line 163 "support/cmdline.yp"
450             { YYY +{ AND => [@_[1,2]] } }
451             ],
452             [#Rule 15
453             'expr', 3,
454             sub
455             #line 164 "support/cmdline.yp"
456             { YYY +{ AND => [@_[1,3]] } }
457             ],
458             [#Rule 16
459             'expr', 2,
460             sub
461             #line 165 "support/cmdline.yp"
462             { YYY +{ NOT => $_[2] } }
463             ],
464             [#Rule 17
465             'expr', 3,
466             sub
467             #line 166 "support/cmdline.yp"
468             { YYY $_[2] }
469             ],
470             [#Rule 18
471             'subsequent_expr', 1, undef
472             ],
473             [#Rule 19
474             'subsequent_expr', 2,
475             sub
476             #line 171 "support/cmdline.yp"
477             { YYY +{ NOT => $_[2] } }
478             ],
479             [#Rule 20
480             'subsequent_expr', 3,
481             sub
482             #line 172 "support/cmdline.yp"
483             { YYY $_[2] }
484             ],
485             [#Rule 21
486             'element', 1, undef
487             ],
488             [#Rule 22
489             'element', 1,
490             sub
491             #line 178 "support/cmdline.yp"
492             {
493             $_[0]->YYData->{SAW_NON_PRUNE_ACTION} = true if $_[1] ne 'prune';
494             YYY $_[1];
495             }
496             ]
497             ],
498             @_);
499             bless($self,$class);
500             }
501              
502             #line 184 "support/cmdline.yp"
503              
504              
505             #############################################################################
506             # Footer
507              
508             # Helpers for the tokenizer {{{1
509              
510             # Flag a ref as invalid without using regexes.
511             # Implements https://git-scm.com/docs/git-check-ref-format as archived at
512             # https://web.archive.org/web/20190725153529/https://git-scm.com/docs/git-check-ref-format
513              
514             sub _is_ref_ok {
515             my $arg = @_ ? $_[0] : $_;
516              
517             return false unless defined $arg and length($arg)>0;
518              
519             #1 - restrictions on slash-separated components
520             if(index($arg, '/') != -1) {
521             return false if index($arg, '/.') != -1 #internal components
522             || index($arg, '.lock/') != -1
523             || substr($arg, 0, 1) eq '.' #components at start/end
524             || substr($arg, -5) eq '.lock';
525             }
526              
527             # Ignore #2 - assume --allow-onelevel
528              
529             #3
530             return false if index($arg, '..') != -1;
531              
532             #4 - require the caller to check that
533             #5 - require the caller to check that - assume NOT --refspec-pattern
534              
535             #6 - assume NOT --normalize
536             return false if substr($arg, 0, 1) eq '/'
537             || substr($arg, -1) eq '/'
538             || index($arg, '//') != -1;
539              
540             # #7. Also prohibits ".", which is OK for git-find since it is
541             # fairly ambiguous between a ref/rev and a path.
542             return false if substr($arg, -1) eq '.';
543              
544             #8
545             return false if index($arg, '@{') != -1;
546              
547             #9 ('@') - ignore this one for simplicity in the rev test below.
548              
549             #10 - require the caller to check that
550              
551             # Extra: Prohibit refs that start with '--' since they are arguably
552             # ambiguous with command-line options (and I can't make them work
553             # with git anyway).
554             return false if substr($arg, 0, 2) eq '--';
555              
556             return true; # It's OK if we got here
557             } #_is_ref_ok()
558              
559             #use re 'debug';
560              
561             # Regex to match a rev or range of revs, i.e., something we should pass to git
562             my $_rev_regex =
563             qr`(?xi) # backtick delimiter because it doesn't occur in the regex text
564             (?&RevRange)
565              
566             (?(DEFINE)
567              
568             (?<RevRange> ^(?:
569             # :/text, :/!-text, :/!!text
570             (?::/ #(?{ print "# saw colon slash\n"; })
571             (?:
572             ![!\-](?:.+) #(?{print "# 4\n";})
573             | [^!].* #(?{print "# 5\u";})
574             )
575             )
576              
577             # :[n:]path. NOTE: we prohibit starting the path with
578             # / if there is no number, in order to disambiguate
579             # the :/ text-search cases.
580             | :\d+:(?:.+) #(?{print "# 2\n";})
581             | :[^/].* #(?{print "# 3\n";})
582              
583             # ^<rev>
584             | \^(?&Rev) #(?{print "# 6\n";})
585              
586             # rev:path
587             | (?&Rev):(?:.+) #(?{print "# 7\n";})
588              
589             # .. and ... differences, including x.., x..., x..y,
590             # and x...y. Also handles the fallthrough
591             # of revrange->rev->ref.
592             | (?&Rev)(?:\.{2,3}(?&Rev)?)?
593             #(?{print "# 8\n";})
594              
595             # ..rev and ...rev
596             | \.{2,3}(?&Rev)
597              
598             # at sign followed by braced item, and possibly
599             # preceded by a REF (not a rev). E.g.,
600             # HEAD@{1}@{1} doesn't work.
601             # refname - at sign - braced item (date, #, branch, "push")
602             | (?&Ref)?\@\{[^\}]+\}
603             #(?{print "# 9\n";})
604              
605             # git-rev-parse "Options for Objects" forms
606             | --all
607             | --(?:branches|tags|remotes)(?:=.+)?
608             | --(?:glob|exclude)=.+
609             | --disambiguate=[0-9a-f]{4,40}
610              
611             # git-rev-parse "Other Options" forms
612             | --(since|after|until|before)=.+
613              
614             )$) # End of RevRange
615              
616             (?<Rev> (?&Ref)(?&RefTrailer)* )
617             # This handles most of the cases.
618             # SHA1s, possibly abbreviated, are refs,
619             # as are git-describe outputs, whence RefTrailer*
620             # instead of RefTrailer+.
621              
622             (?<RefTrailer>
623             # For rev^[#] and rev~[#] forms
624             [~\^]\d*
625              
626             # For rev^{} forms (empty braces OK)
627             | \^\{[^\}]*\}
628              
629             # For rev^[@!] and rev^-n
630             | \^(?: \@ | ! | -\d* )
631             ) # End of RefTrailer
632              
633             (?<Ref>
634             ( \@ # '@' from git-rev-parse
635             | (?:[^\000-\037\177\ ~\^:\\?*\[.@/]
636             # git-check-ref-format #4, #5.
637             # [.@/] are handled below
638             | \.(?!\.) # . ok, but .. prohibited
639             | \@(?!\{) # @ ok, but @{ prohibited
640             | /(?!/) # / ok, but // prohibited
641              
642             )+?
643             )
644             (?(?{ _is_ref_ok($+) })|(?!))
645             # NOTE: $+ used since I couldn't get named capture groups
646             # with either %+ or %- to work
647             ) # End of <Ref>
648              
649             ) #End of (DEFINE)
650              
651             `xi; # End of qr`...` and an extra backtick to unconfuse vim-eyapp: `
652              
653             sub _is_valid_rev {
654             my $arg = @_ ? $_[0] : $_;
655              
656             return false unless defined $arg and length($arg)>0;
657             return scalar($arg =~ m{$_rev_regex});
658             } #_is_valid_rev()
659              
660             # Get an expression element from the array passed in $_[0].
661             my $ARGTEST_cached = App::GitFind::Actions::ARGTEST();
662             sub _consume_expression_element {
663             my $lrArgv = shift;
664             my @retval;
665              
666             #say STDERR "# Trying >>$lrArgv->[0]<<";
667             # TODO find(1) positional options, global options?
668              
669             # Regular options
670             if($lrArgv->[0] =~ $ARGTEST_cached) {
671             #say STDERR "# - matched";
672             my $arg = $1;
673             my %opts = %{App::GitFind::Actions::argdetails($arg)};
674              
675             # Save any non-parser information from the argdetails to be
676             # returned as part of the semantic value.
677             my %extras = %opts;
678             delete @extras{qw(token nparam)};
679              
680             # No-argument tests or actions
681             unless($opts{nparam}>0) {
682             #say STDERR "# - No parameters";
683             shift @$lrArgv;
684             return ($opts{token} => { name => $arg, %extras })
685             }
686              
687             # Consume additional arguments up to a regexp
688             if(ref $opts{nparam} eq 'Regexp') {
689             #say STDERR "# - parameters until $opts{nparam}";
690             die "Need argument(s) for --$arg" if @$lrArgv == 1;
691             my $lastarg;
692             #say STDERR "Args: ", join ' : ', @$lrArgv;
693             for(1..$#$lrArgv) {
694             $lastarg=$_, last if $lrArgv->[$_] =~ $opts{nparam};
695             }
696             die "--$arg needs an argument terminator matching $opts{nparam}"
697             unless defined $lastarg;
698              
699             # Set up to fall through to the numeric-params case
700             $opts{nparam} = $lastarg;
701             }
702              
703             # Consume additional positional arguments
704             #say STDERR "# - $opts{nparam} parameters";
705             die "Not enough parameters after --$arg (need $opts{nparam})"
706             unless @$lrArgv >= ($opts{nparam}+1); # +1 for $arg itself
707              
708             # Custom argument validation
709             if($opts{validator}) {
710             my $errmsg = $opts{validator}->(@{$lrArgv}[0..$opts{nparam}]);
711             die "--$arg argument error: $errmsg" if defined($errmsg);
712             }
713              
714             @retval = ($opts{token} => {
715             name => $arg,
716             params => [ @{$lrArgv}[1..$opts{nparam}] ],
717             %extras,
718             });
719             splice @$lrArgv, 0, $opts{nparam}+1;
720             return @retval;
721             }
722              
723             # Operators
724             my $arg = $lrArgv->[0];
725              
726             @retval = (COMMA => ',') if $arg eq ',';
727             @retval = (OR => '-o') if $arg =~ /^(?:-o|--o|-or|--or|\|\|)$/;
728             @retval = (AND => '-a') if $arg =~ /^(?:-a|--a|-and|--and|&&)$/;
729             @retval = (NOT => '!') if $arg =~ /^(?:-not|--not|!|\^)$/;
730             @retval = (LPAREN => '(') if $arg =~ /^[([]$/;
731             @retval = (RPAREN => ')') if $arg =~ /^[])]$/;
732              
733             if(@retval) {
734             shift @$lrArgv;
735             return @retval;
736             }
737              
738             return (); # Not an expression element
739             } #_consume_expression_element
740              
741             # Get a switch from the array passed in $_[0], if any.
742             # Removes the switch from the array if successful.
743             # Returns the token on success, and () on failure.
744             # TODO un-bundle switches; handle switches with args.
745             sub _consume_switch {
746             my $lrArgv = shift;
747             if($lrArgv->[0] =~ /^-([a-zA-z0-9\?])$/) { # non-bundled switch
748             shift @$lrArgv;
749             return (SWITCH => $1)
750             } elsif($lrArgv->[0] =~ /^--?(help|man|usage|version)$/) { # long switch
751             shift @$lrArgv;
752             return (SWITCH => $1);
753             }
754              
755             return ();
756             } #_consume_switch()
757              
758             # Consume a rev from the array in $_[0]
759             sub _consume_rev {
760             my $lrArgv = shift;
761             my $arg = $lrArgv->[0];
762             if(_is_valid_rev($arg)) {
763             shift @$lrArgv;
764             return (REV => $arg);
765             }
766              
767             return ();
768             } #_consume_rev()
769              
770             # }}}1
771             # Tokenizer and error-reporting routine for Parse::Yapp {{{1
772              
773             # The lexer
774             sub _next_token {
775             my $parser = shift;
776             my $lrArgv = $parser->YYData->{ARGV};
777             return ('', undef) unless @$lrArgv; # EOF
778             my @retval; # The eventual token we will return
779              
780             # TODO? in the expression, split trailing commas into their
781             # own arguments
782              
783             # Check for '--'
784             if($lrArgv->[0] eq '--') {
785             $parser->YYData->{ONLY_EXPRESSIONS} = true;
786             return ('', undef) unless @$lrArgv > 1;
787             # We are about to shift, so return EOF if this was the last arg.
788             shift(@$lrArgv);
789             }
790              
791             if($parser->YYData->{HAS_DASH_DASH}) {
792             # Split-arg mode: don't look for expressions before '--', or
793             # for switches or refs after '--'.
794             if(!$parser->YYData->{ONLY_EXPRESSIONS}) { # Look for switches/refs
795              
796             @retval = _consume_switch($lrArgv);
797             return @retval if @retval;
798              
799             @retval = _consume_rev($lrArgv);
800             if(@retval) { # _consume_rev always gives us two elements
801             if($retval[1] eq ']]') {
802             $parser->YYData->{SAW_RR} ||= true;
803             } else {
804             $parser->YYData->{SAW_NON_RR} ||= true;
805             }
806             return @retval;
807             }
808              
809             die "I don't understand argument '$lrArgv->[0]' before --";
810              
811             } else { # Look for expressions
812             @retval = _consume_expression_element($lrArgv);
813             return @retval if @retval;
814             die "I don't understand argument '$lrArgv->[0]' after --";
815             }
816              
817             } else {
818             # Merged-arg mode: any arg could be anything
819              
820             # Check for expressions. Look for these before checking for refs so
821             # that an expression that happens to look like a ref will be considered
822             # an expression instead of a ref.
823             my @retval = _consume_expression_element($lrArgv);
824             return @retval if @retval;
825              
826             # Next, look for switches. These are after expression elements
827             # so that -a and -o will not be parsed as switches.
828             @retval = _consume_switch($lrArgv);
829             return @retval if @retval;
830              
831             # Last of all, revs.
832             @retval = _consume_rev($lrArgv);
833             if(@retval) { # _consume_rev always gives us two elements
834             if($retval[1] eq ']]') {
835             $parser->YYData->{SAW_RR} ||= true;
836             } else {
837             $parser->YYData->{SAW_NON_RR} ||= true;
838             }
839             return @retval;
840             }
841              
842             die "I don't understand argument $lrArgv->[0]";
843             }
844              
845             die "Unexpected error while processing argument $lrArgv->[0]"; # Shouldn't happen
846             } #_next_token()
847              
848             # Report an error
849             sub _report_error {
850             my $parser = shift;
851             my $got = $parser->YYCurtok || '<end of input>';
852             my $val='';
853             $val = ' (' . $parser->YYCurval . ')' if $parser->YYCurval;
854             die 'Syntax error: could not understand ', $got, $val, "\n";
855             if(ref($parser->YYExpect) eq 'ARRAY') {
856             print 'Expected one of: ', join(',', @{$parser->YYExpect}), "\n";
857             }
858             return;
859             } #_report_error()
860              
861             # }}}1
862             # Top-level parse function {{{1
863              
864             =head2 Parse
865              
866             Parse arguments. Usage:
867              
868             my $hrArgs = App::GitFind::cmdline::Parse(\@ARGV);
869              
870             Modifies the C<@ARGV> array.
871              
872             =cut
873              
874             sub Parse {
875             my $lrArgv = shift or
876             (require Carp, Carp::croak 'Parse: Need an argument list');
877              
878             my $parser = __PACKAGE__->new;
879             my $hrData = $parser->YYData;
880              
881             # Data we use while parsing
882             $hrData->{HAS_DASH_DASH} = !!(scalar grep { $_ eq '--' } @$lrArgv);
883             $hrData->{ONLY_EXPRESSIONS} = false; # true once we hit '--'
884             $hrData->{ARGV} = $lrArgv;
885              
886             # Data we determine while parsing and return to the caller
887              
888             # Keep track of whether an action other than -prune has been seen.
889             # If not, -print is added automatically.
890             $hrData->{SAW_NON_PRUNE_ACTION} = false;
891              
892             # Keep track of the types of rev we've seen (]] or non-]])
893             $hrData->{SAW_RR} = false;
894             $hrData->{SAW_NON_RR} = false;
895              
896             my $hrRetval = $parser->YYParse(yylex => \&_next_token,
897             yyerror => \&_report_error,
898             (@_ ? (yydebug => $_[0]) : ()),
899             );
900              
901             # Add non-AST data to the retval
902             $hrRetval->{saw_nonprune_action} = $hrData->{SAW_NON_PRUNE_ACTION} if $hrRetval;
903             $hrRetval->{saw_rr} = $hrData->{SAW_RR};
904             $hrRetval->{saw_non_rr} = $hrData->{SAW_NON_RR};
905             return $hrRetval;
906             } #Parse()
907              
908             # }}}1
909             # Rest of the docs {{{1
910              
911             =head1 AUTHOR
912              
913             Christopher White C<< <cxw@cpan.org> >>
914              
915             =head1 COPYRIGHT
916              
917             MIT
918              
919             =cut
920              
921             # }}}1
922              
923             # vi: set fdm=marker: #
924              
925             1;