diff options
author | Timotej Lazar <timotej.lazar@araneo.org> | 2014-10-02 16:06:31 +0200 |
---|---|---|
committer | Aleš Smodiš <aless@guru.si> | 2015-08-11 14:26:00 +0200 |
commit | bc084afb2b171cfc0b1c77a529211d7885c7cb6b (patch) | |
tree | b55e094bae5f7cb80f51a7f186d69f429198d318 | |
parent | ff04dc7bbfabfdd40ad25281bda66c0fc5ff552b (diff) |
Rework prolog query engine
Use exceptions to report errors. Used in the server branch.
-rwxr-xr-x | prolog/engine.py | 80 |
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) |