summaryrefslogtreecommitdiff
path: root/prolog/common.py
blob: 5187c65c8d3d28f43ccf4577cdca689e46b503d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# coding=utf-8

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?
    # this will have to be solved more generally
    targets = {'a', 'b', 'c', 'x', 'y', 'z', 'h', 't', '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