# # This software is Copyright 2005 by Elsevier Inc. You may use it # under the terms of the license at http://perl.plover.com/hop/LICENSE.txt . # ### ### dqp.pl ### ## Chapter 8 section 7.1 use Lexer ':all'; sub lex_input { my @input = @_; my $input = sub { shift @input }; my $lexer = iterator_to_stream( make_lexer($input, ['STRING', qr/' (?: \\. | [^'] )* ' |" (?: \\. | [^"] )* " /sx, sub { my $s = shift; $s =~ s/.//; $s =~ s/.$//; $s =~ s/\\(.)/$1/g; ['STRING', $s] } ], ['FIELD', qr/[A-Z]+/ ], ['AND', qr/&/ ], ['OR', qr/\|/ ], ['OP', qr/[!<>=]=|[<>=]/, sub { $_[0] =~ s/^=$/==/; [ 'OP', $_[0] ] } ], ['LPAREN', qr/[(]/ ], ['RPAREN', qr/[)]/ ], ['NUMBER', qr/\d+ (?:\.\d*)? | \.\d+/x ], ['SPACE', qr/\s+/, sub { "" } ], ) ); } ## Chapter 8 section 7.2 use Parser ':all'; use FlatDB_Composable qw(query_or query_and); my ($cquery, $squery, $term); my $CQuery = parser { $cquery->(@_) }; my $SQuery = parser { $squery->(@_) }; my $Term = parser { $term->(@_) }; use FlatDB; ## Chapter 8 section 7.2 $cquery = operator($Term, [lookfor('OR'), \&query_or]); $term = operator($SQuery, [lookfor('AND'), \&query_and]); ## Chapter 8 section 7.2 # This needs to be up here so that the following $squery # definition can see $parser_dbh my $parser_dbh; sub set_parser_dbh { $parser_dbh = shift } sub parser_dbh { $parser_dbh } ## Chapter 8 section 7.2 $squery = alternate( T(concatenate(lookfor('LPAREN'), $CQuery, lookfor('RPAREN'), ), sub { $_[1] }), T(concatenate(lookfor('FIELD'), lookfor('OP'), lookfor('NUMBER')), sub { my ($field, $op, $val) = @_; my $cmp_code = 'sub { $_[0] OP $_[1] }'; $cmp_code =~ s/OP/$op/; my $cmp = eval($cmp_code) or die; my $cb = sub { my %F = @_; $cmp->($F{$field}, $val)}; $parser_dbh->callbackquery($cb); }), ## Chapter 8 section 7.2 T(concatenate(lookfor('FIELD'), lookfor('OP'), lookfor('STRING')), sub { if ($_[1] eq '==') { $parser_dbh->query($_[0], $_[2]); } else { my ($field, $op, $val) = @_; my $cmp_code = 'sub { $_[0] OP $_[1] }'; $cmp_code =~ s/OP/$string_version{$op}/; my $cmp = eval($cmp_code) or die; my $cb = sub { my %F = @_; $cmp->($F{$field}, $val)}; $parser_dbh->callbackquery($cb); } }), ); my %string_version = ('>' => 'gt', '>=', => 'ge', '==' => 'eq', '<' => 'lt', '<=', => 'le', '!=' => 'ne'); package FlatDB::Parser; use base FlatDB_Composable; sub parse_query { my $self = shift; my $query = shift; my $lexer = main::lex_input($query); my $old_parser_dbh = main::parser_dbh(); main::set_parser_dbh($self); my ($result) = $cquery->($lexer); main::set_parser_dbh($old_parser_dbh); return $result; }