source.analyzer   C
last analyzed

Complexity

Total Complexity 57

Size/Duplication

Total Lines 197
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 158
dl 0
loc 197
rs 5.04
c 0
b 0
f 0
wmc 57

14 Functions

Rating   Name   Duplication   Size   Complexity  
A handle_fourth_element() 0 5 2
A handle_first_element() 0 11 3
A test_word_len() 0 2 1
A compare_database_string() 0 2 1
A handle_third_element() 0 7 2
A test_exceptional_mnemonics() 0 7 3
A test_basic() 0 13 4
A test_hexadecimal_case() 0 8 3
F analyzer() 0 46 16
A test_decimal_case() 0 11 5
B handle_exceptional_cases() 0 16 7
A test_char() 0 9 5
A test_hexadecimal() 0 5 4
A show_error() 0 22 1

How to fix   Complexity   

Complexity

Complex classes like source.analyzer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
from source.__config__ import ALONE_IN_LINE
2
from source.__config__ import MRI
3
from source.__config__ import NON_MRI
4
from source.__config__ import PREUDOMSTRUCTION
5
6
7
def analyzer(line: str, declaration: set, usage: set, line_number: int) -> tuple:
8
    error_counter = 0
9
    strings = line.split()
10
    words_number = len(strings)
11
12
    if words_number == 1:
13
        if strings[0] not in ALONE_IN_LINE:
14
            error_counter += show_error(2, line_number)
15
16
    elif words_number == 2:
17
        declaration, usage, err_c = handle_exceptional_cases(strings[1], strings[0], declaration, usage, line_number)
18
        error_counter += err_c
19
20
    elif words_number == 3:
21
        x = strings[0] in MRI or strings[0] in PREUDOMSTRUCTION[1:3]
22
        y = strings[1] in MRI or strings[1] in PREUDOMSTRUCTION[1:3]
23
        if x and not y:
24
            a = 1
25
        elif y and not x:
26
            a = 2
27
        else:
28
            a = 0
29
            error_counter += show_error(8, line_number)
30
        if a != 0:
31
            declaration, usage, err_c = handle_exceptional_cases(strings[a], strings[a - 1], declaration, usage,
32
                                                                 line_number)
33
            error_counter += err_c
34
            if a == 1:
35
                error_counter += handle_fourth_element(strings[2], line_number)
36
            elif a == 2:
37
                declaration, err_c = handle_first_element(strings[0], declaration, line_number)
38
                error_counter += err_c
39
40
    elif words_number == 4:
41
        declaration, usage, err_c = handle_exceptional_cases(strings[2], strings[1], declaration, usage, line_number)
42
        error_counter += err_c
43
        if (strings[1] not in ALONE_IN_LINE) and (strings[1] != PREUDOMSTRUCTION[0]):
44
            declaration, err_c = handle_first_element(strings[0], declaration, line_number)
45
            error_counter += err_c
46
            error_counter += handle_fourth_element(strings[3], line_number)
47
        elif strings[1] == PREUDOMSTRUCTION[0]:
48
            error_counter += show_error(17, line_number)
49
    else:
50
        error_counter += show_error(1, line_number)
51
52
    return declaration, usage, error_counter
53
54
55
def handle_first_element(word: str, declaration: set, line_number: int) -> tuple:
56
    error_counter = 0
57
    if not test_char(word, 'comma'):
58
        error_counter += show_error(4, line_number)
59
    else:
60
        word = word[:-1]
61
        state, err_c = test_basic(word, [MRI, NON_MRI, PREUDOMSTRUCTION], line_number)
62
        error_counter += err_c
63
        if state:
64
            declaration.add(word)
65
    return declaration, error_counter
66
67
68
def handle_third_element(word: str, usage: set, line_number: int) -> tuple:
69
    error_counter = 0
70
    state, err_c = test_basic(word, [MRI, NON_MRI, PREUDOMSTRUCTION], line_number)
71
    error_counter += err_c
72
    if state:
73
        usage.add(word)
74
    return usage, error_counter
75
76
77
def handle_fourth_element(word: str, line_number: int) -> int:
78
    error_counter = 0
79
    if not test_char(word, 'i'):
80
        error_counter += show_error(5, line_number)
81
    return error_counter
82
83
84
def handle_exceptional_cases(word: str, mnemonic: str, declaration: set, usage: set, line_number: int) -> tuple:
85
    error_counter = 0
86
    i = test_exceptional_mnemonics(mnemonic)
87
    if i == -1:
88
        if not compare_database_string(mnemonic, MRI):
89
            error_counter += show_error(6, line_number)
90
        else:
91
            usage, err_c = handle_third_element(word, usage, line_number)
92
            error_counter += err_c
93
    elif i == 0 or i == 1:
94
        error_counter += test_hexadecimal_case(word, line_number)
95
    elif i == 2:
96
        error_counter += test_decimal_case(word, line_number)
97
    elif i == 3:
98
        error_counter += show_error(16, line_number)
99
    return declaration, usage, error_counter
100
101
102
def test_basic(word: str, database, line_number: int) -> tuple:
103
    error_counter = 0
104
    state = True
105
    if test_char(word, 'first'):
106
        error_counter += show_error(3, line_number)
107
        state = False
108
    if not test_char(word, 'length'):
109
        error_counter += show_error(11, line_number)
110
        state = False
111
    if compare_database_string(word, database):
112
        error_counter += show_error(7, line_number)
113
        state = False
114
    return state, error_counter
115
116
117
def test_char(word: str, mode: str) -> bool:
118
    if mode == 'first':
119
        return word[0].isdigit()
120
    elif mode == 'comma':
121
        return word[-1] == ','
122
    elif mode == 'i':
123
        return word == 'i'
124
    elif mode == 'length':
125
        return test_word_len(word, 3)
126
127
128
def test_word_len(word: str, length: int) -> bool:
129
    return len(word) == length
130
131
132
def test_exceptional_mnemonics(mnemonic: str):
133
    if mnemonic in PREUDOMSTRUCTION[:3]:
134
        return PREUDOMSTRUCTION.index(mnemonic)
135
    elif mnemonic in ALONE_IN_LINE:
136
        return 3
137
    else:
138
        return -1
139
140
141
def test_hexadecimal_case(word: str, line_number: int) -> int:
142
    error_counter = 0
143
    if not test_word_len(word, 4):
144
        error_counter += show_error(12, line_number)
145
    else:
146
        if not test_hexadecimal(word):
147
            error_counter += show_error(13, line_number)
148
    return error_counter
149
150
151
def test_hexadecimal(word: str) -> bool:
152
    for i in word:
153
        if not ('0' <= i <= '9') and not ('A' <= i <= 'F'):
154
            return False
155
    return True
156
157
158
def test_decimal_case(word: str, line_number: int) -> int:
159
    error_counter = 0
160
    if word[0] == '-':
161
        word = word[1:]
162
    if word.isdecimal():
163
        num = int(word)
164
        if num < -32768 or 32767 < num:
165
            error_counter += show_error(14, line_number)
166
    else:
167
        error_counter += show_error(15, line_number)
168
    return error_counter
169
170
171
def compare_database_string(word: str, database) -> bool:
172
    return word in database
173
174
175
def show_error(error_code: int, line_number: int):
176
    error_text_list = ["Unexpected Error\n",
177
                       "Exceeded max words [4] in one line limit.\n",
178
                       "Only MRI symbols and END symbol can be alone in one line of code.\n",
179
                       "First character of variable/function/command can't be digits.\n",
180
                       "First element in this line of code should be finished with ','.\n",
181
                       "Last element in \"this\" line of code should be \"i\".\n",
182
                       "Can't recognize mnemonic\n",
183
                       "Using system reserved mnemonics for variable/function is forbidden. \n",
184
                       "Invalid syntax.",
185
                       "The variable/function is not defined. \n",
186
                       "First element of line can't be only ','. \n",
187
                       "Variable/function name can't be more than 3 characters.\n",
188
                       "Hexadecimal number must be in range 0000 to FFFF.\n",
189
                       "Hexadecimal number should come after ORG/HEX mnemonic.\n",
190
                       "Decimal number must be signed 2 byte integer (in range -32768 to 32767).\n",
191
                       "Decimal number should come after DEC mnemonic.\n",
192
                       "Using non-MRI mnemonics or END with other elements isn't correct .\n",
193
                       "ORG mnemonic must be used with just a num after it, nothing before and nothing after num.\n",
194
                       "Invalid error code."]
195
    print("(line => {}) ERROR: ".format(line_number) + error_text_list[error_code])
196
    return 1
197