-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathrrange.py
More file actions
223 lines (196 loc) · 7.39 KB
/
rrange.py
File metadata and controls
223 lines (196 loc) · 7.39 KB
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
from rpython.flowspace.model import Constant
from rpython.rtyper.error import TyperError
from rpython.rtyper.lltypesystem.lltype import Signed, Void, Ptr
from rpython.rtyper.rlist import dum_nocheck, dum_checkidx
from rpython.rtyper.rmodel import Repr, IteratorRepr
from rpython.rtyper.rint import IntegerRepr
from rpython.tool.pairtype import pairtype
class AbstractRangeRepr(Repr):
def __init__(self, step):
self.step = step
if step != 0:
self.lowleveltype = self.RANGE
else:
self.lowleveltype = self.RANGEST
def _getstep(self, v_rng, hop):
return hop.genop(self.getfield_opname,
[v_rng, hop.inputconst(Void, 'step')], resulttype=Signed)
def rtype_len(self, hop):
v_rng, = hop.inputargs(self)
if self.step == 1:
return hop.gendirectcall(ll_rangelen1, v_rng)
elif self.step != 0:
v_step = hop.inputconst(Signed, self.step)
else:
v_step = self._getstep(v_rng, hop)
return hop.gendirectcall(ll_rangelen, v_rng, v_step)
class __extend__(pairtype(AbstractRangeRepr, IntegerRepr)):
def rtype_getitem((r_rng, r_int), hop):
if hop.has_implicit_exception(IndexError):
spec = dum_checkidx
else:
spec = dum_nocheck
v_func = hop.inputconst(Void, spec)
v_lst, v_index = hop.inputargs(r_rng, Signed)
if r_rng.step != 0:
cstep = hop.inputconst(Signed, r_rng.step)
else:
cstep = r_rng._getstep(v_lst, hop)
if hop.args_s[1].nonneg:
llfn = ll_rangeitem_nonneg
else:
llfn = ll_rangeitem
hop.exception_is_here()
return hop.gendirectcall(llfn, v_func, v_lst, v_index, cstep)
# ____________________________________________________________
#
# Low-level methods.
def _ll_rangelen(start, stop, step):
if step > 0:
result = (stop - start + (step - 1)) // step
else:
result = (start - stop - (step + 1)) // (-step)
if result < 0:
result = 0
return result
def ll_rangelen(l, step):
return _ll_rangelen(l.start, l.stop, step)
def ll_rangelen1(l):
result = l.stop - l.start
if result < 0:
result = 0
return result
def ll_rangeitem_nonneg(func, l, index, step):
if func is dum_checkidx and index >= _ll_rangelen(l.start, l.stop, step):
raise IndexError
return l.start + index * step
def ll_rangeitem(func, l, index, step):
if func is dum_checkidx:
length = _ll_rangelen(l.start, l.stop, step)
if index < 0:
index += length
if index < 0 or index >= length:
raise IndexError
else:
if index < 0:
length = _ll_rangelen(l.start, l.stop, step)
index += length
return l.start + index * step
# ____________________________________________________________
#
# Irregular operations.
def rtype_builtin_range(hop):
vstep = hop.inputconst(Signed, 1)
if hop.nb_args == 1:
vstart = hop.inputconst(Signed, 0)
vstop, = hop.inputargs(Signed)
elif hop.nb_args == 2:
vstart, vstop = hop.inputargs(Signed, Signed)
else:
vstart, vstop, vstep = hop.inputargs(Signed, Signed, Signed)
if isinstance(vstep, Constant) and vstep.value == 0:
# not really needed, annotator catches it. Just in case...
raise TyperError("range cannot have a const step of zero")
if isinstance(hop.r_result, AbstractRangeRepr):
if hop.r_result.step != 0:
c_rng = hop.inputconst(Void, hop.r_result.RANGE)
hop.exception_is_here()
return hop.gendirectcall(hop.r_result.ll_newrange, c_rng, vstart, vstop)
else:
hop.exception_is_here()
return hop.gendirectcall(hop.r_result.ll_newrangest, vstart, vstop, vstep)
else:
# cannot build a RANGE object, needs a real list
r_list = hop.r_result
ITEMTYPE = r_list.lowleveltype
if isinstance(ITEMTYPE, Ptr):
ITEMTYPE = ITEMTYPE.TO
cLIST = hop.inputconst(Void, ITEMTYPE)
hop.exception_is_here()
return hop.gendirectcall(ll_range2list, cLIST, vstart, vstop, vstep)
rtype_builtin_xrange = rtype_builtin_range
def ll_range2list(LIST, start, stop, step):
if step == 0:
raise ValueError
length = _ll_rangelen(start, stop, step)
l = LIST.ll_newlist(length)
if LIST.ITEM is not Void:
idx = 0
while idx < length:
l.ll_setitem_fast(idx, start)
start += step
idx += 1
return l
# ____________________________________________________________
#
# Iteration.
class AbstractRangeIteratorRepr(IteratorRepr):
def __init__(self, r_rng):
self.r_rng = r_rng
if r_rng.step != 0:
self.lowleveltype = r_rng.RANGEITER
else:
self.lowleveltype = r_rng.RANGESTITER
def newiter(self, hop):
v_rng, = hop.inputargs(self.r_rng)
citerptr = hop.inputconst(Void, self.lowleveltype)
return hop.gendirectcall(self.ll_rangeiter, citerptr, v_rng)
def rtype_next(self, hop):
v_iter, = hop.inputargs(self)
args = hop.inputconst(Signed, self.r_rng.step),
if self.r_rng.step > 0:
llfn = ll_rangenext_up
elif self.r_rng.step < 0:
llfn = ll_rangenext_down
else:
llfn = ll_rangenext_updown
args = ()
hop.has_implicit_exception(StopIteration) # record that we know about it
hop.exception_is_here()
return hop.gendirectcall(llfn, v_iter, *args)
def ll_rangenext_up(iter, step):
next = iter.next
if next >= iter.stop:
raise StopIteration
iter.next = next + step
return next
def ll_rangenext_down(iter, step):
next = iter.next
if next <= iter.stop:
raise StopIteration
iter.next = next + step
return next
def ll_rangenext_updown(iter):
step = iter.step
if step > 0:
return ll_rangenext_up(iter, step)
else:
return ll_rangenext_down(iter, step)
# ____________________________________________________________
#
# Support for enumerate().
class EnumerateIteratorRepr(IteratorRepr):
def __init__(self, r_baseiter):
self.r_baseiter = r_baseiter
self.lowleveltype = r_baseiter.lowleveltype
# only supports for now enumerate() on sequence types whose iterators
# have a method ll_getnextindex. It could be added for most
# iterator types, but it's a bit messy for no clear benefit.
if not hasattr(r_baseiter, 'll_getnextindex'):
raise TyperError("not implemented for now: enumerate(x) where x "
"is not a regular list (got %r)" % (r_baseiter,))
self.ll_getnextindex = r_baseiter.ll_getnextindex
def rtype_next(self, hop):
v_enumerate, = hop.inputargs(self)
v_index = hop.gendirectcall(self.ll_getnextindex, v_enumerate)
hop2 = hop.copy()
hop2.args_r = [self.r_baseiter]
r_item_src = self.r_baseiter.external_item_repr
r_item_dst = hop.r_result.items_r[1]
v_item = self.r_baseiter.rtype_next(hop2)
v_item = hop.llops.convertvar(v_item, r_item_src, r_item_dst)
return hop.r_result.newtuple(hop.llops, hop.r_result,
[v_index, v_item])
def rtype_builtin_enumerate(hop):
hop.exception_cannot_occur()
return hop.r_result.r_baseiter.newiter(hop)