The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

=head1 NAME

Math::Symbolic::Custom::DumpToFastEval - Compile Math::Symbolic trees fast RPN form

=head1 SYNOPSIS

  use Math::Symbolic::Custom::DumpToFastEval;

=head1 DESCRIPTION

FIXME documentation!

=head2 EXPORT

None by default, but you may choose to import the compile(), compile_to_sub(),
and compile_to_code() subroutines to your namespace using the standart
Exporter semantics including the ':all' tag.

=head1 SUBROUTINES

=cut

package Math::Symbolic::Custom::DumpToFastEval;
use 5.006;
use strict;
use warnings;

our $VERSION = '0.01';

use Math::SymbolicX::FastEvaluator;
use Math::Symbolic::Custom::Base;
BEGIN {*import = \&Math::Symbolic::Custom::Base::aggregate_import}

our $Aggregate_Export = [qw/to_fasteval/];

use Math::Symbolic::ExportConstants qw/:all/;

sub to_fasteval {
    my $tree = shift;
    $tree = shift if not ref $tree and $tree eq __PACKAGE__;

    my $order = shift || [];
    my %order;
    if (ref($order) eq 'HASH') {
        %order = %$order;
    }
    elsif (ref($order) eq 'ARRAY') {
        my $count = 0;
        %order = map { ( $_, $count++ ) } @$order;
    }

    no warnings 'recursion';

    my $vars = [ $tree->explicit_signature() ];

    my %vars;
    my @not_placed;
    foreach (@$vars) {
        my $pos = $order{$_};
        if ( defined $pos ) {
            $vars{$_} = $pos;
        }
        else {
            push @not_placed, $_;
        }
    }

    my $count = 0;
    foreach ( sort @not_placed ) {
        $vars{$_} = @$vars - @not_placed + $count++;
    }

    # The user is to do that himself. Left in to show that it would be
    # a sensible (if slow) thing to do.
    # $tree = $tree->simplify();
    # $tree = $tree->apply_derivatives();
    # $tree = $tree->simplify();

    my @trees;

    my $expr = Math::SymbolicX::FastEvaluator::Expression->new();
    my $success = _rec_ms_to_expr( $expr, $tree, \%vars );
    return() if not $success;
    
    $expr->SetNVars(scalar keys %vars);

    return($expr);
}


{
  no warnings 'recursion';
  sub _rec_ms_to_expr {
    my $expr = shift;
    my $tree  = shift;
    my $vars  = shift;

    my $op = Math::SymbolicX::FastEvaluator::Op->new();

    eval {
      $tree->descend(
        in_place => 1,
        after => sub {
          my $t = shift;
          my $ttype = $t->term_type;
          if ($ttype == T_VARIABLE) {
            $op->SetVariable();
            $op->SetValue($vars->{$t->name});
            #print $t->name, " ";
          }
          elsif ($ttype == T_CONSTANT) {
            $op->SetNumber();
            $op->SetValue($t->value);
            #print $t->value, " ";
          }
          else {
            my $type = $t->type;
            if ($type == U_P_DERIVATIVE || $type == U_T_DERIVATIVE) {
              die "Can't convert dertivatives to RPN for the FastEvaluator!";
            }
            $op->SetOpType($type);
            #print $Math::Symbolic::Operator::Op_Types[$type]{prefix_string}, " ";
          }
          $expr->AddOp($op);
        },
      );
    };
    if ($@) {
      warn "Caught exception while converting Math::Symbolic tree to RPN: $@";
      return();
    }
    return 1;
  }
}

1;
__END__

=head1 AUTHOR

Please send feedback, bug reports, and support requests to the Math::Symbolic
support mailing list:
math-symbolic-support at lists dot sourceforge dot net. Please
consider letting us know how you use Math::Symbolic. Thank you.

If you're interested in helping with the development or extending the
module's functionality, please contact the developers' mailing list:
math-symbolic-develop at lists dot sourceforge dot net.

Steffen Müller, E<lt>smueller@cpan.orgE<gt>

=head1 SEE ALSO

New versions of this module can be found on
http://steffen-mueller.net or CPAN. The module development takes place on
Sourceforge at http://sourceforge.net/projects/math-symbolic/

L<Math::Symbolic>, L<Math::SymbolicX::FastEvaluator>,
L<Math::SymbolicX::FastEvaluator::Expression>


=cut