235 lines
6.8 KiB
Python
235 lines
6.8 KiB
Python
import readline
|
|
from yap4py.yap import *
|
|
from os.path import join, dirname
|
|
from collections import namedtuple
|
|
import sys
|
|
|
|
yap_lib_path = dirname(__file__)
|
|
|
|
bindvars = namedtuple('bindvars', 'list')
|
|
compile = namedtuple('compile', 'file')
|
|
jupyter_query = namedtuple('jupyter_query', 'vars dict')
|
|
library = namedtuple('library', 'listfiles')
|
|
prolog_library = namedtuple('prolog_library', 'listfiles')
|
|
python_query = namedtuple('python_query', 'vars dict')
|
|
set_prolog_flag = namedtuple('set_prolog_flag', 'flag new_value')
|
|
show_answer = namedtuple('show_answer', 'vars dict')
|
|
v0 = namedtuple('v', 'slot')
|
|
yap_query = namedtuple('yap_query', 'query owner')
|
|
yapi_query = namedtuple('yapi_query', 'vars dict')
|
|
|
|
|
|
class Engine( YAPEngine ):
|
|
|
|
def __init__(self, args=None,self_contained=False,**kwargs):
|
|
# type: (object) -> object
|
|
if not args:
|
|
args = EngineArgs(**kwargs)
|
|
args.setEmbedded(True)
|
|
if self_contained:
|
|
yap_lib_path = dirname(__file__)
|
|
args.setYapShareDir(join(yap_lib_path, "prolog"))
|
|
args.setYapPLDIR(yap_lib_path)
|
|
args.setSavedState(join(yap_lib_path, "startup.yss"))
|
|
YAPEngine.__init__(self, args)
|
|
self.run(compile(library('yapi')),m="user",release=True)
|
|
|
|
def run(self, g, m=None, release=False):
|
|
if m:
|
|
self.mgoal(g, m, release)
|
|
else:
|
|
self.goal(g, release)
|
|
|
|
def prolog_library(self, file):
|
|
g = prolog_library(file)
|
|
self.run(g)
|
|
|
|
class JupyterEngine( Engine ):
|
|
|
|
def __init__(self, args=None,self_contained=False,**kwargs):
|
|
# type: (object) -> object
|
|
if not args:
|
|
args = EngineArgs(**kwargs)
|
|
args.jupyter = True
|
|
Engine.__init__(self, args)
|
|
self.errors = None
|
|
try:
|
|
self.run(compile(library('jupyter')),"user")
|
|
self.run(compile(library('complete')),"user")
|
|
self.run(compile(library('verify')),"user")
|
|
except:
|
|
pass
|
|
|
|
class EngineArgs( YAPEngineArgs ):
|
|
""" Interface to Engine Options class"""
|
|
def __init__(self, args=None,**kwargs):
|
|
super().__init__()
|
|
|
|
|
|
class Predicate( YAPPredicate ):
|
|
""" Interface to Generic Predicate"""
|
|
|
|
def __init__(self, t, module=None):
|
|
super().__init__(t)
|
|
|
|
class Query (YAPQuery):
|
|
"""Goal is a predicate instantiated under a specific environment """
|
|
def __init__(self, engine, g):
|
|
super().__init__(g)
|
|
self.engine = engine
|
|
self.port = "call"
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def done(self):
|
|
return self.port == "fail" or self.port == "exit"
|
|
|
|
def __next__(self):
|
|
self.answer = {}
|
|
if self.port == "fail" or self.port == "exit":
|
|
raise StopIteration()
|
|
if self.next():
|
|
return self.answer
|
|
raise StopIteration()
|
|
|
|
def name( name, arity):
|
|
try:
|
|
if arity > 0 and name.isidentifier(): # and not keyword.iskeyword(name):
|
|
s = []
|
|
for i in range(arity):
|
|
s += ["A" + str(i)]
|
|
return namedtuple(name, s)
|
|
except:
|
|
return None
|
|
|
|
class PrologPredicate( YAPPrologPredicate ):
|
|
""" Interface to Prolog Predicate"""
|
|
|
|
class v(YAPVarTerm,v0):
|
|
def __init__(self):
|
|
YAPVarTerm.__init__()
|
|
|
|
def binding(self):
|
|
return self.term()
|
|
|
|
|
|
class YAPShell:
|
|
|
|
def numbervars( self ):
|
|
Dict = {}
|
|
self.engine.goal(show_answer( self, Dict), True)
|
|
return Dict
|
|
# rc = self.q.namedVarsVector()
|
|
# self.q.r = self.q.goal().numbervars()
|
|
# o = []
|
|
# for i in rc:
|
|
# if len(i) == 2:
|
|
# do = str(i[0]) + " = " + str( i[1] ) + "\n"
|
|
# o += do
|
|
# else:
|
|
# do = str(i[0]) + " = " + str( i[1] ) + "\n"
|
|
# o += do
|
|
# return o
|
|
|
|
|
|
def query_prolog(self, query):
|
|
g = None
|
|
#import pdb; pdb.set_trace()
|
|
#
|
|
# construct a query from a one-line string
|
|
# q is opaque to Python
|
|
#
|
|
#q = engine.query(python_query(self, 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
|
|
# import pdb; pdb.set_trace()
|
|
# #pdb.set_trace()
|
|
# atom match either symbols, or if no symbol exists, sttrings, In this case
|
|
# variable names should match strings
|
|
#for eq in vs:
|
|
# if not isinstance(eq[0],str):
|
|
# print( "Error: Variable Name matches a Python Symbol")
|
|
# return
|
|
try:
|
|
engine = self.engine
|
|
bindings = []
|
|
loop = False
|
|
q = Query( engine, python_query( engine, query) )
|
|
for answer in q:
|
|
bindings += [answer]
|
|
if g.done():
|
|
return bindings
|
|
if loop:
|
|
continue
|
|
s = input("more(;), all(*), no(\\n), python(#)? ").lstrip()
|
|
if s.startswith(';') or s.startswith('y'):
|
|
continue
|
|
elif s.startswith('#'):
|
|
try:
|
|
exec(s.lstrip('#'))
|
|
except:
|
|
raise
|
|
elif s.startswith('*') or s.startswith('a'):
|
|
loop = True
|
|
continue
|
|
else:
|
|
break
|
|
if self.q:
|
|
self.q.close()
|
|
self.q = None
|
|
print("No (more) answers")
|
|
return bindings
|
|
except Exception as e:
|
|
if not self.q:
|
|
return False, None
|
|
self.q.close()
|
|
self.q = None
|
|
print("Exception",e)
|
|
e.errorNo = 0
|
|
raise
|
|
|
|
def live(self, engine, **kwargs):
|
|
loop = True
|
|
self.q = None
|
|
while loop:
|
|
try:
|
|
s = input("?- ")
|
|
if not s:
|
|
continue
|
|
else:
|
|
self.query_prolog(s)
|
|
except SyntaxError as err:
|
|
print("Syntax Error error: {0}".format(err))
|
|
continue
|
|
except EOFError:
|
|
return
|
|
except RuntimeError as err:
|
|
print("YAP Execution Error: {0}".format(err))
|
|
except ValueError:
|
|
print("Could not convert data to an integer.")
|
|
except:
|
|
print("Unexpected error:", sys.exc_info()[0])
|
|
raise
|
|
engine.close()
|
|
#
|
|
# initialize engine
|
|
# engine = yap.YAPEngine();
|
|
# engine = yap.YAPEngine(yap.YAPParams());
|
|
#
|
|
def __init__(self, engine, **kwargs):
|
|
self.engine = engine
|
|
|
|
self.live(engine)
|
|
self.q = None
|
|
|
|
|
|
def main():
|
|
engine = Engine()
|
|
YAPShell(engine)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|