summaryrefslogtreecommitdiff
path: root/prolog
diff options
context:
space:
mode:
Diffstat (limited to 'prolog')
-rw-r--r--prolog/engine.py134
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()