1
from pypy.annotation.pairtype import pairtype, extendabletype, pair
2
from pypy.annotation import model as annmodel
3
from pypy.annotation import description
4
from pypy.objspace.flow.model import Constant
5
from pypy.rpython.lltypesystem.lltype import \
6
Void, Bool, Float, Signed, Char, UniChar, \
7
typeOf, LowLevelType, Ptr, PyObject, isCompatibleType
8
from pypy.rpython.lltypesystem import lltype, llmemory
9
from pypy.rpython.ootypesystem import ootype
10
from pypy.rpython.error import TyperError, MissingRTypeOperation
12
# initialization states for Repr instances
22
""" An instance of Repr is associated with each instance of SomeXxx.
23
It defines the chosen representation for the SomeXxx. The Repr subclasses
24
generally follows the SomeXxx subclass hierarchy, but there are numerous
25
exceptions. For example, the annotator uses SomeIter for any iterator, but
26
we need different representations according to the type of container we are
29
__metaclass__ = extendabletype
30
_initialized = setupstate.NOTINITIALIZED
33
return '<%s %s>' % (self.__class__.__name__, self.lowleveltype)
35
def compact_repr(self):
36
return '%s %s' % (self.__class__.__name__.replace('Repr','R'), self.lowleveltype._short_name())
39
""" call _setup_repr() and keep track of the initializiation
40
status to e.g. detect recursive _setup_repr invocations.
41
the '_initialized' attr has four states:
43
if self._initialized == setupstate.FINISHED:
45
elif self._initialized == setupstate.BROKEN:
46
raise BrokenReprTyperError(
47
"cannot setup already failed Repr: %r" %(self,))
48
elif self._initialized == setupstate.INPROGRESS:
50
"recursive invocation of Repr setup(): %r" %(self,))
51
elif self._initialized == setupstate.DELAYED:
53
"Repr setup() is delayed and cannot be called yet: %r" %(self,))
54
assert self._initialized == setupstate.NOTINITIALIZED
55
self._initialized = setupstate.INPROGRESS
59
self._initialized = setupstate.BROKEN
62
self._initialized = setupstate.FINISHED
64
def _setup_repr(self):
65
"For recursive data structure, which must be initialized in two steps."
67
def setup_final(self):
68
"""Same as setup(), called a bit later, for effects that are only
69
needed after the typer finished (as opposed to needed for other parts
70
of the typer itself)."""
71
if self._initialized == setupstate.BROKEN:
72
raise BrokenReprTyperError("cannot perform setup_final_touch "
73
"on failed Repr: %r" %(self,))
74
assert self._initialized == setupstate.FINISHED, (
75
"setup_final() on repr with state %s: %r" %
76
(self._initialized, self))
77
self._setup_repr_final()
79
def _setup_repr_final(self):
82
def is_setup_delayed(self):
83
return self._initialized == setupstate.DELAYED
85
def set_setup_delayed(self, flag):
86
assert self._initialized in (setupstate.NOTINITIALIZED,
89
self._initialized = setupstate.DELAYED
91
self._initialized = setupstate.NOTINITIALIZED
93
def set_setup_maybe_delayed(self):
94
if self._initialized == setupstate.NOTINITIALIZED:
95
self._initialized = setupstate.DELAYED
96
return self._initialized == setupstate.DELAYED
98
def __getattr__(self, name):
99
# Assume that when an attribute is missing, it's because setup() needs
101
if not (name[:2] == '__' == name[-2:]):
102
if self._initialized == setupstate.NOTINITIALIZED:
105
return self.__dict__[name]
108
raise AttributeError("%s instance has no attribute %s" % (
109
self.__class__.__name__, name))
114
def convert_desc_or_const(self, desc_or_const):
115
if isinstance(desc_or_const, description.Desc):
116
return self.convert_desc(desc_or_const)
117
elif isinstance(desc_or_const, Constant):
118
return self.convert_const(desc_or_const.value)
120
raise TyperError("convert_desc_or_const expects a Desc"
121
"or Constant: %r" % desc_or_const)
123
def convert_const(self, value):
124
"Convert the given constant value to the low-level repr of 'self'."
125
if self.lowleveltype is not Void:
127
realtype = typeOf(value)
128
except (AssertionError, AttributeError, TypeError):
130
if realtype != self.lowleveltype:
131
raise TyperError("convert_const(self = %r, value = %r)" % (
135
def get_ll_eq_function(self):
136
"""Return an eq(x,y) function to use to compare two low-level
138
This can return None to mean that simply using '==' is fine.
140
raise TyperError, 'no equality function for %r' % self
142
def get_ll_hash_function(self):
143
"""Return a hash(x) function for low-level values of this Repr.
145
raise TyperError, 'no hashing function for %r' % self
147
def get_ll_fasthash_function(self):
148
"""Return a 'fast' hash(x) function for low-level values of this
149
Repr. The function can assume that 'x' is already stored as a
150
key in a dict. get_ll_fasthash_function() should return None if
151
the hash should rather be cached in the dict entry.
155
def can_ll_be_null(self, s_value):
156
"""Check if the low-level repr can take the value 0/NULL.
157
The annotation s_value is provided as a hint because it may
158
contain more information than the Repr.
160
return True # conservative
162
def get_ll_dummyval_obj(self, rtyper, s_value):
163
"""A dummy value is a special low-level value, not otherwise
164
used. It should not be the NULL value even if it is special.
165
This returns either None, or a hashable object that has a
166
(possibly lazy) attribute 'll_dummy_value'.
167
The annotation s_value is provided as a hint because it may
168
contain more information than the Repr.
170
T = self.lowleveltype
171
if (isinstance(T, lltype.Ptr) and
172
isinstance(T.TO, (lltype.Struct,
174
lltype.ForwardReference)) and
175
T.TO._gckind != 'cpy'):
176
return DummyValueBuilder(rtyper, T.TO)
180
def rtype_bltn_list(self, hop):
181
raise TyperError, 'no list() support for %r' % self
183
def rtype_unichr(self, hop):
184
raise TyperError, 'no unichr() support for %r' % self
186
# default implementation of some operations
188
def rtype_getattr(self, hop):
189
s_attr = hop.args_s[1]
190
if s_attr.is_constant() and isinstance(s_attr.const, str):
192
s_obj = hop.args_s[0]
193
if s_obj.find_method(attr) is None:
194
raise TyperError("no method %s on %r" % (attr, s_obj))
196
# implement methods (of a known name) as just their 'self'
197
return hop.inputarg(self, arg=0)
199
raise TyperError("getattr() with a non-constant attribute name")
201
def rtype_str(self, hop):
202
[v_self] = hop.inputargs(self)
203
return hop.gendirectcall(self.ll_str, v_self)
205
def rtype_nonzero(self, hop):
206
return self.rtype_is_true(hop) # can call a subclass' rtype_is_true()
208
def rtype_is_true(self, hop):
210
vlen = self.rtype_len(hop)
211
except MissingRTypeOperation:
212
if not hop.s_result.is_constant():
213
raise TyperError("rtype_is_true(%r) not implemented" % (self,))
214
return hop.inputconst(Bool, hop.s_result.const)
216
return hop.genop('int_is_true', [vlen], resulttype=Bool)
218
def rtype_id(self, hop):
219
if not isinstance(self.lowleveltype, Ptr):
220
raise TyperError('id() of an instance of the non-pointer %r' % (
222
vobj, = hop.inputargs(self)
223
# XXX why did this go through weakadr??
224
#v_waddr = hop.genop('cast_ptr_to_weakadr', [vobj],
225
# resulttype=llmemory.WeakGcAddress)
226
#return hop.genop('cast_weakadr_to_int', [v_waddr], resulttype=Signed)
228
return hop.genop('cast_ptr_to_int', [vobj], resulttype=Signed)
230
def rtype_hash(self, hop):
231
ll_hash = self.get_ll_hash_function()
232
v, = hop.inputargs(self)
233
return hop.gendirectcall(ll_hash, v)
235
def rtype_iter(self, hop):
236
r_iter = self.make_iterator_repr()
237
return r_iter.newiter(hop)
239
def make_iterator_repr(self, *variant):
240
raise TyperError("%s is not iterable" % (self,))
242
def rtype_hint(self, hop):
243
return hop.inputarg(hop.r_result, arg=0)
247
def get_r_implfunc(self):
248
raise TyperError("%s has no corresponding implementation function representation" % (self,))
250
def get_s_callable(self):
251
raise TyperError("%s is not callable or cannot reconstruct a pbc annotation for itself" % (self,))
257
class CanBeNull(object):
258
"""A mix-in base class for subclasses of Repr that represent None as
259
'null' and true values as non-'null'.
261
def rtype_is_true(self, hop):
262
if hop.s_result.is_constant():
263
return hop.inputconst(Bool, hop.s_result.const)
265
return hop.rtyper.type_system.check_null(self, hop)
268
class IteratorRepr(Repr):
269
"""Base class of Reprs of any kind of iterator."""
271
def rtype_iter(self, hop): # iter(iter(x)) <==> iter(x)
272
v_iter, = hop.inputargs(self)
275
def rtype_method_next(self, hop):
276
return self.rtype_next(hop)
279
class __extend__(annmodel.SomeIterator):
280
# NOTE: SomeIterator is for iterators over any container, not just list
281
def rtyper_makerepr(self, rtyper):
282
r_container = rtyper.getrepr(self.s_container)
283
return r_container.make_iterator_repr(*self.variant)
284
def rtyper_makekey_ex(self, rtyper):
285
return self.__class__, rtyper.makekey(self.s_container), self.variant
287
class __extend__(annmodel.SomeImpossibleValue):
288
def rtyper_makerepr(self, rtyper):
289
return impossible_repr
290
def rtyper_makekey(self):
291
return self.__class__,
293
# ____ generic binary operations _____________________________
296
class __extend__(pairtype(Repr, Repr)):
298
def rtype_is_((robj1, robj2), hop):
299
if hop.s_result.is_constant():
300
return inputconst(Bool, hop.s_result.const)
301
return hop.rtyper.type_system.generic_is(robj1, robj2, hop)
303
# default implementation for checked getitems
305
def rtype_getitem_idx_key((r_c1, r_o1), hop):
306
return pair(r_c1, r_o1).rtype_getitem(hop)
308
rtype_getitem_idx = rtype_getitem_idx_key
309
rtype_getitem_key = rtype_getitem_idx_key
311
# ____________________________________________________________
314
def make_missing_op(rcls, opname):
315
attr = 'rtype_' + opname
316
if not hasattr(rcls, attr):
317
def missing_rtype_operation(self, hop):
318
raise MissingRTypeOperation("unimplemented operation: "
319
"'%s' on %r" % (opname, self))
320
setattr(rcls, attr, missing_rtype_operation)
322
for opname in annmodel.UNARY_OPERATIONS:
323
make_missing_op(Repr, opname)
325
for opname in annmodel.BINARY_OPERATIONS:
326
make_missing_op(pairtype(Repr, Repr), opname)
328
# not in BINARY_OPERATIONS
329
make_missing_op(pairtype(Repr, Repr), 'contains')
331
class __extend__(pairtype(Repr, Repr)):
332
def convert_from_to((r_from, r_to), v, llops):
333
return NotImplemented
335
# ____________________________________________________________
336
# Primitive Repr classes, in the same hierarchical order as
337
# the corresponding SomeObjects
339
class FloatRepr(Repr):
342
class IntegerRepr(FloatRepr):
343
def __init__(self, lowleveltype, opprefix):
344
self.lowleveltype = lowleveltype
345
self._opprefix = opprefix
348
def _get_opprefix(self):
349
if self._opprefix is None:
350
raise TyperError("arithmetic not supported on %r" %
352
return self._opprefix
354
opprefix =property(_get_opprefix)
356
class BoolRepr(IntegerRepr):
358
# NB. no 'opprefix' here. Use 'as_int' systematically.
360
from pypy.rpython.rint import signed_repr
361
self.as_int = signed_repr
363
class VoidRepr(Repr):
365
def get_ll_eq_function(self): return None
366
def get_ll_hash_function(self): return ll_hash_void
367
get_ll_fasthash_function = get_ll_hash_function
368
def ll_str(self, nothing): raise AssertionError("unreachable code")
369
impossible_repr = VoidRepr()
371
class SimplePointerRepr(Repr):
372
"Convenience Repr for simple ll pointer types with no operation on them."
374
def __init__(self, lowleveltype):
375
self.lowleveltype = lowleveltype
377
def convert_const(self, value):
378
if value is not None:
379
raise TyperError("%r only supports None as prebuilt constant, "
380
"got %r" % (self, value))
381
return lltype.nullptr(self.lowleveltype.TO)
383
# ____________________________________________________________
385
def inputdesc(reqtype, desc):
386
"""Return a Constant for the given desc, of the requested type,
387
which can only be a Repr.
389
assert isinstance(reqtype, Repr)
390
value = reqtype.convert_desc(desc)
391
lltype = reqtype.lowleveltype
393
c.concretetype = lltype
396
def inputconst(reqtype, value):
397
"""Return a Constant with the given value, of the requested type,
398
which can be a Repr instance or a low-level type.
400
if isinstance(reqtype, Repr):
401
value = reqtype.convert_const(value)
402
lltype = reqtype.lowleveltype
403
elif isinstance(reqtype, LowLevelType):
406
raise TypeError(repr(reqtype))
407
# Void Constants can hold any value;
408
# non-Void Constants must hold a correctly ll-typed value
409
if lltype is not Void:
411
realtype = typeOf(value)
412
except (AssertionError, AttributeError):
414
if not isCompatibleType(realtype, lltype):
415
raise TyperError("inputconst(reqtype = %s, value = %s):\n"
417
" got a %r" % (reqtype, value,
420
c.concretetype = lltype
423
class BrokenReprTyperError(TyperError):
424
""" raised when trying to setup a Repr whose setup
428
def mangle(prefix, name):
429
"""Make a unique identifier from the prefix and the name. The name
430
is allowed to start with $."""
431
if name.startswith('$'):
432
return '%sinternal_%s' % (prefix, name[1:])
434
return '%s_%s' % (prefix, name)
436
class HalfConcreteWrapper:
437
# see rtyper.gendirectcall()
438
def __init__(self, callback):
439
self.concretize = callback # should produce a concrete const
443
# __________ utilities __________
444
PyObjPtr = Ptr(PyObject)
446
def getgcflavor(classdef):
447
for parentdef in classdef.getmro():
448
if hasattr(parentdef, '_cpy_exported_type_'):
450
classdesc = classdef.classdesc
451
alloc_flavor = classdesc.read_attribute('_alloc_flavor_',
452
Constant('gc')).value
455
def externalvsinternal(rtyper, item_repr): # -> external_item_repr, (internal_)item_repr
456
from pypy.rpython import rclass
457
if (isinstance(item_repr, rclass.AbstractInstanceRepr) and
458
getattr(item_repr, 'gcflavor', 'gc') == 'gc'):
459
return item_repr, rclass.getinstancerepr(rtyper, None)
461
return item_repr, item_repr
464
class DummyValueBuilder(object):
466
def __init__(self, rtyper, TYPE):
474
return hash(self.TYPE)
476
def __eq__(self, other):
477
return (isinstance(other, DummyValueBuilder) and
478
self.rtyper is other.rtyper and
479
self.TYPE == other.TYPE)
481
def __ne__(self, other):
482
return not (self == other)
484
def build_ll_dummy_value(self):
487
return self.rtyper.cache_dummy_values[TYPE]
489
# generate a dummy ptr to an immortal placeholder struct/array
490
if TYPE._is_varsize():
491
p = lltype.malloc(TYPE, 0, immortal=True)
493
p = lltype.malloc(TYPE, immortal=True)
494
self.rtyper.cache_dummy_values[TYPE] = p
497
ll_dummy_value = property(build_ll_dummy_value)
503
from pypy.tool.ansi_print import ansi_log
505
log = py.log.Producer("rtyper")
506
py.log.setconsumer("rtyper", ansi_log)
507
py.log.setconsumer("rtyper translating", None)
508
py.log.setconsumer("rtyper debug", None)