[Bps-public-commit] r18608 - Parse-BooleanLogic/lib/Parse

ruz at bestpractical.com ruz at bestpractical.com
Mon Mar 2 10:07:07 EST 2009


Author: ruz
Date: Mon Mar  2 10:07:06 2009
New Revision: 18608

Modified:
   Parse-BooleanLogic/lib/Parse/BooleanLogic.pm

Log:
* move walk and describe
* add partial solve

Modified: Parse-BooleanLogic/lib/Parse/BooleanLogic.pm
==============================================================================
--- Parse-BooleanLogic/lib/Parse/BooleanLogic.pm	(original)
+++ Parse-BooleanLogic/lib/Parse/BooleanLogic.pm	Mon Mar  2 10:07:06 2009
@@ -500,6 +500,43 @@
 Several functions taking a tree of boolean expressions as returned by
 L<as_array> method and evaluating or changing it using a callback.
 
+=head3 walk $tree $callbacks @rest
+
+A simple method for walking a $tree using four callbacks: open_paren,
+close_paren, operand and operator. All callbacks are optional.
+
+Example:
+
+    $parser->walk(
+        $tree,
+        {
+            open_paren => sub { ... },
+            close_paren => sub { ... },
+            ...
+        },
+        $some_context_argument, $another, ...
+    );
+
+Any additional arguments (@rest) are passed all the time into callbacks.
+
+=cut
+
+sub walk {
+    my ($self, $tree, $cb, @rest) = @_;
+
+    foreach my $entry ( @$tree ) {
+        if ( ref $entry eq 'ARRAY' ) {
+            $cb->{'open_paren'}->( @rest ) if $cb->{'open_paren'};
+            $self->walk( $entry, $cb, @rest );
+            $cb->{'close_paren'}->( @rest ) if $cb->{'close_paren'};
+        } elsif ( ref $entry eq 'HASH' ) {
+            $cb->{'operand'}->( $entry, @rest ) if $cb->{'operand'};
+        } else {
+            $cb->{'operator'}->( $entry, @rest ) if $cb->{'operator'};
+        }
+    }
+}
+
 =head3 filter $tree $callback @rest
 
 Filters a $tree using provided $callback. The callback is called for each operand
@@ -680,20 +717,61 @@
     return $res;
 }
 
-sub walk {
+=head3 partial_solve $tree $callback @rest
+
+Partially solve a $tree. Callback can return undef or a new expression
+and a defined boolean value to be used in solve.
+
+Returns either result or array reference with expression.
+
+Any additional arguments (@rest) are passed all the time into the callback.
+
+=cut
+
+sub partial_solve {
     my ($self, $tree, $cb, @rest) = @_;
 
+    my @res;
+
+    my ($last, $ea, $skip_next) = (0, $self->{'operators'}[1], 0);
     foreach my $entry ( @$tree ) {
+        $skip_next-- and next if $skip_next > 0;
+        unless ( ref $entry ) {
+            $ea = lc $entry;
+            unless ( ref $last ) {
+                $skip_next++ if
+                       ( $last && $ea eq $self->{'operators'}[1])
+                    || (!$last && $ea eq $self->{'operators'}[0]);
+            } else {
+                push @res, $entry;
+            }
+            next;
+        }
+
         if ( ref $entry eq 'ARRAY' ) {
-            $cb->{'open_paren'}->( @rest ) if $cb->{'open_paren'};
-            $self->walk( $entry, $cb, @rest );
-            $cb->{'close_paren'}->( @rest ) if $cb->{'close_paren'};
-        } elsif ( ref $entry eq 'HASH' ) {
-            $cb->{'operand'}->( $entry, @rest ) if $cb->{'operand'};
+            $last = $self->solve( $entry, $cb, @rest );
+            # drop parens with one condition inside
+            $last = $last->[0] if ref $last && @$last == 1;
         } else {
-            $cb->{'operator'}->( $entry, @rest ) if $cb->{'operator'};
+            $last = $cb->( $entry, @rest );
+            $last = $entry unless defined $last;
+        }
+        unless ( ref $last ) {
+            if ( $ea eq $self->{'operators'}[0] ) {
+                # (...) AND 0
+                unless ( $last ) { @res = () } else { pop @res };
+            }
+            elsif ( $ea eq $self->{'operators'}[1] ) {
+                # (...) OR 1
+                if ( $last ) { @res = () } else { pop @res };
+            }
+        } else {
+            push @res, $last;
         }
     }
+
+    return $last unless @res; # solution
+    return \@res; # more than one condition
 }
 
 1;



More information about the Bps-public-commit mailing list