This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/packages/python/python.pl

432 lines
11 KiB
Perl
Raw Normal View History

% % % -* - Mode : Prolog; -*-
2012-10-08 23:58:22 +01:00
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2012-10-17 10:56:44 +01:00
% Author: Vitor Santos Costa
% E-mail: vsc@dcc.fc.up.pt
% Copyright (C): Universidade do Porto
2012-10-08 23:58:22 +01:00
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
2012-10-17 10:56:44 +01:00
% This file is part of the YAP Python Interface
2012-10-08 23:58:22 +01:00
% distributed according to Perl Artistic License
% check LICENSE file for distribution license
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
2015-08-07 22:57:53 +01:00
:- module(python,
[
init_python/0,
end_python/0,
python_command/1,
2015-09-21 23:05:36 +01:00
python_run_file/1,
python_run_command/1,
python_run_script/2,
2015-08-07 22:57:53 +01:00
python_assign/3,
python_import/1,
2015-09-21 23:05:36 +01:00
array_to_python_list/4,
array_to_python_tuple/4,
array_to_python_view/5,
2015-08-07 22:57:53 +01:00
python/2,
(:=)/2,
(:=)/1,
(<-)/2,
(<-)/1,
op(100,fy,$),
op(950,fy,:=),
op(950,yfx,:=),
op(950,fx,<-),
op(950,yfx,<-),
op(50, yf, []),
op(50, yf, '()'),
op(100, xfy, '.'),
op(100, fy, '.')
]).
2015-01-04 23:58:23 +00:00
/** <module> python
A C-based Prolog interface to python.
@author Vitor Santos Costa
@version 0:0:5, 2012/10/8
@license Perl Artistic License
2015-08-07 22:57:53 +01:00
This is an interface to allow calling Python from Prolog. Please look
at the SWIG package if you want to embedd Prolog with Python.
The interface should be activated by consulting the python lybrary. It
immediately boots a Python image.
To best define the interface, one has to address two opposite goals:
- make it as similar to python as possible
- make all embedded language interfaces (python, R, Java) as
similar as possible.
YAP supports the following translation between Prolog and Python:
| *Prolog* | *Pyhon* | *Prolog Examples* |
|:-------------:|:-------------:|---------------------------------------:|
| Numbers | Numbers | 2.3
| | | 1545
| | |
| Atom | Symbols | var
| $Atom | | $var [ = var]
| `string` | 'string' | \`hello\`
| "string" | ' | "hello"
| | |
| Atom(...) | Symb(...) | f( a, b, named=v)
| E.F(...) | E.F (...) | mod.f( a) [ = [mod\|f(a)] ]
| Atom() | | f() [ = '()'(f) ]
| Lists | Lists | [1,2,3]
| t(....) | Tuples | t(1,2,3) to (1,2,3)
| (..., ...) | | (1,2,3)[ = (1,(2,3))]
| {.=., .=.} | Dict | {\`one\`: 1, \`two\`: 2, \`three\`: 3}
2015-08-07 22:57:53 +01:00
2015-01-04 23:58:23 +00:00
*/
2012-10-17 10:56:44 +01:00
2012-10-25 00:33:02 +01:00
/************************************************************************************************************
2015-09-21 23:05:36 +01:00
2012-10-25 00:33:02 +01:00
Python interface
Data types are
2015-08-07 22:57:53 +01:00
Python Prolog
string atoms
numbers numbers
lists lists
tuples t(...)
generic objs __pointer__(Address)
2012-10-25 00:33:02 +01:00
2012-10-26 00:24:07 +01:00
$var refers to the attribute __main__.var
2012-10-25 00:33:02 +01:00
*************************************************************************************************************/
2012-10-17 10:56:44 +01:00
:- use_module(library(shlib)).
:- use_module(library(lists)).
:- use_module(library(apply_macros)).
:- use_module(library(charsio)).
2012-12-01 14:28:25 +00:00
:- dynamic python_mref_cache/2, python_obj_cache/2.
2012-10-25 00:33:02 +01:00
:= F :- python(F,_).
2015-09-21 23:05:36 +01:00
V := F :- var(V), !, python(F,V0),
python_exports(V0,V).
A := F :-
2015-09-21 23:05:36 +01:00
python_eval_term(F, EF),
assign(A, EF, _).
2012-10-25 00:33:02 +01:00
2015-09-21 23:05:36 +01:00
( V <- F ) :-
var(V), !,
2015-09-21 23:05:36 +01:00
V0 := F,
python_exports(V0,V).
( V <- F ) :-
ground(V), !,
V := F.
2015-09-21 23:05:36 +01:00
( V <- F ) :-
copy_term(V, V0),
V0 := F,
python_exports(V0,V).
python_exports(V0, V0) :-
var(V0), !.
python_exports(V0, V0) :-
atomic(V0), !.
python_exports('__obj__'(T0), T) :-
!,
python_export('__obj__'(T0), T).
python_exports(V0, VF) :-
V0 =.. [F|L],
maplist(python_exports, L, LF),
VF =.. [F|LF].
2015-08-07 22:57:53 +01:00
2015-09-21 23:05:36 +01:00
((<- F)) :-
python( F, _).
2015-08-07 22:57:53 +01:00
2012-10-26 00:24:07 +01:00
python_import(Module) :-
python_do_import(Module, _).
2012-10-25 00:33:02 +01:00
python_do_import(Module, MRef) :-
python_mref_cache(Module, MRef), !.
python_do_import(Module, MRef) :-
python_import(Module, MRef),
2012-10-25 00:33:02 +01:00
assert( python_mref_cache(Module, MRef) ).
fetch_module(M:E, _M1, E, MRef) :-
2012-10-26 00:24:07 +01:00
atom(M),
python_import(M, MRef).
2012-12-01 14:28:25 +00:00
% from an exp take an object, and its corresponding Prolog representation
descend_exp(V, _Obj) :-
2012-12-01 14:28:25 +00:00
var(V), !,
throw(error(instantiation_error,_)).
descend_exp(Mod.Exp, Obj) :-
2015-08-07 22:57:53 +01:00
atom(Mod),
2012-12-01 14:28:25 +00:00
python_import(Mod, MObj),
!,
descend_exp(MObj.Exp, Obj).
descend_exp(C1.C2.E, Obj) :- !,
python_eval_term(C1, O1),
python_field(O1, C2, Obj0 ),
descend_exp(Obj0.E, Obj).
descend_exp(C1.E, Obj) :-
!,
python_eval_term(C1, O1),
python_field(O1, E, Obj0 ),
python_check_args(E, NE, Dict),
python_apply(Obj0, NE, Dict, Obj).
descend_exp(C, O) :-
python_is(C, O).
2012-12-01 14:28:25 +00:00
python_class(Obj) :-
python_obj_cache(inspect:isclass(_), F),
python_apply(F, isclass(Obj), {}, true).
process_obj(Obj, _, S, Obj, NS, Dict) :-
python_callable(Obj), !,
2012-12-03 12:39:25 +00:00
python_check_args(S, NS, Dict).
2014-12-14 12:05:43 +00:00
process_obj(Obj, _, S, FObj, NS, Dict) :-
2015-09-21 23:05:36 +01:00
descend_object(Obj.'__init__', FObj, _, _),
descend_object(Obj.'__init__', FObj, _, _),
2012-12-03 12:39:25 +00:00
python_check_args(S, NS, Dict).
2012-12-01 14:28:25 +00:00
%% @pred python_eval_term( + Obj, -Obj) is semi-det
% It implements the Python interprter's evaluation loop.
%
2012-12-01 14:28:25 +00:00
python_eval_term(Obj, Obj) :-
var(Obj), !,
throw(error(instantiation_error, Obj) ).
%% atom use basic evaluation of an atom
%% check if a variable.
python_eval_term(Name, Obj) :-
atom(Name),
!,
python_is(Name, Obj).
%% numbers are evaluated
python_eval_term(N, N) :- number(N), !.
python_eval_term(N, N) :- string(N), !.
%% we assume objects are so yoo.
2012-12-01 14:28:25 +00:00
python_eval_term('__obj__'(Obj), '__obj__'(Obj)) :- !.
%% constant functions are useful.
python_eval_term('()'(X), NX) :- !,
python_eval_term(X, NX).
%% $ -> compatibilty with older versions
2012-12-01 14:28:25 +00:00
python_eval_term($Name, Obj) :- !,
python_is(Name, Obj).
%% lists are collections of individuals
%% that may need futrher processing
2015-08-07 22:57:53 +01:00
python_eval_term([H|T], NL) :-
is_list(T), !,
maplist( python_eval_term, [H|T], NL).
%% array access, Python understands numeric
% indices and slices.
python_eval_term(Exp[Min:Max:Step], NEl) :- !,
2015-09-21 23:05:36 +01:00
python_eval_term(slice(Min,Max,Step), Slice),
python_slice(Exp,Slice, NEl).
python_eval_term(Exp[Min:Max], NEl) :- !,
python_eval_term(slice(Min,Max), Slice),
2015-09-21 23:05:36 +01:00
python_slide(Exp,Min,Max, NEl).
python_eval_term(Exp[Index], O) :- !,
2015-09-21 23:05:36 +01:00
python_item(Exp,Index,O).
% function or method call of the form
% a.b.f(...)
python_eval_term(Inp.Exp, Obj) :- !,
%flatten_exp(Exp, Exp1, []),
descend_exp(Inp.Exp, Obj).
2015-09-21 23:05:36 +01:00
python_eval_term((A,B), Obj) :- !,
flatten_conj((A,B),Cs,[]),
maplist( python_eval_term, Cs, NCs),
Tuple =.. [t|NCs],
python_is(Tuple, Obj).
% tuples and varyadic functions.
python_eval_term(Tuple, Obj) :-
Tuple =.. [Name|TupleL],
maplist( python_eval_term, TupleL, NewTupleL),
(
Name == t
->
!,
NewTuple =.. [t|NewTupleL],
python_is(NewTuple, Obj)
;
Name == open ->
!,
% calls the file constructor
NewTuple =.. [open|NewTupleL],
python_builtin_eval( NewTuple, [], Obj )
).
python_eval_term(Exp, Obj) :-
2015-09-21 23:05:36 +01:00
python_is(Exp, Obj).
flatten_exp( V , V, V0) :-
V0 == [],
var( V ),
!.
flatten_exp( V1 ) -->
{ var( V1 ) },
!,
[V1].
flatten_exp( (V1.V2) ) -->
!,
flatten_exp( V1 ), % propagte the RHS first.
flatten_exp( V2 ).
flatten_exp( V1() ) -->
!,
flatten_exp( V1 ).
flatten_exp( V1, V1, V0 ) :- V0 == [], !.
flatten_exp( V1 ) -->
[V1].
2012-10-25 00:33:02 +01:00
2015-09-21 23:05:36 +01:00
flatten_conj( V1 ) -->
{ var( V1 ) },
!,
[V1].
flatten_conj( (V1,V2) ) -->
!,
flatten_conj( V1 ), % propagte the RHS first.
flatten_conj( V2 ).
flatten_conj( V1 ) -->
[V1].
python_check_args(_Exp(), t, {}) :-
!.
python_check_args(Exp, t, {}) :-
2012-12-01 14:28:25 +00:00
Exp =.. [_,V], var(V), !.
python_check_args(Exp, NExp, Dict) :-
2015-09-21 23:05:36 +01:00
Exp =.. [_F|LArgs], !,
match_args(LArgs, NLArgs, Dict),
2012-12-01 14:28:25 +00:00
NExp =.. [t|NLArgs].
2015-09-21 23:05:36 +01:00
python_check_args(Exp, Exp, {}).
2012-12-01 14:28:25 +00:00
python_build_tuple(V) -->
{var(V) }, !,
[V].
python_build_tuple((X,Y)) --> !,
python_build_tuple(X),
python_build_tuple(Y).
python_build_tuple(X) --> [X].
2012-12-01 14:28:25 +00:00
% in case it is __init__ from __new__
splice_class(Ref, Ref, ArgNames, ArgNames) :- !.
splice_class(_FRef, _Ref, [_|ArgNames], ArgNames).
match_args([], [], {}).
match_args([V=A|LArgs], [], Dict) :- !,
2015-09-21 23:05:36 +01:00
python_eval_term(A, EvA),
match_named_args([V=EvA|LArgs], Map),
2012-12-01 14:28:25 +00:00
map_to_dict(Map, Dict).
match_args([A|LArgs], [VA|NLArgs], Dict) :-
2012-12-01 14:28:25 +00:00
python_eval_term(A, VA),
match_args(LArgs, NLArgs, Dict).
2012-12-01 14:28:25 +00:00
match_named_args([], []).
2015-09-21 23:05:36 +01:00
match_named_args([K=A|LArgs], [K=A|Map]) :-
match_named_args(LArgs, Map).
2012-12-01 14:28:25 +00:00
map_to_dict([X=V], {X:V}) :- !.
map_to_dict([X=V|Map], {X:V,NDict}) :-
map_to_dict(Map, {NDict}).
match_from_anames([K|_ArgNames], K, VA, [_|Defaults], [VA|Defaults]) :- !.
match_from_anames([_|ArgNames], K, VA, [V|Defaults], [V|NDefaults]) :-
match_from_anames(ArgNames, K, VA, Defaults, NDefaults).
fetch_args(FRef, Args, Kwd, Defaults) :-
FRef = '__obj__'(_), !,
2014-12-14 12:05:43 +00:00
%python_mref_cache('inspect', M),
2012-12-01 14:28:25 +00:00
python_obj_cache(inspect:getargspec(_), F),
python_apply(F, getargspec(FRef), {}, ExtraArgs),
ExtraArgs=t(Args, _, Kwd, Defaults).
fetch_args(_, []).
2012-11-05 13:49:15 +00:00
2012-10-25 00:33:02 +01:00
python(Obj, Out) :-
2012-11-27 12:10:41 +00:00
python_eval_term(Obj, Out).
2012-10-17 10:56:44 +01:00
2012-10-08 23:58:22 +01:00
python_command(Cmd) :-
2012-10-25 00:33:02 +01:00
python_run_command(Cmd).
2012-10-08 23:58:22 +01:00
python_lhs(Obj,Obj) :-
var(Obj), !.
python_lhs(Name,Name) :-
atom(Name), !.
python_lhs(N, N) :-
number(N), !,
throw(error(type(evaluable, N)), "in left-hand-side of s").
2015-09-21 23:05:36 +01:00
python_lhs(N,N) :-
string(N), !,
throw(error(type(evaluable, N)), "in left-hand-side of s").
python_lhs('__obj__'(Obj), '__obj__'(Obj)) :- !.
python_lhs($Name, Name) :-
!.
python_lhs([H|T], NL) :-
is_list(T), !,
maplist( python_lhs, [H|T], NL).
python_lhs((Exp1,Exp2), O) :- !,
python_build_tuple((Exp1,Exp2), TupleL, []),
Tuple =.. [t|TupleL], % <<<
python_lhs( Tuple, O).
python_lhs(F, F).
2012-10-08 23:58:22 +01:00
start_python :-
2012-10-23 10:18:24 +01:00
init_python,
2012-12-01 14:28:25 +00:00
python_main_module(MRef),
assert(python_mref_cache('__main__', MRef)),
2012-11-05 13:49:15 +00:00
python_command('import sys'),
2012-12-01 14:28:25 +00:00
python_import('inspect'),
python_mref_cache(inspect, InspRef),
python_field(InspRef, isclass(_), IsClass),
2012-12-01 14:28:25 +00:00
assert(python_obj_cache(inspect:isclass(_), IsClass)),
python_field(InspRef, getargspec(_), GetArgSpec),
assert(python_obj_cache(inspect:getargspec(_), GetArgSpec)),
at_halt(end_python).
2012-10-25 00:33:02 +01:00
add_cwd_to_python :-
2012-10-23 10:18:24 +01:00
unix(getcwd(Dir)),
atom_concat(['sys.path.append(\"',Dir,'\")'], Command),
2012-11-02 22:37:27 +00:00
python_command(Command),
python_command("sys.argv = [\"yap\"]").
2015-08-07 22:57:53 +01:00
% done
2012-10-08 23:58:22 +01:00
2015-09-21 23:05:36 +01:00
assign( V, E, O ) :-
var(V),
!,
E = V,
O = V.
assign( EName, E, EName ) :-
\+ atomic(EName),
python_assign_tuple(EName, E),
!.
assign(Name, Exp, Name) :-
2012-10-25 00:33:02 +01:00
python_assign(Name, Exp).
2012-10-08 23:58:22 +01:00
2015-09-21 23:05:36 +01:00
% from an exp take an object, and its corresponding Prolog representation
python_assign_field(V, _Obj) :-
var(V), !,
throw(error(instantiation_error,_)).
python_assign_field(Mod.Exp, Obj) :-
atom(Mod),
python_import(Mod, MObj),
!,
python_assign_field(MObj.Exp, Obj).
python_assign_field(C1.C2.E, Obj) :- !,
python_eval_term(C1, O1),
python_field(O1, C2, Obj0 ),
python_assign_field(Obj0.E, Obj).
python_assign_field(Exp, Obj) :-
fail,
python_mref_cache(_, MObj),
python_field(MObj, Exp, Obj), !.
python_assign_field(C1.E, Obj) :-
atom(E),
!,
python_eval_term(C1, O1),
python_assign_field(O1, E, Obj ).
2015-08-07 22:57:53 +01:00
:- initialization( use_foreign_library(foreign(libpython)), now ).
2014-08-20 13:56:33 +01:00
:- initialization(start_python ).