The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Data::Query::ExprBuilder;

use strictures 1;
use Scalar::Util ();
use Data::Query::ExprHelpers qw(perl_scalar_value perl_operator);

use overload (
  # unary operators
  (map {
    my $op = $_;
    $op => sub {
      Data::Query::ExprBuilder->new({
        expr => perl_operator($op => $_[0]->{expr})
      });
    }
  } qw(! neg)),
  # binary operators
  (map {
    my ($overload, $as) = ref($_) ? @$_ : ($_, $_);
    $overload => sub {
      Data::Query::ExprBuilder->new({
        expr => perl_operator(
           $as,
           map {
             (Scalar::Util::blessed($_)
             && $_->isa('Data::Query::ExprBuilder'))
               ? $_->{expr}
               : perl_scalar_value($_)
              # we're called with ($left, $right, 0) or ($right, $left, 1)
            } $_[2] ? @_[1,0] : @_[0,1]
          )
      });
    }
  }
    qw(+ - * / % ** << >> . < > == != lt le gt ge eq ne),

    # since 'and' and 'or' aren't operators we borrow the bitwise ops
    [ '&' => 'and' ], [ '|' => 'or' ],
  ),
  # unsupported
  (map {
    my $op = $_;
    $op => sub { die "Can't use operator $op on a ".ref($_[0]) }
   } qw(<=> cmp x ^ ~)
  ),
  fallback => 1,
); 

sub new {
  bless({ %{$_[1]} }, (ref($_[0])||$_[0]));
}

1;