cython

Форк
0
/
LineTable.py 
114 строк · 4.2 Кб
1
"""
2
Build a line table for CodeObjects, according to PEP-626 / Python 3.11.
3

4
See  https://github.com/python/cpython/blob/1054a755a3016f95fcd24b3ad20e8ed9048b7939/InternalDocs/locations.md
5
See  https://github.com/python/cpython/blob/1054a755a3016f95fcd24b3ad20e8ed9048b7939/Python/assemble.c#L192
6
"""
7

8
import cython
9

10

11
def build_line_table(positions, firstlineno):
12
    # positions is a list of four-tuples (start_lineno, end_lineno, start_col_offset, end_col_offset)
13
    table_bytes = []
14
    last_lineno = firstlineno
15
    for position_info in positions:
16
        last_lineno = encode_single_position(table_bytes, position_info, last_lineno)
17
    linetable = ''.join(table_bytes)
18

19
    """
20
    # Hacky debug helper code for the line table generation.
21
    code_obj = build_line_table.__code__.replace(co_linetable=linetable.encode('latin1'), co_firstlineno=firstlineno)
22
    print()
23
    print(repr(linetable))
24
    print(positions)
25
    print(list(code_obj.co_positions()))
26
    """
27

28
    return linetable
29

30

31
@cython.cfunc
32
def encode_single_position(table_bytes: list, position_info: tuple, last_lineno: cython.int) -> cython.int:
33
    start_lineno: cython.int
34
    end_lineno: cython.int
35
    start_column: cython.int
36
    end_column: cython.int
37

38
    start_lineno, end_lineno, start_column, end_column = position_info
39
    assert start_lineno >= last_lineno, f"{start_lineno} >= {last_lineno}"  # positions should be sorted
40

41
    last_lineno_delta: cython.int = start_lineno - last_lineno
42

43
    if end_lineno == start_lineno:
44
        # All in one line, can try short forms.
45
        if last_lineno_delta == 0 and start_column < 80 and 0 <= (end_column - start_column) < 16:
46
            # Short format (code 0-9): still on same line, small column offset
47
            encode_location_short(table_bytes, start_column, end_column)
48
            return end_lineno
49
        elif 0 <= last_lineno_delta < 3 and start_column < 128 and end_column < 128:
50
            # One line format (code 10-12): small line offsets / larger column offsets
51
            encode_location_oneline(table_bytes, last_lineno_delta, start_column, end_column)
52
            return end_lineno
53

54
    # Store in long format (code 14)
55
    encode_location_start(table_bytes, 14)
56
    # Since we sort positions, negative line deltas should never occur ==> inline encode_varint_signed()
57
    encode_varint(table_bytes, last_lineno_delta << 1)
58
    encode_varint(table_bytes, end_lineno - start_lineno)
59
    encode_varint(table_bytes, start_column + 1)
60
    encode_varint(table_bytes, end_column + 1)
61
    return end_lineno
62

63

64
@cython.exceptval(-1, check=False)
65
@cython.cfunc
66
def encode_location_start(table_bytes: list, code: cython.int) -> cython.int:
67
    # "Instruction" size is always 1
68
    # 128 | (code << 3) | (length - 1)
69
    table_bytes.append(chr(128 | (code << 3)))
70
    return 0
71

72

73
@cython.exceptval(-1, check=False)
74
@cython.cfunc
75
def encode_location_short(table_bytes: list, start_column: cython.int, end_column: cython.int) -> cython.int:
76
    low_bits: cython.int = start_column & 7
77
    code: cython.int = start_column >> 3
78
    # inlined encode_location_start()
79
    table_bytes.append(f"{128 | (code << 3):c}{(low_bits << 4) | (end_column - start_column):c}")
80
    return 0
81

82

83
@cython.exceptval(-1, check=False)
84
@cython.cfunc
85
def encode_location_oneline(table_bytes: list, line_delta: cython.int, start_column: cython.int, end_column: cython.int) -> cython.int:
86
    code: cython.int = 10 + line_delta
87
    # inlined encode_location_start()
88
    table_bytes.append(f"{128 | (code << 3):c}{start_column:c}{end_column:c}")
89
    return 0
90

91

92
"""
93
# Since we sort positions, negative line deltas should not occur.
94
@cython.cfunc
95
def encode_varint_signed(table_bytes: list, value: cython.int) -> cython.int:
96
    # (unsigned int)(-val) has undefined behavior for INT_MIN
97
    uval: cython.uint = cython.cast(cython.uint, value) if cython.compiled else value
98
    if value < 0:
99
        uval = ((0 - uval) << 1) | 1
100
    else:
101
        uval = uval << 1
102
    encode_varint(table_bytes, uval)
103
"""
104

105

106
@cython.exceptval(-1, check=False)
107
@cython.cfunc
108
def encode_varint(table_bytes: list, value: cython.uint) -> cython.int:
109
    assert value > 0 or value == 0
110
    while value >= 64:
111
        table_bytes.append(chr(64 | (value & 63)))
112
        value >>= 6
113
    table_bytes.append(chr(value))
114
    return 0
115

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.