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 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
|
"""
Built-in functions.
"""
import sys
from collections import OrderedDict, defaultdict
from rpython.annotator.model import (
SomeInteger, SomeChar, SomeBool, SomeString, SomeTuple,
SomeUnicodeCodePoint, SomeFloat, union, SomeUnicodeString,
SomePBC, SomeInstance, SomeDict, SomeList, SomeWeakRef, SomeIterator,
SomeOrderedDict, SomeByteArray, add_knowntypedata, s_ImpossibleValue,)
from rpython.annotator.bookkeeper import (
getbookkeeper, immutablevalue, BUILTIN_ANALYZERS, analyzer_for)
from rpython.annotator import description
from rpython.annotator.classdesc import ClassDef
from rpython.flowspace.model import Constant
import rpython.rlib.rarithmetic
import rpython.rlib.objectmodel
from rpython.annotator.model import AnnotatorError
def constpropagate(func, args_s, s_result):
"""Returns s_result unless all args are constants, in which case the
func() is called and a constant result is returned (it must be contained
in s_result).
"""
args = []
for s in args_s:
if not s.is_immutable_constant():
return s_result
args.append(s.const)
try:
realresult = func(*args)
except (ValueError, OverflowError):
# no possible answer for this precise input. Be conservative
# and keep the computation non-constant. Example:
# unichr(constant-that-doesn't-fit-16-bits) on platforms where
# the underlying Python has sys.maxunicode == 0xffff.
return s_result
s_realresult = immutablevalue(realresult)
if not s_result.contains(s_realresult):
raise AnnotatorError(
"%s%r returned %r, which is not contained in %s" % (
func, args, realresult, s_result))
return s_realresult
# ____________________________________________________________
def builtin_range(*args):
s_step = immutablevalue(1)
if len(args) == 1:
s_start = immutablevalue(0)
s_stop = args[0]
elif len(args) == 2:
s_start, s_stop = args
elif len(args) == 3:
s_start, s_stop = args[:2]
s_step = args[2]
else:
raise AnnotatorError("range() takes 1 to 3 arguments")
empty = False # so far
if not s_step.is_constant():
step = 0 # this case signals a variable step
else:
step = s_step.const
if step == 0:
raise AnnotatorError("range() with step zero")
if s_start.is_constant() and s_stop.is_constant():
try:
if len(xrange(s_start.const, s_stop.const, step)) == 0:
empty = True
except TypeError: # if one of the .const is a Symbolic
pass
if empty:
s_item = s_ImpossibleValue
else:
nonneg = False # so far
if step > 0 or s_step.nonneg:
nonneg = s_start.nonneg
elif step < 0:
nonneg = s_stop.nonneg or (s_stop.is_constant() and
s_stop.const >= -1)
s_item = SomeInteger(nonneg=nonneg)
return getbookkeeper().newlist(s_item, range_step=step)
builtin_xrange = builtin_range # xxx for now allow it
def builtin_enumerate(s_obj):
return SomeIterator(s_obj, "enumerate")
def builtin_reversed(s_obj):
return SomeIterator(s_obj, "reversed")
def builtin_bool(s_obj):
return s_obj.bool()
def builtin_int(s_obj, s_base=None):
if isinstance(s_obj, SomeInteger):
assert not s_obj.unsigned, "instead of int(r_uint(x)), use intmask(r_uint(x))"
assert (s_base is None or isinstance(s_base, SomeInteger)
and s_obj.knowntype == str), "only int(v|string) or int(string,int) expected"
if s_base is not None:
args_s = [s_obj, s_base]
else:
args_s = [s_obj]
nonneg = isinstance(s_obj, SomeInteger) and s_obj.nonneg
return constpropagate(int, args_s, SomeInteger(nonneg=nonneg))
def builtin_float(s_obj):
return constpropagate(float, [s_obj], SomeFloat())
def builtin_chr(s_int):
return constpropagate(chr, [s_int], SomeChar())
def builtin_unichr(s_int):
return constpropagate(unichr, [s_int], SomeUnicodeCodePoint())
def builtin_unicode(s_unicode):
return constpropagate(unicode, [s_unicode], SomeUnicodeString())
def builtin_bytearray(s_str):
return SomeByteArray()
# note that this one either needs to be constant, or we will create SomeObject
def builtin_hasattr(s_obj, s_attr):
if not s_attr.is_constant() or not isinstance(s_attr.const, str):
getbookkeeper().warning('hasattr(%r, %r) is not RPythonic enough' %
(s_obj, s_attr))
r = SomeBool()
if s_obj.is_immutable_constant():
r.const = hasattr(s_obj.const, s_attr.const)
elif (isinstance(s_obj, SomePBC)
and s_obj.getKind() is description.FrozenDesc):
answers = {}
for d in s_obj.descriptions:
answer = (d.s_read_attribute(s_attr.const) != s_ImpossibleValue)
answers[answer] = True
if len(answers) == 1:
r.const, = answers
return r
def builtin_tuple(s_iterable):
if isinstance(s_iterable, SomeTuple):
return s_iterable
raise AnnotatorError("tuple(): argument must be another tuple")
def builtin_list(s_iterable):
bk = getbookkeeper()
if isinstance(s_iterable, SomeList):
return s_iterable.listdef.offspring(bk)
s_iter = s_iterable.iter()
return bk.newlist(s_iter.next())
def builtin_zip(s_iterable1, s_iterable2): # xxx not actually implemented
s_iter1 = s_iterable1.iter()
s_iter2 = s_iterable2.iter()
s_tup = SomeTuple((s_iter1.next(),s_iter2.next()))
return getbookkeeper().newlist(s_tup)
def builtin_min(*s_values):
if len(s_values) == 1: # xxx do we support this?
s_iter = s_values[0].iter()
return s_iter.next()
else:
return union(*s_values)
def builtin_max(*s_values):
if len(s_values) == 1: # xxx do we support this?
s_iter = s_values[0].iter()
return s_iter.next()
else:
s = union(*s_values)
if type(s) is SomeInteger and not s.nonneg:
nonneg = False
for s1 in s_values:
nonneg |= s1.nonneg
if nonneg:
s = SomeInteger(nonneg=True, knowntype=s.knowntype)
return s
# collect all functions
import __builtin__
for name, value in globals().items():
if name.startswith('builtin_'):
original = getattr(__builtin__, name[8:])
BUILTIN_ANALYZERS[original] = value
@analyzer_for(getattr(object.__init__, 'im_func', object.__init__))
def object_init(s_self, *args):
# ignore - mostly used for abstract classes initialization
pass
@analyzer_for(getattr(EnvironmentError.__init__, 'im_func', EnvironmentError.__init__))
def EnvironmentError_init(s_self, *args):
pass
try:
WindowsError
except NameError:
pass
else:
@analyzer_for(getattr(WindowsError.__init__, 'im_func', WindowsError.__init__))
def WindowsError_init(s_self, *args):
pass
@analyzer_for(sys.getdefaultencoding)
def conf():
return SomeString()
@analyzer_for(rpython.rlib.rarithmetic.intmask)
def rarith_intmask(s_obj):
return SomeInteger()
@analyzer_for(rpython.rlib.rarithmetic.longlongmask)
def rarith_longlongmask(s_obj):
return SomeInteger(knowntype=rpython.rlib.rarithmetic.r_longlong)
@analyzer_for(rpython.rlib.objectmodel.instantiate)
def robjmodel_instantiate(s_clspbc, s_nonmovable=None):
assert isinstance(s_clspbc, SomePBC)
clsdef = None
more_than_one = len(s_clspbc.descriptions) > 1
for desc in s_clspbc.descriptions:
cdef = desc.getuniqueclassdef()
if more_than_one:
getbookkeeper().needs_generic_instantiate[cdef] = True
if not clsdef:
clsdef = cdef
else:
clsdef = clsdef.commonbase(cdef)
return SomeInstance(clsdef)
@analyzer_for(rpython.rlib.objectmodel.r_dict)
def robjmodel_r_dict(s_eqfn, s_hashfn, s_force_non_null=None, s_simple_hash_eq=None):
return _r_dict_helper(SomeDict, s_eqfn, s_hashfn, s_force_non_null, s_simple_hash_eq)
@analyzer_for(rpython.rlib.objectmodel.r_ordereddict)
def robjmodel_r_ordereddict(s_eqfn, s_hashfn, s_force_non_null=None, s_simple_hash_eq=None):
return _r_dict_helper(SomeOrderedDict, s_eqfn, s_hashfn,
s_force_non_null, s_simple_hash_eq)
def _r_dict_helper(cls, s_eqfn, s_hashfn, s_force_non_null, s_simple_hash_eq):
if s_force_non_null is None:
force_non_null = False
else:
assert s_force_non_null.is_constant()
force_non_null = s_force_non_null.const
if s_simple_hash_eq is None:
simple_hash_eq = False
else:
assert s_simple_hash_eq.is_constant()
simple_hash_eq = s_simple_hash_eq.const
dictdef = getbookkeeper().getdictdef(is_r_dict=True,
force_non_null=force_non_null,
simple_hash_eq=simple_hash_eq)
dictdef.dictkey.update_rdict_annotations(s_eqfn, s_hashfn)
return cls(dictdef)
@analyzer_for(rpython.rlib.objectmodel.hlinvoke)
def robjmodel_hlinvoke(s_repr, s_llcallable, *args_s):
from rpython.rtyper.llannotation import lltype_to_annotation
from rpython.rtyper import rmodel
from rpython.rtyper.error import TyperError
assert s_repr.is_constant() and isinstance(s_repr.const, rmodel.Repr), "hlinvoke expects a constant repr as first argument"
r_func, nimplicitarg = s_repr.const.get_r_implfunc()
nbargs = len(args_s) + nimplicitarg
s_sigs = r_func.get_s_signatures((nbargs, (), False))
if len(s_sigs) != 1:
raise TyperError("cannot hlinvoke callable %r with not uniform"
"annotations: %r" % (s_repr.const,
s_sigs))
_, s_ret = s_sigs[0]
rresult = r_func.rtyper.getrepr(s_ret)
return lltype_to_annotation(rresult.lowleveltype)
@analyzer_for(rpython.rlib.objectmodel.keepalive_until_here)
def robjmodel_keepalive_until_here(*args_s):
return immutablevalue(None)
try:
import unicodedata
except ImportError:
pass
else:
@analyzer_for(unicodedata.decimal)
def unicodedata_decimal(s_uchr):
raise AnnotatorError(
"unicodedate.decimal() calls should not happen at interp-level")
@analyzer_for(OrderedDict)
def analyze():
return SomeOrderedDict(getbookkeeper().getdictdef())
#________________________________
# weakrefs
import weakref
@analyzer_for(weakref.ref)
def weakref_ref(s_obj):
if not isinstance(s_obj, SomeInstance):
raise AnnotatorError("cannot take a weakref to %r" % (s_obj,))
if s_obj.can_be_None:
raise AnnotatorError("should assert that the instance we take "
"a weakref to cannot be None")
return SomeWeakRef(s_obj.classdef)
#________________________________
# non-gc objects
@analyzer_for(rpython.rlib.objectmodel.free_non_gc_object)
def robjmodel_free_non_gc_object(obj):
pass
#________________________________
# pdb
import pdb
@analyzer_for(pdb.set_trace)
def pdb_set_trace(*args_s):
raise AnnotatorError(
"you left pdb.set_trace() in your interpreter! "
"If you want to attach a gdb instead, call rlib.debug.attach_gdb()")
|