This commit is contained in:
Vitor Santos Costa
2017-12-20 00:29:15 +00:00
parent 4a5002091f
commit 814aa2bd4c
10 changed files with 796 additions and 960 deletions

View File

@@ -1,6 +1,5 @@
#include "py4yap.h"
#include <VFS.h>
@@ -27,7 +26,8 @@ PyObject *py_ModDict;
VFS_t pystream;
static void *py_open(VFS_t *me, int sno, const char *name, const char *io_mode) {
static void *py_open(VFS_t *me, int sno, const char *name,
const char *io_mode) {
#if HAVE_STRCASESTR
if (strcasestr(name, "//python/") == name)
name += strlen("//python/");
@@ -35,56 +35,57 @@ static void *py_open(VFS_t *me, int sno, const char *name, const char *io_mode)
if (strstr(name, "//python/") == name)
name += strlen("//python/");
#endif
StreamDesc *st = YAP_RepStreamFromId(sno);
StreamDesc *st = YAP_RepStreamFromId(sno);
// we assume object is already open, so there is no need to open it.
PyObject *stream = string_to_python(name, true, NULL);
if (stream == Py_None)
return NULL;
Py_INCREF(stream);
st->u.private_data = stream;
st->vfs = me;
st->status = Append_Stream_f | Output_Stream_f;
Yap_DefaultStreamOps(st);
return stream;
Py_INCREF(stream);
st->u.private_data = stream;
st->vfs = me;
st->status = Append_Stream_f | Output_Stream_f;
Yap_DefaultStreamOps(st);
return stream;
}
static bool py_close(int sno) {
return true;
StreamDesc *s = YAP_GetStreamFromId(sno);
StreamDesc *s = YAP_GetStreamFromId(sno);
PyObject *fclose = PyObject_GetAttrString(s->u.private_data, "close");
PyObject *rc = PyObject_CallObject(fclose, NULL);
bool v = (rc == Py_True);
return v;
}
static int py_put(int sno, int ch) {
// PyObject *pyw; // buffer
//int pyw_kind;
//PyObject *pyw_data;
// int pyw_kind;
// PyObject *pyw_data;
char s[2];
StreamDesc *st = YAP_GetStreamFromId(sno);
// PyUnicode_WRITE(pyw_kind, pyw_data, 0, ch);
PyObject *err,*fput = PyObject_GetAttrString(st->u.private_data, "write");
char s[2];
StreamDesc *st = YAP_GetStreamFromId(sno);
// PyUnicode_WRITE(pyw_kind, pyw_data, 0, ch);
PyObject *err, *fput = PyObject_GetAttrString(st->u.private_data, "write");
s[0] = ch;
s[1] = '\0';
PyObject_CallFunctionObjArgs(fput, PyUnicode_FromString(s), NULL);
if ((err = PyErr_Occurred())) {
PyErr_SetString(err, "Error in put\n");// %s:%s:%d!\n", __FILE__, __FUNCTION__, __LINE__);
}
s[1] = '\0';
PyObject_CallFunctionObjArgs(fput, PyBytes_FromString(s), NULL);
if ((err = PyErr_Occurred())) {
PyErr_SetString(
err,
"Error in put\n"); // %s:%s:%d!\n", __FILE__, __FUNCTION__, __LINE__);
}
return ch;
}
static int py_get(int sno) {
StreamDesc *s = YAP_GetStreamFromId(sno);
StreamDesc *s = YAP_GetStreamFromId(sno);
PyObject *fget = PyObject_GetAttrString(s->u.private_data, "read");
PyObject *pyr = PyObject_CallFunctionObjArgs(fget, PyLong_FromLong(1), NULL);
return PyUnicode_READ_CHAR(pyr, 0);
}
static int64_t py_seek(int sno, int64_t where, int how) {
StreamDesc *s = YAP_GetStreamFromId(sno);
StreamDesc *s = YAP_GetStreamFromId(sno);
PyObject *fseek = PyObject_GetAttrString(s->u.private_data, "seek");
PyObject *pyr = PyObject_CallFunctionObjArgs(fseek, PyLong_FromLong(where),
PyLong_FromLong(how), NULL);
@@ -92,7 +93,7 @@ static int64_t py_seek(int sno, int64_t where, int how) {
}
static void py_flush(int sno) {
StreamDesc *s = YAP_GetStreamFromId(sno);
StreamDesc *s = YAP_GetStreamFromId(sno);
PyObject *flush = PyObject_GetAttrString(s->u.private_data, "flush");
PyObject_CallFunction(flush, NULL);
}
@@ -111,9 +112,9 @@ static void python_output(void) {
#endif
static bool init_python_stream(void) {
//pyw = PyUnicode_FromString("x");
//pyw_kind = PyUnicode_KIND(pyw);
//pyw_data = PyUnicode_DATA(pyw);
// pyw = PyUnicode_FromString("x");
// pyw_kind = PyUnicode_KIND(pyw);
// pyw_data = PyUnicode_DATA(pyw);
pystream.name = "python stream";
pystream.vflags =
@@ -227,6 +228,6 @@ X_API bool do_init_python(void) {
install_pl2pl();
// PyGILState_Release(gstate);
add_modules();
// python_output();
// python_output();
return true;
}

View File

@@ -61,13 +61,13 @@ argi(N,I,I1) :-
I1 is I+1.
python_query( Self, String ) :-
yap_flag(typein_module, Mod),
atomic_to_term( String, Goal, VarNames ),
query_to_answer( Mod:Goal, VarNames, Status, Bindings),
maplist(in_dict(Self.bindings), Bindings),
query_to_answer( Goal, VarNames, Status, Bindings),
Self.port := Status,
write_query_answer( Bindings ),
nl( user_error ),
Self.port := Status.
nl(user_error),
Self.bindings := {},
maplist(in_dict(Self.bindings), Bindings).
in_dict(Dict, var([V0,V|Vs])) :- !,
Dict[V] := V0,

View File

@@ -1,6 +1,7 @@
import os
import sys
import abc
import math
import yap4py.yapi
from IPython.core import interactiveshell
@@ -14,6 +15,7 @@ from pygments import highlight
from pygments.lexers.prolog import PrologLexer
from pygments.formatters import HtmlFormatter
import pdb
from collections import namedtuple
@@ -87,7 +89,7 @@ class YAPCompleter:
class YAPInteractive(InteractiveShell):
"""An enhanced, interactive shell for YAP."""
def init_yap_completer(self):
"""Initialize the completion machinery.
@@ -110,9 +112,9 @@ class YAPInteractive(InteractiveShell):
self.yapeng.goal(use_module(library("jupyter")))
self.q = None
self.run = False
self.os = ""
self.port = None
self.init_yap_completer()
self.init_syntax_highlighting()
def init_syntax_highlighting(self, changes=None):
# Python source parser/formatter for syntax highlighting
@@ -169,7 +171,7 @@ class YAPInteractive(InteractiveShell):
def run_cell(self, raw_cell, store_history=True, silent=False,
shell_futures=True):
"""Run a complete IPython cell.
@@ -206,9 +208,9 @@ class YAPInteractive(InteractiveShell):
# vs is the list of variables
# you can print it out, the left-side is the variable name,
# the right side wraps a handle to a variable
# pdb.set_trace()
# #pdb.set_trace()
# atom match either symbols, or if no symbol exists, strings, In this case
pdb.set_trace()
# import pdb; pdb.set_trace()
# atom match either symbols, or if no symbol ex b pl nvists, strings, In this case
# variable names should match strings
# ask = True
# launch the query
@@ -222,6 +224,7 @@ class YAPInteractive(InteractiveShell):
store_history = False
if store_history:
self.execution_count = self.execution_count+1
result.execution_count = self.execution_count
def error_before_exec(value):
@@ -237,13 +240,14 @@ class YAPInteractive(InteractiveShell):
# prefilter_manager) raises an exception, we store it in this variable
# so that we can display the error after logging the input and storing
# it in the history.
# preprocessing_exc_tuple = None
# try:
# # Static input transformations
# cell = raw_cell #self.input_transformer_manager.transform_cell(raw_cell)
# except SyntaxError:
# preprocessing_exc_tuple = sys.exc_info()
cell = raw_cell # cell has to exist so it can be stored/logged
preprocessing_exc_tuple = None
try:
# Static input transformations
cell = raw_cell.strip(" \n\t").rstrip(" \n\t") #self.input_transformer_manager.transform_cell(raw_cell.strip(" \n\t").rstrip(" \n\t"))
except SyntaxError:
preprocessing_exc_tuple = sys.exc_info()
#
# cell = raw_cell # cell has to exist so it can be stored/logged
# else:
# # import pdb; pdb.set_trace()
# if False and len(cell.splitlines()) == 1:
@@ -277,6 +281,8 @@ class YAPInteractive(InteractiveShell):
# compiler
# compiler = self.compile if shell_futures else CachingCompiler()
pdb.set_trace()
cell_name = str( self.execution_count)
if cell[0] == '%':
@@ -308,7 +314,7 @@ class YAPInteractive(InteractiveShell):
has_raised = False
try:
self.bindings = dict = {}
state = self.jupyter_query(cell)
state = self.jupyter_query(raw_cell)
if state:
self.last_execution_succeeded = True
result.result = (True, dict)
@@ -341,7 +347,7 @@ class YAPInteractive(InteractiveShell):
def prolog_cell(self,s):
""""
Trasform a text into program+query. A query is the
last line if the last line is non-empty and does not terminate
last line if the last line is non-empty and does not terminate
on a dot. You can also finish with
- `*`: you request all solutions
@@ -349,33 +355,48 @@ class YAPInteractive(InteractiveShell):
- '?'[N]: you want an answer; optionally you want N answers
If the line terminates on a `*/` or starts on a `%` we assume the line
is a comment.
is a comment.
"""
s = s.rstrip()
take = 0
its = 0
[program,x,query] = s.partition('\n')
if query == '':
query = program
while take < len(query):
take += 1
ch = query[-take]
if ch.isdigit():
its = its + ord(ch) - ord('0')
elif ch == '*' and take == 1:
return program, query[:-take], -1
elif ch == '.' and take == 1:
return s, '', 1
elif ch == '/' and query[-2] == '*' and take == 1:
return program, query[:-take], -1
elif ch == '^' and take == 1:
return program, query[:-take], 1
elif ch == '?':
return program, query[:-take], its+1
s = s.rstrip().strip()
l = s.split("\n")
while not l[0]:
l = l[1:]
rl = []
for h in l:
if h and h[0] == '%':
if h[1] == '%':
break
else:
return program, query, 1
return s, '', 1
rl = [h] + rl
if not rl:
return '','',1
query = rl[0]
program = ''
i=0
for h in rl:
if h and not h.isspace():
break
i += 1
rl = rl[i:]
if not rl:
return '','',1
take = 1
ch = query[-take]
if ch == '*' and take == 1:
query = l[:-1]
sols = -1
if ch == '.':
return s, '', 1
rl = rl[1:]
while True:
h = rl[0]
if h and not h.isspace():
query = h + '\n'+ query
rl = rl[1:]
break
for l in rl:
program = l + '\n'+ program
return program,query,take
def jupyter_query(self, s):
# import pdb; pdb.set_trace()
@@ -383,15 +404,19 @@ class YAPInteractive(InteractiveShell):
# construct a self.query from a one-line string
# self.q is opaque to Python
self.bindings = {}
self.port = "call"
iterations=1
if self.q and s != self.os:
self.q.close()
self.q = None
if not self.q:
import pdb; pdb.set_trace()
program,query,self.iterations = self.prolog_cell(s)
#import pdb; pdb.set_trace()
self.port = "call"
program,query,iterations = self.prolog_cell(s)
self.q = self.yapeng.query(jupyter_query(self, program, query))
self.os = s
self.solutions = []
if not self.q:
return True, []
self.os = s
# vs is the list of variables
# you can print it out, the left-side is the variable name,
# the right side wraps a handle to a variable
@@ -406,23 +431,34 @@ class YAPInteractive(InteractiveShell):
# ask = True
# launch the query
# run the new commbnand using the given tracer
solutions = []
while self.iterations > 0:
self.iterations -= 1
rc = self.answer(self.q)
if rc:
# deterministic = one solution
if self.port == "exit":
# done
self.q.close()
self.q = None
self.os = ""
print("yes")
solutions += [self.bindings]
if iterations <0:
while self.answer( self.q):
self.solutions += [self.bindings]
self.q.close()
self.q = None
self.os = ""
if not self.solutions:
print("no solutions found")
return True
rc = self.answer(self.q)
if rc:
# deterministic = one solution
#Dict = {}
#engine.goal(show_answer( q.namedVars(), Dict))
self.solutions += [self.bindings]
if self.port == "exit":
# done
self.q.close()
self.q = None
self.os = ""
return True
else:
print("No (more) answers")
self.q.close()
self.q = None
return True, solutions
self.os = ''
return False
def answer(self, q):
try:
@@ -430,7 +466,7 @@ class YAPInteractive(InteractiveShell):
except Exception as e:
print(e.args[1])
self.yapeng.goal(exit_cell(self))
return False, None
return e
class YAPInteractiveABC(metaclass=abc.ABCMeta):

View File

@@ -1,4 +1,14 @@
/**
* @file jupyter.yap
*
* @brief allow interaction between Jupyter and YAP.
*
* @long The code in here:
* - establishes communication between Prolog and Python Streams
* - inputs Prolog code and queries
* - supports completion of Prolog programs.
* -
*/
:- use_module(library(yapi)).
:- use_module(library(lists)).
:- use_module(library(maplist)).
@@ -6,33 +16,50 @@
:- python_import(sys).
:- start_low_level_trace.
user:jupyter_query(Self, Cell, Line ) :-
setup_call_cleanup(
enter_cell(Self),
jupyter_cell(Self, Cell, Line),
exit_cell(Self) ).
exit_cell(Self)
).
jupyter_cell(_Self, Cell, _) :-
open_mem_read_stream( Cell, Stream),
load_files(['jupyter cell'],[stream(Stream)]),
close( Stream ),
stop_low_level_trace,
jupyter_consult(Cell),
fail.
jupyter_cell( _Self, _, Line ) :-
blank( Line ),
!.
jupyter_cell( Self, _, Line ) :-
start_low_level_trace,
python_query( Self, Line ).
jupyter_consult(Text) :-
blank( Text ),
!.
jupyter_consult(Cell) :-
open_mem_read_stream( Cell, Stream),
load_files(user:'jupyter cell',[stream(Stream)]).
%should load_files close?
blank(Text) :-
atom_codes(Text, L),
maplist( blankc, L).
blankc(' ').
blankc('\n').
blankc('\t').
enter_cell(_Self) :-
%open('//python/sys.stdin', read, _Input, []),
open('//python/sys.stdout', append, _Output, []),
open('//python/sys.stdout', append, _Error, []),
%set_prolog_flag(user_input, _Input),
set_prolog_flag(user_output, _Output),
set_prolog_flag(user_error, _Error),
writeln(hello),
format(user_error,'h~n',[]),
:= print("py"),
:= sys.stderr.write("ok\n").
set_prolog_flag(user_error, _Error).
exit_cell(_Self) :-
%close( user_input),
close( user_output),
close( user_error).