import operator import prolog.engine from prolog.util import tokenize from server.hints import Hint, HintPopup id = 1 hint_type = { 'no_hint': Hint('no_hint'), 'program_already_correct': Hint('program_already_correct'), 'system_error': Hint('system_error'), 'test_results': Hint('test_results'), 'syntax_error': Hint('syntax_error'), 'monkey_main': Hint('monkey_main'), 'monkey_change': HintPopup('monkey_change', style='change'), 'monkey_insert': HintPopup('monkey_insert', style='insert'), 'monkey_remove': HintPopup('monkey_remove', style='remove'), 'noncapitalised_variable': Hint('noncapitalised_variable'), 'noncapitalised_variable_markup': HintPopup('noncapitalised_variable_markup'), 'fail_rule': HintPopup('fail_rule'), } # Check program for syntax errors. def check_syntax(code, aux_code): try: engine_id, output = prolog.engine.create(code=code+aux_code, timeout=1.0) if 'error' in map(operator.itemgetter(0), output): errors_msg = '\n'.join(['{}: {}'.format(m_type, m_text) for m_type, m_text in output]) return [{'id': 'syntax_error', 'args': {'messages': errors_msg}}] except socket.timeout as ex: # TODO check if a timeout can actually happen here pass finally: if engine_id is not None: prolog.engine.destroy(engine_id) return [] def hint(code, aux_code): tokens = tokenize(code) hints = [] # rules like a(X) :- fail. for i, t in enumerate(tokens[:-2]): t1 = tokens[i+1] t2 = tokens[i+2] if t.val == ':-' and t1.val in ('fail', 'false') and t2.val == '.': hints += [{'id': 'fail_rule', 'start': t.pos, 'end': t2.pos + len(t2.val)}] # a,b,c are a bit dangerous when crossing the river exercise is being solved # what about potential numbers after letters? # TODO this will have to be solved more generally targets = {'a', 'c', 'x', 'y', 'z', 'h', 'l', 's', 'v', 'w'} marks = [(t.pos, t.pos + len(t.val)) for t in tokens if t.type == 'NAME' and t.val in targets] if marks: hints += [{'id': 'noncapitalised_variable_markup', 'start': m[0], 'end': m[1]} for m in marks] + \ [{'id': 'noncapitalised_variable'}] return hints