summaryrefslogtreecommitdiff
path: root/prolog
diff options
context:
space:
mode:
authorTimotej Lazar <timotej.lazar@araneo.org>2014-10-02 16:06:31 +0200
committerAleš Smodiš <aless@guru.si>2015-08-11 14:26:00 +0200
commitbc084afb2b171cfc0b1c77a529211d7885c7cb6b (patch)
treeb55e094bae5f7cb80f51a7f186d69f429198d318 /prolog
parentff04dc7bbfabfdd40ad25281bda66c0fc5ff552b (diff)
Rework prolog query engine
Use exceptions to report errors. Used in the server branch.
Diffstat (limited to 'prolog')
-rwxr-xr-xprolog/engine.py80
1 files changed, 49 insertions, 31 deletions
diff --git a/prolog/engine.py b/prolog/engine.py
index d18b08b..6087bbc 100755
--- a/prolog/engine.py
+++ b/prolog/engine.py
@@ -30,7 +30,7 @@ class Term(object):
else:
# Parse term from [val].
if not PL_chars_to_term(bytes(val, encoding=encoding), self.ref):
- raise ValueError("invalid compound term")
+ raise ValueError('invalid compound term')
elif isinstance(val, int):
PL_put_integer(self.ref, val)
elif isinstance(val, float):
@@ -104,9 +104,31 @@ class PrologEngine(object):
# discard messages from swipl library
self.load('message_hook(_, _, _). ')
+ def exception(self, qid):
+ ref = PL_exception(qid)
+ if ref is None:
+ return False
+ try:
+ ex = Term(ref=ref)
+ if ex is not None:
+ msg = Term()
+ if PL_call_predicate(None, self.err_flags,
+ self.p['message_to_string'], Termv([ex, msg]).ref):
+ raise Exception(str(msg))
+ raise Exception('Unknown error')
+ finally:
+ PL_clear_exception()
+ return False
+
def call(self, name, args):
- return PL_call_predicate(None, self.err_flags,
- self.p[name], Termv(args).ref) == 1
+ qid = PL_open_query(None, self.err_flags, self.p[name], Termv(args).ref)
+ try:
+ if not PL_next_solution(qid):
+ if not self.exception(qid):
+ return False
+ finally:
+ PL_cut_query(qid)
+ return True
def consult(self, filename):
return self.call('consult', [Term(Atom(filename))])
@@ -120,27 +142,32 @@ class PrologEngine(object):
if tokens[idx] != ('PERIOD', '.') or idx - start <= 1:
continue
rule = stringify(tokens[start:idx])
+ orig_rule = rule
start = idx + 1
- if module != None:
+ if module is not None:
rule = module + ':(' + rule + ')'
- Ref = Term('Ref')
- if self.call('assertz', [Term(rule), Ref]):
- refs.append(Ref)
- except:
+ ref = Term()
+ if self.call('assertz', [Term(rule), ref]):
+ refs.append(ref)
+ except Exception as ex:
# unload already loaded rules (hacky, mustfix, todo)
for ref in refs:
self.call('erase', [ref])
- return None
+ raise Exception('Error loading program: {}\nBad rule: {}'.format(ex, orig_rule))
self.max_index += 1
self.refs[self.max_index] = refs
return self.max_index
def unload(self, index):
- for ref in self.refs[index]:
- self.call('erase', [ref])
- del self.refs[index]
+ try:
+ for ref in self.refs[index]:
+ self.call('erase', [ref])
+ del self.refs[index]
+ except Exception as ex:
+ # This should never happen.
+ sys.stderr.write(str(ex) + '\n')
# Get up to [n] solutions to query [q].
def query(self, q, module=None, n=1):
@@ -149,18 +176,18 @@ class PrologEngine(object):
fid = PL_open_foreign_frame()
- # Parse term and store variable names.
var_names = Term()
options = Term([Term('variable_names', [var_names])])
goal = Term()
- if not self.call('read_term_from_atom', [Term(Atom(q)), goal, options]):
- sys.stderr.write('Warning: Could not read term from {}\n'.format(q))
- return None
-
- # Check if goal is safe with currently loaded rules.
- if not self.call('safe_goal', [goal]):
- sys.stderr.write('Warning: Unsafe goal: {}\n'.format(goal))
- return None
+ try:
+ # Parse term and store variable names.
+ if not self.call('read_term_from_atom', [Term(Atom(q)), goal, options]):
+ raise Exception('Warning: Could not read term from {}\n'.format(q))
+ # Check if goal is safe with currently loaded rules.
+ if not self.call('safe_goal', [goal]):
+ raise Exception('Warning: Unsafe goal: {}\n'.format(goal))
+ except Exception as ex:
+ raise
solutions = Term()
goal_aux = Term('findnsols', [Term(n), goal, goal, solutions])
@@ -181,16 +208,7 @@ class PrologEngine(object):
result.append(variables)
PL_rewind_foreign_frame(fid_solution)
else:
- ex = PL_exception(qid)
- if ex != None:
- ex = Term(ref=PL_exception(qid))
- if ex != None:
- Msg = Term()
- if self.call('message_to_string', [ex, Msg]):
- sys.stderr.write('Error: ' + str(Msg) + '\n')
- else:
- sys.stderr.write('Unknown error\n')
- PL_clear_exception()
+ self.exception(qid)
PL_close_query(qid)
PL_discard_foreign_frame(fid)