diff options
Diffstat (limited to 'prolog')
-rw-r--r-- | prolog/engine.py | 134 |
1 files changed, 67 insertions, 67 deletions
diff --git a/prolog/engine.py b/prolog/engine.py index d15704a..07489df 100644 --- a/prolog/engine.py +++ b/prolog/engine.py @@ -113,38 +113,22 @@ class PrologEngine(object): # Dictionary of correct answers; keys are (pid, query). self.answers = {} - # Return a description of the last exception, or None if no error occurred. - def error(self, qid): - error_ref = PL_exception(qid) - if not error_ref: - return None - PL_clear_exception() - - # Get the Prolog error message. + # Loads the correct solution [code] to problem [pid]. + # TODO handle library loading. + def load_solution(self, pid, code): fid = PL_open_foreign_frame() - msg = Term() - if PL_call_predicate(None, self.err_flags, self.p['message_to_string/2'], - Termv([Term(ref=error_ref), msg]).ref): - error_str = str(msg) - else: - error_str = 'Unknown error' + module = 'solution{}'.format(pid) + for rule in prolog.util.split(code): + self.call('assertz/1', [Term('{}:({})'.format(module, rule))]) PL_discard_foreign_frame(fid) - return error_str - - # Call the Prolog predicate [name]. Raise an exception on error. Since this - # creates a Termv object, it should be called within an open foreign frame. - def call(self, name, args): - qid = PL_open_query(None, self.err_flags, self.p[name], Termv(args).ref) - try: - if not PL_next_solution(qid): - error_msg = self.error(qid) - if error_msg: - raise Exception(error_msg) - return False - finally: - PL_cut_query(qid) - return True + # Import the correct solution for problem [pid] into module for user [uid]. + def mark_solved(self, uid, pid): + fid = PL_open_foreign_frame() + m_user = 'user{}'.format(uid) + m_solution = 'solution{}'.format(pid) + return self.call('add_import_module/3', [Term(m_user), Term(m_solution), Term('end')]) + PL_discard_foreign_frame(fid) # Get up to [n] solutions to query [q]. If there are no solutions, return # an empty list. Raise an exception on error (either from self.call, or due @@ -198,44 +182,6 @@ class PrologEngine(object): return result - # Loads the correct solution [code] to problem [pid]. - # TODO handle library loading. - def load_solution(self, pid, code): - fid = PL_open_foreign_frame() - module = 'solution{}'.format(pid) - for rule in prolog.util.split(code): - self.call('assertz/1', [Term('{}:({})'.format(module, rule))]) - PL_discard_foreign_frame(fid) - - # Import the correct solution for problem [pid] into module for user [uid]. - def mark_solved(self, uid, pid): - fid = PL_open_foreign_frame() - m_user = 'user{}'.format(uid) - m_solution = 'solution{}'.format(pid) - return self.call('add_import_module/3', [Term(m_user), Term(m_solution), Term('end')]) - PL_discard_foreign_frame(fid) - - # Return the main functor defined by [clause], e.g. dup/2. - def predicate_indicator(self, clause): - # Return the main functor for [term]. - def main_functor(term): - name = Term() - arity = Term() - self.call('functor/3', [term, name, arity]) - return '{}/{}'.format(name, arity) - - fid = PL_open_foreign_frame() - clause = Term(clause) - functor = main_functor(clause) - # Check whether [clause] is a rule or a fact. - if functor == ':-/2': - # [clause] is a rule, return the main functor for the head. - head = Term() - self.call('arg/3', [Term(1), clause, head]) - functor = main_functor(head) - PL_discard_foreign_frame(fid) - return functor - # Test whether [code] gives the same answer to [query] as the correct # solution. The solution for problem [pid] should be loaded beforehand. def test(self, uid, pid, code, queries): @@ -273,6 +219,60 @@ class PrologEngine(object): return correct + # Call the Prolog predicate [name]. Raise an exception on error. Since this + # creates a Termv object, it should be called within an open foreign frame. + def call(self, name, args): + qid = PL_open_query(None, self.err_flags, self.p[name], Termv(args).ref) + try: + if not PL_next_solution(qid): + error_msg = self.error(qid) + if error_msg: + raise Exception(error_msg) + return False + finally: + PL_cut_query(qid) + return True + + # Return a description of the last exception, or None if no error occurred. + def error(self, qid): + error_ref = PL_exception(qid) + if not error_ref: + return None + PL_clear_exception() + + # Get the Prolog error message. + fid = PL_open_foreign_frame() + msg = Term() + if PL_call_predicate(None, self.err_flags, self.p['message_to_string/2'], + Termv([Term(ref=error_ref), msg]).ref): + error_str = str(msg) + else: + error_str = 'Unknown error' + PL_discard_foreign_frame(fid) + + return error_str + + # Return the main functor defined by [clause], e.g. dup/2. + def predicate_indicator(self, clause): + # Return the main functor for [term]. + def main_functor(term): + name = Term() + arity = Term() + self.call('functor/3', [term, name, arity]) + return '{}/{}'.format(name, arity) + + fid = PL_open_foreign_frame() + clause = Term(clause) + functor = main_functor(clause) + # Check whether [clause] is a rule or a fact. + if functor == ':-/2': + # [clause] is a rule, return the main functor for the head. + head = Term() + self.call('arg/3', [Term(1), clause, head]) + functor = main_functor(head) + PL_discard_foreign_frame(fid) + return functor + # Basic sanity check. if __name__ == '__main__': engine = PrologEngine() |