[Bps-public-commit] r15998 - Parse-BooleanLogic/lib/Parse
ruz at bestpractical.com
ruz at bestpractical.com
Tue Sep 16 16:56:40 EDT 2008
Author: ruz
Date: Tue Sep 16 16:56:31 2008
New Revision: 15998
Modified:
Parse-BooleanLogic/lib/Parse/BooleanLogic.pm
Log:
* refactor state machine, make it faster by using less regexp matches
* add new STOP token - end of expression
* everything in one 'if/elsif' block
Modified: Parse-BooleanLogic/lib/Parse/BooleanLogic.pm
==============================================================================
--- Parse-BooleanLogic/lib/Parse/BooleanLogic.pm (original)
+++ Parse-BooleanLogic/lib/Parse/BooleanLogic.pm Tue Sep 16 16:56:31 2008
@@ -41,7 +41,8 @@
use constant OPERATOR => 2;
use constant OPEN_PAREN => 4;
use constant CLOSE_PAREN => 8;
-my @tokens = qw[OPERAND OPERATOR OPEN_PAREN CLOSE_PAREN];
+use constant STOP => 16;
+my @tokens = qw[OPERAND OPERATOR OPEN_PAREN CLOSE_PAREN STOP];
use Regexp::Common qw(delimited);
my $re_operator = qr{\b(?i:AND|OR)\b};
@@ -50,7 +51,7 @@
my $re_tokens = qr{(?:$re_operator|$re_open_paren|$re_close_paren)};
my $re_delim = qr{$RE{delimited}{-delim=>qq{\'\"}}};
-my $re_operand = qr{(?!\s)(?:$re_delim|(?!$re_tokens|["']).+?(?=$re_tokens|["']|\Z))+};
+my $re_operand = qr{(?:$re_delim|(?!$re_tokens|["']).+?(?=$re_tokens|["']|\Z))+};
=head1 METHODS
@@ -186,66 +187,52 @@
my ($string, $cb) = @args{qw(string callback)};
$string = '' unless defined $string;
- my $want = OPERAND | OPEN_PAREN;
+ # States
+ my $want = OPERAND | OPEN_PAREN | STOP;
my $last = 0;
-
my $depth = 0;
- while ( $string =~ /(
- $re_operator
- |$re_open_paren
- |$re_close_paren
- |$re_operand
- )/iogx )
- {
- my $match = $1;
- next if $match =~ /^\s*$/;
-
- # Highest priority is last
- my $current = 0;
- $current = OPERAND if ($want & OPERAND) && $match =~ /^$re_operand$/io;
- $current = OPERATOR if ($want & OPERATOR) && $match =~ /^$re_operator$/io;
- $current = OPEN_PAREN if ($want & OPEN_PAREN) && $match =~ /^$re_open_paren$/io;
- $current = CLOSE_PAREN if ($want & CLOSE_PAREN) && $match =~ /^$re_close_paren$/io;
-
- unless ($current && $want & $current) {
- my $tmp = substr($string, 0, pos($string)- length($match));
- $tmp .= '>'. $match .'<--here'. substr($string, pos($string));
- my $msg = "Wrong expression, expecting a ". $self->bitmask_to_string($want) ." in '$tmp'";
- $cb->{'error'}? $cb->{'error'}->($msg): die $msg;
- return;
+ while (1) {
+ # State Machine
+ if ( ($want & OPERAND ) && $string =~ /\G\s*($re_operand)/iogc ) {
+ my $m = $1;
+ $m=~ s/\s+$//;
+ $cb->{'operand'}->( $m );
+ $last = OPERAND;
+ $want = OPERATOR;
+ $want |= $depth? CLOSE_PAREN : STOP;
}
-
- # State Machine:
- if ( $current & OPEN_PAREN ) {
- $cb->{'open_paren'}->( $match );
+ elsif ( ($want & OPERATOR ) && $string =~ /\G\s*($re_operator)/iogc ) {
+ $cb->{'operator'}->( $1 );
+ $last = OPERATOR;
+ $want = OPERAND | OPEN_PAREN;
+ }
+ elsif ( ($want & OPEN_PAREN ) && $string =~ /\G\s*($re_open_paren)/iogc ) {
+ $cb->{'open_paren'}->( $1 );
$depth++;
+ $last = OPEN_PAREN;
$want = OPERAND | OPEN_PAREN;
}
- elsif ( $current & CLOSE_PAREN ) {
- $cb->{'close_paren'}->( $match );
+ elsif ( ($want & CLOSE_PAREN) && $string =~ /\G\s*($re_close_paren)/iogc ) {
+ $cb->{'close_paren'}->( $1 );
$depth--;
+ $last = CLOSE_PAREN;
$want = OPERATOR;
- $want |= CLOSE_PAREN if $depth;
+ $want |= $depth? CLOSE_PAREN : STOP;
}
- elsif ( $current & OPERATOR ) {
- $cb->{'operator'}->( $match );
- $want = OPERAND | OPEN_PAREN;
+ elsif ( ($want & STOP) && $string =~ /\G\s*$/igc ) {
+ $last = STOP;
+ last;
}
- elsif ( $current & OPERAND ) {
- $match =~ s/\s+$//;
- $cb->{'operand'}->( $match );
- $want = OPERATOR;
- $want |= CLOSE_PAREN if $depth;
+ else {
+ last;
}
-
- $last = $current;
}
- unless ( !$last || $last & (CLOSE_PAREN | OPERAND) ) {
- my $msg = "Incomplete query, last element ("
- . $self->bitmask_to_string($last)
- . ") is not CLOSE_PAREN or OPERAND in '$string'";
+ if (!$last || !($want & $last)) {
+ my $tmp = substr( $string, 0, pos($string) );
+ $tmp .= '>>>here<<<'. substr($string, pos($string));
+ my $msg = "Incomplete or incorrect expression, expecting a ". $self->bitmask_to_string($want) ." in '$tmp'";
$cb->{'error'}? $cb->{'error'}->($msg): die $msg;
return;
}
More information about the Bps-public-commit
mailing list