parse_inner()   F
last analyzed

Complexity

Conditions 15

Size

Total Lines 57

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 15
dl 0
loc 57
rs 3.2957

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like parse_inner() 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
# There's already a 'parser' in the Python standard library, so we're
2
# forced to call this trifle_parser.py.
3
4
from trifle_types import (
5
    List, Hashmap,
6
    OpenParen, CloseParen, OpenCurlyParen, CloseCurlyParen,
7
    TrifleExceptionInstance)
8
from errors import parse_failed
9
from interpreter.hashable import check_hashable
10
11
12
def list_to_hashmap(trifle_list):
13
    """Convert (1 2 3 4) to {1 2, 3 4}, checking all the corner cases.
14
15
    """
16
    if len(trifle_list.values) % 2 != 0:
17
        # TODO: This should be a syntax error.
18
        return TrifleExceptionInstance(
19
            parse_failed,
20
            u'Hashmaps must have an even number of elements, but got %d!' % len(trifle_list.values))
21
22
    # TODO: Once we have immutable containers, we should allow these as keys too.
23
    keys = []
24
    values = []
25
    for i in range(len(trifle_list.values) / 2):
26
        keys.append(trifle_list.values[2 * i])
27
        values.append(trifle_list.values[2 * i + 1])
28
29
    is_hashable_error = check_hashable(keys)
30
    if isinstance(is_hashable_error, TrifleExceptionInstance):
31
        return is_hashable_error
32
33
    hashmap = Hashmap()
34
    for i in range(len(keys)):
35
        hashmap.dict[keys[i]] = values[i]
36
37
    return hashmap
38
39
40
def parse_inner(tokens, top_level, expecting_list):
41
    parsed_expressions = List()
42
    saw_closing_paren = False
43
44
    # TODO: This could cause a stack overflow for deeply nested literals.
45
    while tokens:
46
        token = tokens.pop(0)
47
48
        if isinstance(token, OpenParen):
49
            parsed = parse_inner(tokens, top_level=False, expecting_list=True)
50
51
            if isinstance(parsed, TrifleExceptionInstance):
52
                return parsed
53
54
            parsed_expressions.append(parsed)
55
        elif isinstance(token, OpenCurlyParen):
56
            parsed = parse_inner(tokens, top_level=False, expecting_list=False)
57
58
            if isinstance(parsed, TrifleExceptionInstance):
59
                return parsed
60
                
61
            parsed_expressions.append(parsed)
62
        elif isinstance(token, CloseParen):
63
            if top_level:
64
                return TrifleExceptionInstance(
65
                    parse_failed,
66
                    u'Closing ) has no matching opening (.')
67
            elif not expecting_list:
68
                return TrifleExceptionInstance(
69
                    parse_failed,
70
                    u'Closing ) does not match opening {.')
71
            else:
72
                saw_closing_paren = True
73
                break
74
        elif isinstance(token, CloseCurlyParen):
75
            if top_level:
76
                return TrifleExceptionInstance(
77
                    parse_failed,
78
                    u'Closing } has no matching opening {.')
79
            elif expecting_list:
80
                return TrifleExceptionInstance(
81
                    parse_failed,
82
                    u'Closing } does not match opening (.')
83
            else:
84
                saw_closing_paren = True
85
                break
86
        else:
87
            parsed_expressions.append(token)
88
89
    if not top_level and not saw_closing_paren:
90
        return TrifleExceptionInstance(
91
            parse_failed, u'Open paren was not closed.')
92
93
    if expecting_list:
94
        return parsed_expressions
95
    else:
96
        return list_to_hashmap(parsed_expressions)
97
98
99
def parse(tokens):
100
    return parse_inner(tokens.values, top_level=True, expecting_list=True)
101
102
103
def parse_one(tokens):
104
    """Only return the first expression parsed. Useful when parsing short
105
    code snippets.
106
107
    """
108
    parse_result = parse(tokens)
109
110
    if isinstance(parse_result, TrifleExceptionInstance):
111
        return parse_result
112
    else:
113
        return parse_result.values[0]
114