File Coverage

blib/lib/Array/PatternMatcher.pm
Criterion Covered Total %
statement 179 194 92.2
branch 56 66 84.8
condition 21 30 70.0
subroutine 25 26 96.1
pod 0 20 0.0
total 281 336 83.6


line stmt bran cond sub pod time code
1             package Array::PatternMatcher;
2              
3             require 5.005_62;
4 6     6   48310 use strict;
  6         15  
  6         232  
5 6     6   36 use warnings;
  6         10  
  6         206  
6 6     6   8281 use diagnostics;
  6         1356351  
  6         72  
7              
8             require Exporter;
9              
10             our @ISA = qw(Exporter);
11              
12              
13              
14 6     6   10061 use Carp::Datum qw(:all on);
  6         339094  
  6         1271  
15             #use Carp::Datum;
16              
17             #DLOAD_CONFIG(-config => "all(on)");
18             #DLOAD_CONFIG(-config => "all(off)");
19             #DLOAD_CONFIG(-config => "all(yes)");
20             #DLOAD_CONFIG(-config => "all(no)");
21             #DLOAD_CONFIG(-config => $ENV{Array_PatternMatcher_Trace});
22              
23 6     6   3843 use Data::Dumper;
  6         14  
  6         268  
24 6     6   6499 use Storable;
  6         20704  
  6         17797  
25             # Items to export into callers namespace by default. Note: do not export
26             # names by default without a very good reason. Use EXPORT_OK instead.
27             # Do not simply export all your public functions/methods/constants.
28              
29             # This allows declaration use Array::PatternMatcher ':all';
30             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
31             # will save memory.
32             our %EXPORT_TAGS = ( 'all' => [ qw(pat_match rest subseq
33            
34             ) ] );
35              
36             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
37              
38             our @EXPORT = qw(
39            
40             );
41             our $VERSION = '0.04';
42              
43              
44             # Preloaded methods go here.
45              
46              
47              
48             =head1 NAME
49              
50             Array::PatternMatcher - Pattern matching for arrays.
51              
52             =head1 SYNOPSIS
53              
54             This section inlines the entire test suite. Please excuse the ok()s.
55              
56             use Array::PatternMatcher;
57              
58             =head2 Matching logical variables to input stream
59            
60             # 1 - simple match of logical variable to input
61             my $pattern = 'AGE' ;
62             my $input = 969 ;
63             my $result = pat_match ($pattern, $input, {} ) ;
64             ok($result->{AGE}, 969) ;
65            
66             # 2 - if binding exists, it must equal the input
67             $input = 12;
68             my $new_result = pat_match ($pattern, $input, $result) ;
69             ok(!defined($new_result)) ;
70            
71             # 3 - bind the pattern logical variables to the input list
72            
73             $pattern = [qw(X Y)] ;
74             $input = [ 77, 45 ] ;
75             my $result = pat_match ($pattern, $input, {} ) ;
76             ok($result->{X}, 77) ;
77            
78             =head2 Matching segments (quantifying) portions of the input stream
79            
80             # 1
81             {
82             my $pattern = ['a', [qw(X *)], 'd'] ;
83             my $input = ['a', 'b', 'c', 'd'] ;
84            
85             my $result = pat_match ($pattern, $input, {} ) ;
86             ok ("@{$result->{X}}","b c") ;
87             }
88            
89             # 2
90             {
91            
92             my $pattern = ['a', [qw(X *)], [qw(Y *)], 'd'] ;
93             my $input = ['a', 'b', 'c', 'd'] ;
94             my $result = pat_match ($pattern, $input, {} ) ;
95             ok ("@{$result->{Y}}","b c") ;
96            
97             }
98             # 3
99             {
100             my $pattern = ['a', [qw(X +)], 'd'] ;
101             my $input = ['a', 'b', 'c', 'd'] ;
102             ok ("@{$result->{X}}","b c") ;
103             }
104             # 4
105             {
106             my $pattern = [ 'a', [qw(X ?)], 'c' ] ;
107             my $input = [ 'a', 'b', 'c' ] ;
108             my $result = pat_match ($pattern, $input, {} ) ;
109             ok ("$result->{X}","b") ;
110             }
111             # 5
112             {
113             my $pattern = [ qw(X OP Y is Z),
114             [
115             sub { "($_->{X} $_->{OP} $_->{Y}) == $_->{Z}" },
116             'IF?'
117             ]
118             ] ;
119             my $input = [qw(3 + 4 is 7) ] ;
120             my $result = pat_match ($pattern, $input, {} ) ;
121             ok ($result) ;
122             }
123            
124             =head2 Single-matching:
125            
126             Take a single input and a series of patterns and decide which pattern
127             matches the input:
128            
129             # 1 - Here all input patterns must match the input
130            
131             {
132             my @pattern ;
133             push @pattern, [ qw(X Y) ] ;
134             push @pattern, [ qw(22 Z ) ] ;
135             push @pattern, [ qw(M 33) ] ;
136            
137             my $input = [ qw(22 33) ] ;
138            
139             my $meta_pattern = [ 'AND?', \@pattern ] ;
140            
141             # if no bindings, add a binding between pattern and input
142             my $result = pat_match ($meta_pattern, $input, {} ) ;
143             ok ($result->{Z},33) ;
144             }
145            
146             # 2 - Here, any one of the patterns must match the input
147            
148             {
149             my @pattern ;
150             push @pattern, [ qw(99 22) ] ;
151             push @pattern, [ qw(33 22) ] ;
152             push @pattern, [ qw(44 3) ] ;
153             push @pattern, [ qw(22 Z) ] ;
154            
155             my $input = [ qw(22 33) ] ;
156            
157             my $meta_pattern = [ 'OR?', \@pattern ] ;
158            
159             # if no bindings, add a binding between pattern and input
160             my $result = pat_match ($meta_pattern, $input, {} ) ;
161             ok ($result->{Z},33) ;
162             }
163            
164             # 3 - Here, none of the patterns must match the input
165            
166             {
167             my @pattern ;
168             push @pattern, [ qw(99 22) ] ;
169             push @pattern, [ qw(33 22) ] ;
170             push @pattern, [ qw(44 3) ] ;
171             push @pattern, [ qw(22 Z) ] ;
172            
173             my $input = [ qw(22 33) ] ;
174            
175             my $meta_pattern = [ 'NOT?', \@pattern ] ;
176            
177             # if no bindings, add a binding between pattern and input
178             my $result = pat_match ($meta_pattern, $input, {} ) ;
179             ok (scalar keys %$result == 0) ;
180             }
181            
182             # 4 - here the input must satisfy the predicate
183             {
184             sub numberp { $_[0] =~ /\d+/ }
185            
186             my $pattern = [ qw(X age), [qw(IS? N), \&numberp] ] ;
187             my $input = [ qw(Mary age), 'thirty-four' ] ;
188            
189             # if no bindings, add a binding between pattern and input
190             my $result = pat_match ($pattern, $input, {} ) ;
191             ok (!defined($result));
192             }
193            
194             # 5 - same thing, but this time a failing result --- ''
195             # not undef because it is the return val of numberp
196             {
197             sub numberp { $_[0] =~ /\d+/ }
198            
199             my $pattern = [ qw(X age), [qw(IS? N), \&numberp] ] ;
200             my $input = [ qw(Mary age), 34 ] ;
201             my $result = pat_match ($pattern, $input, {} ) ;
202            
203             ok ($result->{N},34) ;
204             }
205            
206             =head2 Segment-matching:
207            
208             Match a chunk of the input stream using *, +, ?
209            
210             # 1 - * is greedy in this case, but not with 2 consecutve * patterns
211             {
212             my $pattern = ['a', [qw(X *)], 'd'] ;
213             my $input = ['a', 'b', 'c', 'd'] ;
214            
215             # if no bindings, add a binding between pattern and input
216             my $result = pat_match ($pattern, $input, {} ) ;
217             warn sprintf "X*RETVAL: %s", Data::Dumper::Dumper($result) ;
218             ok ("@{$result->{X}}","b c") ;
219             }
220             # 2 - X* gets nothing, Y* gets all it can:
221             {
222            
223             my $pattern = ['a', [qw(X *)], [qw(Y *)], 'd'] ;
224             my $input = ['a', 'b', 'c', 'd'] ;
225            
226             # if no bindings, add a binding between pattern and input
227             my $result = pat_match ($pattern, $input, {} ) ;
228             warn sprintf "X*Y*RETVAL: %s", Data::Dumper::Dumper($result) ;
229             ok ("@{$result->{Y}}","b c") ;
230            
231             }
232             # 3 - samething , but require at least one match for X
233             {
234             my $pattern = ['a', [qw(X +)], 'd'] ;
235             my $input = ['a', 'b', 'c', 'd'] ;
236            
237             my $result = pat_match ($pattern, $input, {} ) ;
238             warn sprintf "RETVAL: @{$result->{X}}" ;
239             ok ("@{$result->{X}}","b c") ;
240             }
241             # 4 - require 0 or 1 match for X
242             {
243             my $pattern = [ 'a', [qw(X ?)], 'c' ] ;
244             my $input = [ 'a', 'b', 'c' ] ;
245            
246            
247             my $result = pat_match ($pattern, $input, {} ) ;
248            
249             ok ("$result->{X}","b") ;
250             }
251             # 5 - evaluate a sub on the fly after match
252             {
253             my $pattern = [ qw(X OP Y is Z),
254             [
255             sub { "($_->{X} $_->{OP} $_->{Y}) == $_->{Z}" },
256             'IF?'
257             ]
258             ] ;
259             my $input = [qw(3 + 4 is 7) ] ;
260            
261             my $result = pat_match ($pattern, $input, {} ) ;
262            
263             ok ($result) ;
264             }
265             # --- 6 same thing, but fail
266             {
267             my $pattern = [ qw(X OP Y is Z),
268             [
269             sub { "($_->{X} $_->{OP} $_->{Y}) == $_->{Z}" },
270             'IF?'
271             ]
272             ] ;
273             my $input = [qw(3 + 4 is 8) ] ;
274            
275             my $result = pat_match ($pattern, $input, {} ) ;
276             warn sprintf "IF_RETVAL2: *%s*", Data::Dumper::Dumper($result);
277             ok ($result eq '') ;
278             }
279            
280              
281             =head1 DESCRIPTION
282              
283             Array::PatternMatcher is based directly on the pattern matcher in
284             Peter Norvig's excellent text
285             "Paradigms of AI Programming: Case Studies in Common Lisp".
286              
287             All in all, it basically offers a different way to work with an array.
288             Instead of manually indexing into the array and using if-thens to
289             validate and otherwise characterize the array, you can use
290             pattern-matching instead.
291              
292             =head2 EXPORT
293              
294             None by default.
295              
296             use Array::PatternMatcher qw(:all) exports pat_match(), rest(), subseq()
297              
298             =head1 Description of Pattern Matching
299              
300             The pattern-matching routine, pat-match, takes 3 arguments, a pattern,
301             an input, and a set of "bindings".
302              
303             The input is an array ref of constants:
304              
305             my $input_1 = [qw(how is it going dude) ] ;
306             my $input_2 = [qw(where is it going dude) ] ;
307             my $input_3 = [qw(when is it going pal) ] ;
308             my $input_4 = [qw(when is it flying chum) ] ;
309             my $input_5 = [qw(how is it hanging homeboy) ] ;
310              
311             The pattern is your spec on how you expect to match the input:
312              
313             my $pattern = [qw(ADJECTIVE is it VERB OBJECT)] ;
314              
315             =head2 Valid pattern elements:
316              
317             =over 4
318              
319             =item 1 a variable
320              
321             =item 2 a constant (a string or number)
322              
323             =item 3 a segment pattern
324              
325             =item 4 a meta-pattern to applied to the input
326              
327             =item 5 an array ref whose array consists of items 1 .. 4
328              
329             =back
330              
331              
332             The bindings is a hashref consisting of all logical variables
333             bound during the matching of the input to the pattern. Thus:
334              
335             use Array::PatternMatcher qw(:all);
336             {
337             my $b1 = pat_match $pattern, $input_1, {} ;
338              
339             # yields these bindings
340             { ADJECTIVE => 'how', VERB => 'going, OBJECT => 'dude' }
341             }
342             Skipping to input_4:
343             {
344             my $b1 = pat_match $pattern, $input_1, {} ;
345              
346             # yields these bindings
347             { ADJECTIVE => 'when', VERB => 'flying', OBJECT => 'chum' }
348             }
349              
350              
351             Please see the synopsis for comprehensive usage examples.
352              
353             =head1 BUGS
354              
355             Please report them, if possible submitting a test case similar to the
356             ones in the /t directory.
357              
358             =head1 AUTHOR
359              
360             Terrence M. Brannon, tbone@cpan.org
361              
362             =cut
363              
364              
365             sub match_variable {
366 26     26 0 1540 DFEATURE my $f_;
367 26         70974 my ($var,$input,$bindings) = @_;
368 26         83 my $binding = $bindings->{$var} ;
369 26 100       96 if (!$binding) {
    50          
370 25         170 DTRACE "no bindings for $var. extending and setting equal to %s", Data::Dumper::Dumper($input);
371 25         89749 $bindings->{$var} = $input ;
372 25         127 return DVAL $bindings;
373             } elsif ($binding eq $input) { # this equal will be inadequate for lists
374 0         0 DTRACE "binding for $var with $input already exists";
375 0         0 return DVAL $bindings ;
376             } else {
377 1         4 return DVOID ;
378             }
379             }
380              
381             sub subseq {
382 9     9 0 1276 DFEATURE my $f_;
383 9         25730 my ($input,$start,$end) = @_;
384              
385 9         24 my $max = $#$input ;
386 9 100       30 $end = defined($end) ? $end : $max ;
387              
388 9         65 DTRACE "subseq_start: $start end: $end max: $max";
389              
390 9         18156 [ @{$input}[$start..$end] ] ;
  9         73  
391              
392             }
393              
394             sub atomic {
395 4     4 0 21 DFEATURE my $f_;
396 4         8122 my $pat = shift ;
397              
398 4 100       26 if (ref($pat) eq 'ARRAY') { return DVOID }
  1         7  
399 3         16 return DVAL 1;
400             }
401              
402             sub is_variable {
403 106     106 0 5330 DFEATURE my $f_;
404              
405 106         233413 my $p = shift;
406              
407 106 100       447 if (ref($p)) {
408 52         246 return DVOID;
409             } else {
410 54         379 my $r = ($p =~ /^[A-Z][A-Z0-9]*$/) ;
411 54         10540 return DVAL $r ;
412             }
413             }
414              
415              
416             sub first_match_pos {
417 4     4 0 19 DFEATURE my $f_;
418 4         9705 my ($pattern, $input, $start) = @_;
419              
420 4 100       55 $start = int($start) if (!defined($start));
421              
422 4         1970 DTRACE sprintf "first_match_pos_pattern: %s", Data::Dumper::Dumper($pattern);
423 4         9377 DTRACE sprintf "first_match_pos_input: %s", Data::Dumper::Dumper($input);
424 4         8082 DTRACE sprintf "first_match_pos_start: %s", Data::Dumper::Dumper($start);
425              
426 4 100 66     8035 if ((atomic $pattern) && (!is_variable($pattern))) {
    50          
427             # look for first place that pattern equals input
428 3         4174 for (my $i = $start; $i <= $#$input; ++$i) {
429 8 100       29 if ($pattern eq $input->[$i]) {
430 3         11 return DVAL $i;
431             }
432             }
433 0         0 return DVAL undef;
434             }
435             elsif ($start < @$input) {
436 1         1809 return DVAL $start;
437             }
438             }
439             sub rest {
440 94     94 0 68465 DFEATURE my $f_;
441 94         247011 my $aref = shift;
442 94         402 my @ary = @$aref;
443              
444 94 100       490 if (@$aref == 1) {
445 28         127 return DVAL undef ;
446             }
447              
448 66 50       318 if (@$aref > 1) {
449 66         183 splice @ary, 0, 1;
450 66         332 return DVAL \@ary;
451             }
452              
453             }
454              
455             sub segment_match {
456 4     4 0 21 DFEATURE my $f_;
457 4         7958 my ($pattern, $input, $bindings, $start) = @_;
458 4         14 my $var = $pattern->[0]->[0] ;
459 4         16 my $pat = rest $pattern ;
460              
461 4 50       6393 if (!defined($pat)) {
462 0         0 DTRACE "not defined pat";
463 0         0 return DVAL match_variable($var,$input,$bindings) ;
464             } else {
465 4         23 DTRACE " defined pat";
466 4         8064 my $pos = first_match_pos($pat->[0], $input, $start) ;
467              
468 4 50       5932 if (!defined($pos)) {
469 0         0 DTRACE "no first match pos";
470 0         0 return DVAL undef;
471             } else {
472 4         48 DTRACE "there is a first match pos ($pos)";
473             # if it does have a match
474 4 100       7270 my $match_variable_subseq_end = (!$pos) ? 0 : $pos - 1 ;
475 4         18 my $b2 = pat_match($pat, subseq($input,$pos),
476             match_variable($var, subseq($input,0,$match_variable_subseq_end), $bindings));
477 4 50       6936 if ($b2) {
478 4         27 DTRACE "found our match ($b2)";
479 4         10784 return DVAL $b2;
480             } else {
481 0         0 DTRACE "incrementing and attempting again";
482 0         0 return DVAL (segment_match($pattern, $input, $bindings,
483             (1+$pos)));
484             }
485             }
486             }
487             }
488            
489             sub segment_match_plus {
490 1     1 0 6 DFEATURE my $f_;
491 1         2063 my ($pattern, $input, $bindings) = @_;
492 1         6 return DVAL segment_match $pattern, $input, $bindings, 1 ;
493             }
494              
495             sub segment_match_optional {
496 1     1 0 5 DFEATURE my $f_;
497 1         1751 my ($pattern, $input, $bindings) = @_ ;
498 1         4 my $var = $pattern->[0][0] ;
499 1         6 my $pat = rest $pattern ;
500              
501 1   33     1145 return DVAL (
502             (pat_match ( [($var, @$pat)], $input, $bindings) ) ||
503             (pat_match $pat , $input, $bindings)
504             ) ;
505             }
506              
507              
508             sub pat_match ;
509             sub single_match_is {
510 2     2 0 12 DFEATURE my $f_;
511 2         14627 my ($is_var_and_pred, $input, $bindings) = @_ ;
512              
513 2         15 DTRACE "INPUT ", Data::Dumper::Dumper(\@_) ;
514 2         4760 my ($var,$pred) = ($is_var_and_pred->[1],$is_var_and_pred->[2]) ;
515 2         18 my $new_bindings = pat_match $var, $input, $bindings ;
516 2         6451 DTRACE "NEW_BINDINGS ", Data::Dumper::Dumper($new_bindings) ;
517              
518 2 50 33     4821 if (!defined($new_bindings) or !defined($pred->($input))) {
519 0         0 DTRACE "pred FAILED";
520 0         0 return DVOID ;
521             } else {
522 2         27 my $result = $pred->($input) ;
523 2         18 DTRACE "pred result: $result";
524 2 100       4235 if ($result) {
525 1         6 return DVAL $bindings ;
526             } else {
527 1         7 return DVOID;
528             }
529             }
530             }
531              
532             sub single_match_or ;
533             sub single_match_not {
534 1     1 0 6 DFEATURE my $f_;
535              
536 1         3089 my ($pattern,$input,$bindings) = @_;
537 1         5 my $o = single_match_or $pattern, $input, $bindings ;
538 1 50       1267 if ($o) {
539 0         0 return DVOID ;
540             } else {
541 1         5 return DVAL $bindings ;
542             }
543             }
544              
545             sub match_or;
546             sub single_match_or {
547 7     7 0 34 DFEATURE my $f_;
548              
549 7         14409 my ($pattern,$input,$bindings) = @_;
550              
551 7         45 DTRACE "smor_input: ", Data::Dumper::Dumper($input) ;
552              
553 7 100 66     17535 if (!defined($pattern) or (scalar @$pattern == 0)) { return DVOID }
  1         6  
554 6         323 my $input_copy = Storable::dclone($input);
555 6         26 my $rest_pattern = rest $pattern;
556 6         11304 my $new_bindings = pat_match $pattern->[0], $input, $bindings ;
557 6 100       9514 if (!defined($new_bindings)) {
558 5         45 my $r = single_match_or $rest_pattern, $input_copy, $bindings ;
559             } else {
560 1         6 return DVAL $new_bindings ;
561             }
562             }
563              
564             sub single_match_and {
565 4     4 0 20 DFEATURE my $f_;
566              
567 4         7518 my ($meta_pattern,$input,$bindings) = @_;
568 4         22 DTRACE "single_match_and meta_p: i: b:", Data::Dumper::Dumper($meta_pattern,$input,$bindings) ;
569              
570 4 50       7477 if (!defined($bindings)) { return DVOID }
  0         0  
571 4 100 66     31 if (!defined($meta_pattern) or !@$meta_pattern) { return DVAL $bindings }
  1         7  
572 3         29 my $rest_meta_pattern = rest $meta_pattern ;
573              
574 3         4380 my $input_copy = [ @$input ] ;
575 3         18 my $f = pat_match $meta_pattern->[0], $input, $bindings ;
576 3         4727 DTRACE sprintf "and_first gave this: %s now we work with these: %s,%s",
577             Data::Dumper::Dumper($f),
578             Data::Dumper::Dumper($rest_meta_pattern),
579             Data::Dumper::Dumper($input_copy) ;
580 3         16590 my $ret = single_match_and ($rest_meta_pattern, $input_copy, $f) ;
581            
582 3         3900 return DVAL $ret ;
583             }
584              
585              
586             sub segment_match_if {
587 2     2 0 9 DFEATURE my $f_;
588 2         2985 my ($pattern, $input, $bindings) = @_ ;
589              
590 2         13 DTRACE "p: i: b:", Data::Dumper::Dumper($pattern,$input,$bindings) ;
591            
592              
593 2         3357 local $_ = $bindings ;
594              
595 2         11 return DVAL eval $pattern->[0]->[0]->() ;
596              
597             }
598              
599             our %segment_dispatch =
600             (
601             '*' => \&segment_match,
602             '+' => \&segment_match_plus,
603             '?' => \&segment_match_optional,
604             'IF?' => \&segment_match_if
605             ) ;
606              
607             our %single_dispatch =
608             (
609             'IS?' => \&single_match_is,
610             'AND?' => \&single_match_and,
611             'OR?' => \&single_match_or,
612             'NOT?' => \&single_match_not,
613             ) ;
614              
615              
616             sub is_array_ref {
617 236     236 0 875 DFEATURE my $f_;
618 236         501386 return DVAL ref ($_[0]) eq 'ARRAY';
619             }
620             sub is_code_ref {
621 0     0 0 0 DFEATURE my $f_;
622 0         0 return DVAL ref ($_[0]) eq 'CODE';
623             }
624              
625              
626              
627             sub segment_match_fn {
628 10     10 0 30 my $x = shift;
629 10         52 DTRACE "dispatching on $x";
630 10         20575 my $fn = $segment_dispatch{$x} ;
631 10         39 return $fn;
632             }
633            
634             sub is_single_pattern {
635 74     74 0 285 DFEATURE my $f_;
636             # warn "@_" , Data::Dumper::Dumper(\@_) ;
637 74         152030 my $term_aref = $_[0] ;
638 74 100       271 if (is_array_ref($term_aref)) {
639 45         78159 DTRACE "dispatching on", Data::Dumper::Dumper($term_aref->[0]);
640 45         106889 return DVAL $single_dispatch{$term_aref->[0]} ;
641             } else {
642 29         42031 return DVOID ;
643             }
644              
645             }
646              
647             sub is_segment_pattern {
648 81     81 0 359 DFEATURE my $f_;
649 81         168652 my $pat = shift;
650 81         599 DTRACE "is_segment_pattern ", Data::Dumper::Dumper($pat) ;
651 81         161000 my $a = is_array_ref($pat) ;
652 81 100       157960 my $first = $a ? $pat->[0] : undef ;
653 81         241 my $a2 = is_array_ref($first) ;
654              
655 81 100 100     135760 return undef unless ($a && $a2) ;
656              
657 10         74 DTRACE "hi there $first->[1]" ;
658              
659 10         19999 my $s = segment_match_fn($first->[1]) ;
660              
661 10         107 DTRACE "s $s" ;
662              
663 10 100       23735 if ($s) {
664 7         49 return $s ;
665             } else {
666 3         26 return undef ;
667             }
668              
669             }
670            
671              
672              
673             sub pat_match {
674 109     109 0 136156 DFEATURE my $f_;
675              
676 109         318046 my ($pattern, $input, $bindings) = @_;
677              
678 109         826 DTRACE "pattern,input,bindings", Data::Dumper::Dumper($pattern,$input,$bindings) ;
679              
680 109 100       258409 if (!defined($bindings)) { return DVOID }
  6         32  
681 103 100       455 if (is_variable($pattern)) { return DVAL match_variable(@_) }
  22         51506  
682 81 100       124505 if (my $segment_matcher = is_segment_pattern($pattern)) {
683 7         2102 return DVAL $segment_matcher->(@_) ;
684             }
685              
686 74 100       23158 if (my $single_matcher = is_single_pattern($pattern)) {
687 5 100 100     8598 if (($pattern->[0] eq 'AND?') or ($pattern->[0] eq 'OR?')) {
688 2         14 DTRACE sprintf "p0: %s p1: %s p2: %s", Data::Dumper::Dumper($pattern->[0]), Data::Dumper::Dumper($pattern->[1]), Data::Dumper::Dumper($pattern->[2]) ;
689             # remove AND? and the entire outer list
690 2         4486 $pattern = $pattern->[1] ;
691             }
692 5         27 return DVAL $single_matcher->($pattern,$input,$bindings) ;
693             }
694              
695 69 50 100     126043 if ( (
      66        
      66        
696             (ref($pattern) eq 'ARRAY') &&
697             (ref($input) eq 'ARRAY') &&
698             (@$pattern) && (@$input)
699             )
700             ) {
701 39         177 DTRACE "handling first and rest" ;
702 39         94670 my $b = pat_match($pattern->[0], $input->[0], $bindings) ;
703 39         103007 my $newer_binds = pat_match((rest $pattern), (rest $input), $b);
704 39         74303 DTRACE "new binds($newer_binds)", Data::Dumper::Dumper($newer_binds) ;
705 39         97685 return DVAL $newer_binds;
706             }
707 30 100       299 if ($pattern eq $input) {
708 25         16952 DTRACE "$pattern eq $input ... returning bindings($bindings)";
709 25         63094 return DVAL $bindings ;
710             }
711 5         22 return DVOID ;
712             }
713              
714             =head1 AUTHOR
715              
716             T.M. Brannon
717              
718             =head1 SEE ALSO
719              
720             L,
721             L, L
722              
723             =cut
724              
725             1;
726             __END__