From 487b9a3cb6849a49189c56925cbd4ddd30c230bf Mon Sep 17 00:00:00 2001 From: Timotej Lazar Date: Wed, 17 Dec 2014 12:24:25 +0100 Subject: Mark solution predicates as static after loading This prevents incorrect student solutions from overwriting or adding to predicates in solution modules. --- prolog/engine.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/prolog/engine.py b/prolog/engine.py index 07489df..088948e 100644 --- a/prolog/engine.py +++ b/prolog/engine.py @@ -85,6 +85,7 @@ class PrologEngine(object): 'arg/3': PL_predicate(b'arg', 3, None), 'assertz/1': PL_predicate(b'assertz', 1, None), 'call_with_time_limit/2': PL_predicate(b'call_with_time_limit', 2, None), + 'compile_predicates/1': PL_predicate(b'compile_predicates', 1, None), 'consult/1': PL_predicate(b'consult', 1, None), 'functor/3': PL_predicate(b'functor', 3, None), 'message_to_string/2': PL_predicate(b'message_to_string', 2, None), @@ -116,19 +117,25 @@ class PrologEngine(object): # 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) + + fid = PL_open_foreign_frame() + predicates = set() for rule in prolog.util.split(code): self.call('assertz/1', [Term('{}:({})'.format(module, rule))]) + predicates.add('{}:{}'.format(module, self.predicate_indicator(rule))) + self.call('compile_predicates/1', [Term([Term(p) for p in predicates])]) 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')]) + + fid = PL_open_foreign_frame() + result = self.call('add_import_module/3', [Term(m_user), Term(m_solution), Term('end')]) PL_discard_foreign_frame(fid) + return result # 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 @@ -206,7 +213,7 @@ class PrologEngine(object): self.call('assertz/1', [Term('{}:({})'.format(m_user, rule))]) predicates.add(self.predicate_indicator(rule)) - for i, query in enumerate(queries): + for query in queries: result = self.query(query, m_user) correct &= (len(result) == 1 and result[0]['X'] == self.answers[(pid, query)]) except Exception as ex: -- cgit v1.2.1