File: location.py

package info (click to toggle)
pypy3 7.3.19%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 212,236 kB
  • sloc: python: 2,098,316; ansic: 540,565; sh: 21,462; asm: 14,419; cpp: 4,451; makefile: 4,209; objc: 761; xml: 530; exp: 499; javascript: 314; pascal: 244; lisp: 45; csh: 12; awk: 4
file content (193 lines) | stat: -rw-r--r-- 5,772 bytes parent folder | download | duplicates (2)
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
from rpython.rlib import rstring

class DecodeError(Exception):
    pass

def encode_varint_unsigned(i, res):
    # XXX can't use code in dawg because that doesn't take a StringBuilder :-(
    # https://en.wikipedia.org/wiki/LEB128 unsigned variant
    more = True
    if i < 0:
        raise ValueError("only positive numbers supported", i)
    while more:
        lowest7bits = i & 0b1111111
        i >>= 7
        if i == 0:
            more = False
        else:
            lowest7bits |= 0b10000000
        res.append(chr(lowest7bits))

def decode_varint_unsigned(b, index=0):
    # can't use code in dawg because this variant needs to be safe against
    # invalidly encoded varints
    res = 0
    shift = 0
    while True:
        byte = ord(b[index])
        res = res | ((byte & 0b1111111) << shift)
        index += 1
        if not (byte & 0b10000000):
            return res, index
        shift += 7
        if index == len(b):
            raise DecodeError


def encode_positions(l, firstlineno):
    # l is a list of four-tuples (lineno, end_lineno, col_offset,
    # end_col_offset) coming out of the AST nodes
    table = rstring.StringBuilder(4 * len(l))
    for position_info in l:
        encode_single_position(table, position_info, firstlineno)


    return table.build()

def encode_single_position(table, position_info, firstlineno):
    # this is really inefficient for now. we can always change it though

    # three formats:
    # (1) 0:
    #     no info at all
    # (2) varint lineno_delta 0:
    #     just a line number no further info, the lineno_delta is 1 too big and
    #     is relative to co_firstlineno
    # (3) varint lineno_delta, char col_offset, char end_col_offset, char end_lineno_delta
    #     full info, col_offset and end_col_offset are 1 too big to distinguish
    #     from case (2)

    # XXX clarify what missing values are, 0 or -1?
    lineno, end_lineno, col_offset, end_col_offset = position_info
    if lineno == -1 or lineno < firstlineno:
        table.append(chr(0))
        return
        # case (1)
    lineno_delta = lineno - firstlineno + 1
    end_line_delta = end_lineno - lineno
    # encode lineno_delta as a varsized int
    encode_varint_unsigned(lineno_delta, table)

    # the rest gets one byte each (or a single 0 for 'everything invalid')
    if (
        col_offset >= 255
        or end_col_offset >= 255
        or col_offset == -1
        or end_col_offset == -1
        or end_line_delta < 0
        or end_line_delta > 255
    ):
        #
        table.append(chr(0))
    else:
        table.append(chr(col_offset + 1))
        table.append(chr(end_col_offset + 1))
        table.append(chr(end_line_delta))

def _decode_entry(table, firstlineno, position):
    if position >= len(table):
        raise DecodeError
    lineno, position = decode_varint_unsigned(table, position)
    if lineno == 0:
        return (-1, -1, -1, -1, position)
    lineno -= 1
    lineno += firstlineno
    if position == len(table):
        raise DecodeError
    col_offset = ord(table[position]) - 1
    position += 1
    if col_offset == -1: # was a single 0, no more bytes
        end_col_offset = -1
        end_lineno = -1
    else:
        if position + 1 >= len(table):
            raise DecodeError
        end_col_offset = ord(table[position]) - 1
        end_line_delta = ord(table[position + 1])
        position += 2
        end_lineno = lineno + end_line_delta
    return lineno, end_lineno, col_offset, end_col_offset, position


def decode_positions(table, firstlineno):
    res = []
    position = 0
    while position < len(table):
        lineno, end_lineno, col_offset, end_col_offset, position = _decode_entry(table, firstlineno, position)
        res.append((lineno, end_lineno, col_offset, end_col_offset))
    return res

def offset2lineno(c, stopat):
    if stopat == -1:
        return c.co_firstlineno
    try:
        return _offset2lineno(c.co_linetable, c.co_firstlineno, stopat // 2)
    except DecodeError:
        return -1

def _offset2lineno(linetable, firstlineno, stopat):
    position = 0
    lineno = -1
    for i in range(stopat + 1):
        tup = _decode_entry(linetable, firstlineno, position)
        position = tup[4]
        lineno = tup[0]
    return lineno


# converting back to lnotab

def _encode_lnotab_pair(addr, line, table):
    while addr > 255:
        table.append(chr(255))
        table.append(chr(0))
        addr -= 255
    while line < -128:
        table.append(chr(addr))
        table.append(chr(-128 + 256))
        line += 128
        addr = 0
    while line > 127:
        table.append(chr(addr))
        table.append(chr(127))
        line -= 127
        addr = 0
    table.append(chr(addr))

    # store as signed char
    assert -128 <= line <= 127
    if line < 0:
        line += 256
    table.append(chr(line))

def linetable2lnotab(linetable, firstlineno):
    position = 0
    res = []
    line = firstlineno
    start_pc = pc = 0
    while position < len(linetable):
        try:
            lineno, _, _, _, position = _decode_entry(linetable, firstlineno, position)
        except DecodeError:
            return b''
        if lineno != line:
            bdelta = pc - start_pc
            ldelta = lineno - line
            _encode_lnotab_pair(bdelta, ldelta, res)
            line = lineno
            start_pc = pc
        pc += 2
    return b"".join(res)

def marklines(linetable, firstlineno):
    res = []
    line = -1
    position = 0
    while position < len(linetable):
        lineno, _, _, _, position = _decode_entry(linetable, firstlineno, position)
        if lineno != line and lineno != -1:
            res.append(lineno)
            line = lineno
        else:
            res.append(-1)
    return res