AI-Prolog

 view release on metacpan or  search on metacpan

lib/AI/Prolog/Engine/Primitives.pm  view on Meta::CPAN

# minux(X,Y) := 26.
# mult(X,Y)  := 27.
# div(X,Y)   := 28.
# mod(X,Y)   := 29.

$PRIMITIVES[30] = sub {    # seq/1
    my ( $self, $term, $c ) = @_;
    $self->_splice_goal_list($term);
    CONTINUE;
};

my $HELP_OUTPUT;
$PRIMITIVES[31] = sub {    # help/0
    _load_builtins();
    if ( not $HELP_OUTPUT ) {
        $HELP_OUTPUT = "Help is available for the following builtins:\n\n";
        my @predicates = sort keys %DESCRIPTION_FOR;
        my $length     = length $LONGEST_PREDICATE;
        my $columns    = 5;
        my $format     = join '    ' => ("%-${length}s") x $columns;
        while (@predicates) {
            my @row;
            for ( 1 .. $columns ) {
                push @row => @predicates
                    ? shift @predicates
                    : '';
            }
            $HELP_OUTPUT .= sprintf $format => @row;
            $HELP_OUTPUT .= "\n";
        }
        $HELP_OUTPUT .= "\n";
    }
    AI::Prolog::Engine::_print($HELP_OUTPUT);
    CONTINUE;
};

$PRIMITIVES[32] = sub {    # help/1
    my ( $self, $term, $c ) = @_;
    my $predicate = $term->getarg(0)->to_string;
    _load_builtins();
    if ( my $description = $DESCRIPTION_FOR{$predicate} ) {
        AI::Prolog::Engine::_print($description);
    }
    else {
        AI::Prolog::Engine::_print("No help available for ($predicate)\n\n");
        $PRIMITIVES[31]->();
    }
    CONTINUE;
};

my $gensym_int = 0;
$PRIMITIVES[33] = sub {    # gemsym/1
    my ( $self, $term, $c ) = @_;
    my $t2 = Term->new( 'v' . $gensym_int++, 0 );
    return $t2->unify( $term->getarg(0), $self->{_stack} )
        ? CONTINUE
        : FAIL;
};

use constant UNDEFINED_SUBROUTINE_ERROR => do {
    eval {
        no strict 'refs';    ## no critic NoStrict
        &{'---'};
    };
    my $e = $@;

    # Undefined subroutine &main::--- called at .../Primitives.pm line 12.
    my ($msg) = $e =~ / \A
                        (.+)    # 'Undefined subroutine'
                        (?<=\s) # ' '
                        \S*     # &main::
                        ---/mx
        or die q[Perl's error message changed! Damn! Fix this regex.];

    $msg;
};

$PRIMITIVES[34] = sub {    # perlcall2/2
    my ( $self, $term ) = @_;

    # Get a function name...
    my $function_term = $term->getarg(0);
    if ( not $function_term->is_bound ) {
        return FAIL;
    }
    my $function_name = $function_term->to_string;

    # Lookup a fully qualified function name...
    my $function_ref;
    if ( $function_name =~ /[:\']/mx ) {
        $function_ref = $function_name;
    }
    elsif ( defined( my $package = $self->{_perlpackage} ) ) {
        $function_name = "$package\::$function_name";
    }

    # Search the call stack...
    if ( not defined $function_ref ) {
        my $cx = 1;
        my %packages;
    CX:
        while ( my $package = caller $cx ) {

            # Don't retry packages...
            next if exists $packages{$package};
            $packages{$package} = undef;

            # AUTOLOAD using packages are expected to provide a
            # ->can() that works. I don't know if that's a widely
            # known expectation but it's what I'm going to go
            # with. Hash::AsObject gets this wrong.
            if (do {
                    no strict 'refs';    ## no critic NoStrict
                    defined &{"$package\::$function_name"};
                }
                or $package->can($function_name)
                )
            {
                $function_ref = "$package\::$function_name";
                last CX;
            }
        }
        continue {
            ++$cx;
        }
    }

    # We got nuthin! Damn! I'll try for the first AUTOLOAD.
    if ( not defined $function_ref ) {
        my $cx = 1;
        my %packages;
    AUTOLOAD_CX:
        while ( my ($package) = caller $cx ) {
            next if exists $packages{$package};
            $packages{$package} = undef;

            if (do {
                    no strict 'refs';    ## no critic NoStrict
                    defined &{"$package\::AUTOLOAD"};
                }
                or $package->can('AUTOLOAD')
                )
            {
                $function_ref = "$package\::$function_name";
                last AUTOLOAD_CX;
            }
        }
        continue {
            ++$cx;
        }
    }

    if ( not defined $function_ref ) {
	return FAIL;
    }

    # XXX What do to with the first arg?
    my ( undef, $results_ref ) = $term->getarg(1)->to_data;
    my @results = @{ $results_ref->[0] };

    eval {

        no strict 'refs';    ## no critic NoStrict
        $function_ref->(@results);
    };
    if ( my $e = $@ ) {
    
        # Extreme caution here.
        if ( $e =~ UNDEFINED_SUBROUTINE_ERROR ) {
            return FAIL;
        }
    }

    return CONTINUE;
};

sub find { return $PRIMITIVES[ $_[1] ] }

1;

__END__

=head1 NAME

AI::Prolog::Engine::Primitives - The code for running aiprolog builtins

=head1 SYNOPSIS

 my $builtin = AI::Prolog::Engine::Primitives ->find($builtin_id);

=head1 DESCRIPTION

This module contains the code to handle the built-in predicates.  The
L<AI::Prolog::Engine|AI::Prolog::Engine> assigns many builtins an ID
number and this number is used to lookup the sub necessary to execute
the built-in.

=head1 AUTHOR

Curtis "Ovid" Poe, E<lt>moc tod oohay ta eop_divo_sitrucE<gt>

Reverse the name to email me.

=head1 COPYRIGHT AND LICENSE

Copyright 2005 by Curtis "Ovid" Poe

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut



( run in 1.742 second using v1.01-cache-2.11-cpan-5a3173703d6 )