__main__.py 6.39 KB
Newer Older
1
2
import lib.reg as reg
import lib.cfl as cfl
3
4
from lib import parser
from lib.parser import ParsingError
5
6
7
from lib.checker import get_task, dfa_transform, nfa_transform, check_task, check_empty, check_alphabets, exit_correct, exit_incorrect
import sys
import signal
8
import traceback
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from typing import Any


render_html: bool = False


def wrap(text: str, tag: str, **options: str) -> str:
    if render_html:
        front = f"<{tag}"
        front += " " if options else ""
        front += " ".join(f'{k}="{v}"' for k, v in options.items()) + ">"
        return f"{front}{text}</{tag}>"
    return text


def paragraph(*args: Any) -> str:
25
    return wrap(' '.join(str(a) for a in args), "p", style="margin-bottom: 0px")
26
27
28
29


def code(val: str) -> str:
    return wrap(val, "code")
30
31
32


def print_extra_word_ce(student_word):
33
    print(paragraph("Příklad slova, které je ve studentově řešení a není v zadaném jazyce:", code(student_word)))
34
35
36


def print_missing_word_ce(teacher_word):
37
    print(paragraph("Příklad slova, které chybí ve studentově řešení a je v zadaném jazyce:", code(teacher_word)))
38
39
40
41
42
43
44


def dfa_task(teacher_type, teacher_string, task, student_string):
    try:
        student_solution = dfa_transform(student_string, task)
        teacher_solution = dfa_transform(teacher_string, teacher_type)
    except ParsingError as ex:
45
        print(paragraph("Nastala chyba při parsování:", ex))
46
        traceback.print_exc(file=sys.stderr)
47
48
        exit_incorrect()

49
50
51
52
    task_solved = ""
    if isinstance(student_solution, reg.DFA) or isinstance(student_solution, reg.NFA):
            task_solved = check_task(student_solution, task)

53
    check_empty(student_solution=student_solution,
54
55
                teacher_solution=teacher_solution,
                task_solved=task_solved)
56
57
58
59

    alphabets = check_alphabets(student_alpha=student_solution.characters,
                                teacher_alpha=teacher_solution.characters, task=task)
    if alphabets != "":
60
        print(paragraph(alphabets))
61
62
63
        exit_incorrect()

    result = reg.DFA.is_equivalent(student_solution, teacher_solution)
64

65
66
67
68
69
70
71
72
73
    if task_solved == "" and result:
        exit_correct()

    print(task_solved)

    if not result:
        student_word, teacher_word = result.left_counterexample, result.right_counterexample

        if student_word is None:
74
            print(paragraph("Studentovo řešení je podmnožinou zadaného jazyka."))
75
76
77
78
        else:
            print_extra_word_ce(student_word)

        if teacher_word is None:
79
            print(paragraph("Studentovo řešení je nadmnožinou zadaného jazyka."))
80
81
82
83
        else:
            print_missing_word_ce(teacher_word)

        if result.inf is not None:
84
            print(paragraph("Rozdíl porovnávaných jazyků je nekonečný."))
85
        else:
86
            print(paragraph("Rozdíl porovnávaných jazyků je konečný."))
87
88
89
90
91

    exit_incorrect()


def exit_cfl_ok_but_invalid_constraint(msg : str) -> None:
92
93
    print(paragraph("Gramatika generuje zadaný jazyk, ale nesplňuje podmínky"
                    f"zadání: {msg}"))
94
95
96
97
98
99
100
101
102
103
    exit(1)


def cfg_task(teacher_type: str, teacher_string: str, task: str,
             student_string: str) -> None:
    assert task[:3] == "CFG", f"Invalid task prefix {task[:3]}"
    if len(task) > 3:
        assert task[3] == '+', f"Invalid task suffix {task[3:]}"
    constraints = filter(lambda x: len(x) != 0, task[4:].split(","))
    try:
104
        teacher_solution = parser.cfg(teacher_string)
105
    except ParsingError as message:
106
        print(paragraph(f"Error parsing teacher's solution: {message}"))
107
108
109
        exit(1)

    try:
110
        student_solution = parser.cfg(student_string)
111
    except ParsingError as message:
112
        print(paragraph(f"Error parsing student's solution: {message}"))
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
        exit(1)

    check_empty(student_solution=student_solution,
                teacher_solution=teacher_solution)

    alphabets = check_alphabets(student_alpha=student_solution.terminals,
                                teacher_alpha=teacher_solution.terminals, task="GRA")
    if alphabets != "":
        print(alphabets)
        exit_incorrect()

    equals = cfl.CFG.is_equivalent_test(student_solution, teacher_solution)

    if equals:
        failed = []
        for constraint in constraints:
            if constraint == "¬ε":
                if not student_solution.is_epsilon_normal_form():
                    failed.append("obsahuje nepovolené ε-kroky")
            elif constraint == "¬s":
                if student_solution.has_simple_rules():
                    failed.append("obsahuje nepovolená jednoduchá pravidla")
            elif constraint == "CNF":
                if not student_solution.is_cnf():
                    failed.append("není v CNF")
            else:
                assert False, f"Unknown constraint `{constraint}'"

        if len(failed) == 0:
            exit_correct()
        exit_cfl_ok_but_invalid_constraint(", ".join(failed))

    if equals.left_counterexample is not None:
        print_extra_word_ce(equals.left_counterexample)
    if equals.right_counterexample:
        print_missing_word_ce(equals.right_counterexample)

    exit_incorrect()


def main():
    signal.alarm(50)

156
157
158
159
    global render_html
    if sys.argv[1] == "--html":
        render_html = True

160
    # Get string with student's solution.
161
    with open(sys.argv[1 + render_html]) as student_file:
162
163
164
165
166
167
168
169
170
171
172
        student_string = student_file.read()

    # Get string with teacher's solution and type of the task.
    for argument in sys.argv:
        if argument[:2] == "-o":
            teacher_string = argument[2:]

    try:
        task_prefix, teacher_string = teacher_string.split(":", 1)
        teacher_type, task = get_task(task_prefix)

173
        # When time comes, teacher's solution can surely be also GRA or REG, see web_checker.
174
175
176
177
178
179
180
        if teacher_type == "DFA" or teacher_type == "NFA":
            dfa_task(teacher_type=teacher_type, teacher_string=teacher_string,
                     task=task, student_string=student_string)
        elif teacher_type == "CFG":
            cfg_task(teacher_type=teacher_type, teacher_string=teacher_string,
                     task=task, student_string=student_string)
        else:
181
            print(paragraph(f"Invalid question type {task_prefix}"))
182
183
184
            exit(1)

    except Exception as ex:
185
        print(paragraph("Error inside of fja_checker:", ex.args))
186
        traceback.print_exc(file=sys.stderr)
187
188
189
190
        exit(1)

if __name__ == "__main__":
    main()