Source

pypy-postgresql / pypy / objspace / std / model.py

  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
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
"""
The full list of which Python types and which implementation we want
to provide in this version of PyPy, along with conversion rules.
"""

from pypy.objspace.std.multimethod import MultiMethodTable, FailedToImplement
from pypy.interpreter.baseobjspace import W_Root, ObjSpace
import pypy.interpreter.pycode
import pypy.interpreter.special

_registered_implementations = set()
def registerimplementation(implcls):
    """Hint to objspace.std.model to register the implementation class."""
    assert issubclass(implcls, W_Object)
    _registered_implementations.add(implcls)

option_to_typename = {
    "withspecialisedtuple" : ["specialisedtupleobject.W_SpecialisedTupleObject"],
    "withsmalltuple" : ["smalltupleobject.W_SmallTupleObject"],
    "withsmallint"   : ["smallintobject.W_SmallIntObject"],
    "withsmalllong"  : ["smalllongobject.W_SmallLongObject"],
    "withstrslice"   : ["strsliceobject.W_StringSliceObject"],
    "withstrjoin"    : ["strjoinobject.W_StringJoinObject"],
    "withstrbuf"     : ["strbufobject.W_StringBufferObject"],
    "withrope"       : ["ropeobject.W_RopeObject",
                        "ropeobject.W_RopeIterObject"],
    "withropeunicode": ["ropeunicodeobject.W_RopeUnicodeObject",
                        "ropeunicodeobject.W_RopeUnicodeIterObject"],
    "withtproxy" : ["proxyobject.W_TransparentList",
                    "proxyobject.W_TransparentDict"],
}

IDTAG_INT     = 1
IDTAG_LONG    = 3
IDTAG_FLOAT   = 5
IDTAG_COMPLEX = 7

class StdTypeModel:

    def __init__(self, config):
        """NOT_RPYTHON: inititialization only"""
        self.config = config
        # All the Python types that we want to provide in this StdObjSpace
        class result:
            from pypy.objspace.std.objecttype import object_typedef
            from pypy.objspace.std.booltype   import bool_typedef
            from pypy.objspace.std.inttype    import int_typedef
            from pypy.objspace.std.floattype  import float_typedef
            from pypy.objspace.std.complextype  import complex_typedef
            from pypy.objspace.std.settype import set_typedef
            from pypy.objspace.std.frozensettype import frozenset_typedef
            from pypy.objspace.std.tupletype  import tuple_typedef
            from pypy.objspace.std.listtype   import list_typedef
            from pypy.objspace.std.dicttype   import dict_typedef
            from pypy.objspace.std.basestringtype import basestring_typedef
            from pypy.objspace.std.stringtype import str_typedef
            from pypy.objspace.std.bytearraytype import bytearray_typedef
            from pypy.objspace.std.typetype   import type_typedef
            from pypy.objspace.std.slicetype  import slice_typedef
            from pypy.objspace.std.longtype   import long_typedef
            from pypy.objspace.std.unicodetype import unicode_typedef
            from pypy.objspace.std.nonetype import none_typedef
            from pypy.objspace.std.itertype import iter_typedef
        self.pythontypes = [value for key, value in result.__dict__.items()
                            if not key.startswith('_')]   # don't look

        # The object implementations that we want to 'link' into PyPy must be
        # imported here.  This registers them into the multimethod tables,
        # *before* the type objects are built from these multimethod tables.
        from pypy.objspace.std import objectobject
        from pypy.objspace.std import boolobject
        from pypy.objspace.std import intobject
        from pypy.objspace.std import floatobject
        from pypy.objspace.std import complexobject
        from pypy.objspace.std import setobject
        from pypy.objspace.std import tupleobject
        from pypy.objspace.std import listobject
        from pypy.objspace.std import dictmultiobject
        from pypy.objspace.std import stringobject
        from pypy.objspace.std import bytearrayobject
        from pypy.objspace.std import typeobject
        from pypy.objspace.std import sliceobject
        from pypy.objspace.std import longobject
        from pypy.objspace.std import noneobject
        from pypy.objspace.std import iterobject
        from pypy.objspace.std import unicodeobject
        from pypy.objspace.std import dictproxyobject
        from pypy.objspace.std import proxyobject
        from pypy.objspace.std import fake
        import pypy.objspace.std.default # register a few catch-all multimethods

        import pypy.objspace.std.marshal_impl # install marshal multimethods
        if config.objspace.usemodules.array:
            import pypy.module.array

        # the set of implementation types
        self.typeorder = {
            objectobject.W_ObjectObject: [],
            boolobject.W_BoolObject: [],
            intobject.W_IntObject: [],
            floatobject.W_FloatObject: [],
            tupleobject.W_TupleObject: [],
            listobject.W_ListObject: [],
            dictmultiobject.W_DictMultiObject: [],
            dictmultiobject.W_DictMultiIterObject: [],
            stringobject.W_StringObject: [],
            bytearrayobject.W_BytearrayObject: [],
            typeobject.W_TypeObject: [],
            sliceobject.W_SliceObject: [],
            longobject.W_LongObject: [],
            noneobject.W_NoneObject: [],
            complexobject.W_ComplexObject: [],
            setobject.W_BaseSetObject: [],
            setobject.W_SetObject: [],
            setobject.W_FrozensetObject: [],
            setobject.W_SetIterObject: [],
            iterobject.W_SeqIterObject: [],
            iterobject.W_FastListIterObject: [],
            iterobject.W_FastTupleIterObject: [],
            iterobject.W_ReverseSeqIterObject: [],
            unicodeobject.W_UnicodeObject: [],
            dictmultiobject.W_DictViewKeysObject: [],
            dictmultiobject.W_DictViewItemsObject: [],
            dictmultiobject.W_DictViewValuesObject: [],
            pypy.interpreter.pycode.PyCode: [],
            pypy.interpreter.special.Ellipsis: [],
            }

        self.imported_but_not_registered = {
            dictmultiobject.W_DictMultiObject: True, # XXXXXX
            dictmultiobject.W_DictMultiIterObject: True,
            listobject.W_ListObject: True,
            stringobject.W_StringObject: True,
            tupleobject.W_TupleObject: True,
        }
        for option, value in config.objspace.std:
            if option.startswith("with") and option in option_to_typename:
                for classname in option_to_typename[option]:
                    modname = classname[:classname.index('.')]
                    classname = classname[classname.index('.')+1:]
                    d = {}
                    exec "from pypy.objspace.std.%s import %s" % (
                        modname, classname) in d
                    implcls = d[classname]
                    if value:
                        self.typeorder[implcls] = []
                    else:
                        self.imported_but_not_registered[implcls] = True

        if config.objspace.std.withrope:
            del self.typeorder[stringobject.W_StringObject]

        # check if we missed implementations
        for implcls in _registered_implementations:
            if hasattr(implcls, 'register'):
                implcls.register(self.typeorder)
            assert (implcls in self.typeorder or
                    implcls in self.imported_but_not_registered), (
                "please add %r in StdTypeModel.typeorder" % (implcls,))


        for type in self.typeorder:
            self.typeorder[type].append((type, None))

        # register the order in which types are converted into each others
        # when trying to dispatch multimethods.
        # XXX build these lists a bit more automatically later

        if config.objspace.std.withsmallint:
            from pypy.objspace.std import smallintobject
            self.typeorder[boolobject.W_BoolObject] += [
                (smallintobject.W_SmallIntObject, boolobject.delegate_Bool2SmallInt),
                ]
            self.typeorder[smallintobject.W_SmallIntObject] += [
                (intobject.W_IntObject, smallintobject.delegate_SmallInt2Int),
                (floatobject.W_FloatObject, smallintobject.delegate_SmallInt2Float),
                (longobject.W_LongObject, smallintobject.delegate_SmallInt2Long),
                (complexobject.W_ComplexObject, smallintobject.delegate_SmallInt2Complex),
                ]

        self.typeorder[boolobject.W_BoolObject] += [
            (intobject.W_IntObject,     boolobject.delegate_Bool2IntObject),
            (floatobject.W_FloatObject, floatobject.delegate_Bool2Float),
            (longobject.W_LongObject,   longobject.delegate_Bool2Long),
            (complexobject.W_ComplexObject, complexobject.delegate_Bool2Complex),
            ]
        self.typeorder[intobject.W_IntObject] += [
            (floatobject.W_FloatObject, floatobject.delegate_Int2Float),
            (longobject.W_LongObject,   longobject.delegate_Int2Long),
            (complexobject.W_ComplexObject, complexobject.delegate_Int2Complex),
            ]
        if config.objspace.std.withsmalllong:
            from pypy.objspace.std import smalllongobject
            self.typeorder[boolobject.W_BoolObject] += [
                (smalllongobject.W_SmallLongObject, smalllongobject.delegate_Bool2SmallLong),
                ]
            self.typeorder[intobject.W_IntObject] += [
                (smalllongobject.W_SmallLongObject, smalllongobject.delegate_Int2SmallLong),
                ]
            self.typeorder[smalllongobject.W_SmallLongObject] += [
                (longobject.W_LongObject, smalllongobject.delegate_SmallLong2Long),
                (floatobject.W_FloatObject, smalllongobject.delegate_SmallLong2Float),
                (complexobject.W_ComplexObject, smalllongobject.delegate_SmallLong2Complex),
                ]
        self.typeorder[longobject.W_LongObject] += [
            (floatobject.W_FloatObject, floatobject.delegate_Long2Float),
            (complexobject.W_ComplexObject,
                    complexobject.delegate_Long2Complex),
            ]
        self.typeorder[floatobject.W_FloatObject] += [
            (complexobject.W_ComplexObject,
                    complexobject.delegate_Float2Complex),
            ]
        self.typeorder[setobject.W_SetObject] += [
            (setobject.W_BaseSetObject, None)
            ]
        self.typeorder[setobject.W_FrozensetObject] += [
            (setobject.W_BaseSetObject, None)
            ]
        if not config.objspace.std.withrope:
            self.typeorder[stringobject.W_StringObject] += [
             (unicodeobject.W_UnicodeObject, unicodeobject.delegate_String2Unicode),
                ]
        else:
            from pypy.objspace.std import ropeobject
            if config.objspace.std.withropeunicode:
                from pypy.objspace.std import ropeunicodeobject
                self.typeorder[ropeobject.W_RopeObject] += [
                 (ropeunicodeobject.W_RopeUnicodeObject,
                     ropeunicodeobject.delegate_Rope2RopeUnicode),
                 ]
            else:
                self.typeorder[ropeobject.W_RopeObject] += [
                 (unicodeobject.W_UnicodeObject, unicodeobject.delegate_String2Unicode),
                    ]
        if config.objspace.std.withstrslice:
            from pypy.objspace.std import strsliceobject
            self.typeorder[strsliceobject.W_StringSliceObject] += [
                (stringobject.W_StringObject,
                                       strsliceobject.delegate_slice2str),
                (unicodeobject.W_UnicodeObject,
                                       strsliceobject.delegate_slice2unicode),
                ]
        if config.objspace.std.withstrjoin:
            from pypy.objspace.std import strjoinobject
            self.typeorder[strjoinobject.W_StringJoinObject] += [
                (stringobject.W_StringObject,
                                       strjoinobject.delegate_join2str),
                (unicodeobject.W_UnicodeObject,
                                       strjoinobject.delegate_join2unicode)
                ]
        elif config.objspace.std.withstrbuf:
            from pypy.objspace.std import strbufobject
            self.typeorder[strbufobject.W_StringBufferObject] += [
                (stringobject.W_StringObject,
                                       strbufobject.delegate_buf2str),
                (unicodeobject.W_UnicodeObject,
                                       strbufobject.delegate_buf2unicode)
                ]
        if config.objspace.std.withsmalltuple:
            from pypy.objspace.std import smalltupleobject
            self.typeorder[smalltupleobject.W_SmallTupleObject] += [
                (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)]

        if config.objspace.std.withspecialisedtuple:
            from pypy.objspace.std import specialisedtupleobject
            self.typeorder[specialisedtupleobject.W_SpecialisedTupleObject] += [
                (tupleobject.W_TupleObject, specialisedtupleobject.delegate_SpecialisedTuple2Tuple)]

        # put W_Root everywhere
        self.typeorder[W_Root] = []
        for type in self.typeorder:
            from pypy.objspace.std import stdtypedef
            if type is not W_Root and isinstance(type.typedef, stdtypedef.StdTypeDef):
                self.typeorder[type].append((type.typedef.any, None))
            self.typeorder[type].append((W_Root, None))

        self._typeorder_with_empty_usersubcls = None

        # ____________________________________________________________
        # Prebuilt common integer values

        if config.objspace.std.withprebuiltint:
            intobject.W_IntObject.PREBUILT = []
            for i in range(config.objspace.std.prebuiltintfrom,
                           config.objspace.std.prebuiltintto):
                intobject.W_IntObject.PREBUILT.append(intobject.W_IntObject(i))
            del i
        else:
            intobject.W_IntObject.PREBUILT = None

        # ____________________________________________________________

    def get_typeorder_with_empty_usersubcls(self):
        if self._typeorder_with_empty_usersubcls is None:
            from pypy.interpreter.typedef import enum_interplevel_subclasses
            from pypy.objspace.std import stdtypedef
            result = self.typeorder.copy()
            for cls in self.typeorder:
                if (hasattr(cls, 'typedef') and cls.typedef is not None and
                    cls.typedef.acceptable_as_base_class):
                    subclslist = enum_interplevel_subclasses(self.config, cls)
                    for subcls in subclslist:
                        if cls in subcls.__bases__:   # only direct subclasses
                            # for user subclasses we only accept "generic"
                            # matches: "typedef.any" is the applevel-type-based
                            # matching, and "W_Root" is ANY.
                            matches = []
                            if isinstance(cls.typedef, stdtypedef.StdTypeDef):
                                matches.append((cls.typedef.any, None))
                            matches.append((W_Root, None))
                            result[subcls] = matches
            self._typeorder_with_empty_usersubcls = result
        return self._typeorder_with_empty_usersubcls

def _op_negated(function):
    def op(space, w_1, w_2):
        return space.not_(function(space, w_1, w_2))
    return op

def _op_swapped(function):
    def op(space, w_1, w_2):
        return function(space, w_2, w_1)
    return op

def _op_swapped_negated(function):
    def op(space, w_1, w_2):
        return space.not_(function(space, w_2, w_1))
    return op

OPERATORS = ['lt', 'le', 'eq', 'ne', 'gt', 'ge']
OP_CORRESPONDANCES = [
    ('eq', 'ne', _op_negated),
    ('lt', 'gt', _op_swapped),
    ('le', 'ge', _op_swapped),
    ('lt', 'ge', _op_negated),
    ('le', 'gt', _op_negated),
    ('lt', 'le', _op_swapped_negated),
    ('gt', 'ge', _op_swapped_negated),
    ]
for op1, op2, value in OP_CORRESPONDANCES[:]:
    i = OP_CORRESPONDANCES.index((op1, op2, value))
    OP_CORRESPONDANCES.insert(i+1, (op2, op1, value))

def add_extra_comparisons():
    """
    Add the missing comparison operators if they were not explicitly
    defined:  eq <-> ne  and  lt <-> le <-> gt <-> ge.
    We try to add them in the order defined by the OP_CORRESPONDANCES
    table, thus favouring swapping the arguments over negating the result.
    """
    originalentries = {}
    for op in OPERATORS:
        originalentries[op] = getattr(MM, op).signatures()

    for op1, op2, correspondance in OP_CORRESPONDANCES:
        mirrorfunc = getattr(MM, op2)
        for types in originalentries[op1]:
            t1, t2 = types
            if t1 is t2:
                if not mirrorfunc.has_signature(types):
                    functions = getattr(MM, op1).getfunctions(types)
                    assert len(functions) == 1, ('Automatic'
                            ' registration of comparison functions'
                            ' only work when there is a single method for'
                            ' the operation.')
                    mirrorfunc.register(correspondance(functions[0]), *types)


# ____________________________________________________________

W_ANY = W_Root

class W_Object(W_Root):
    "Parent base class for wrapped objects provided by the StdObjSpace."
    # Note that not all wrapped objects in the interpreter inherit from
    # W_Object.  (They inherit from W_Root.)
    __slots__ = ()

    def __repr__(self):
        name = getattr(self, 'name', '')
        if not isinstance(name, str):
            name = ''
        s = '%s(%s)' % (self.__class__.__name__, name)
        w_cls = getattr(self, 'w__class__', None)
        if w_cls is not None and w_cls is not self:
            s += ' instance of %s' % self.w__class__
        return '<%s>' % s

    def unwrap(w_self, space):
        raise UnwrapError, 'cannot unwrap %r' % (w_self,)

class UnwrapError(Exception):
    pass


class StdObjSpaceMultiMethod(MultiMethodTable):

    def __init__(self, operatorsymbol, arity, specialnames=None, **extras):
        """NOT_RPYTHON: cannot create new multimethods dynamically.
        """
        MultiMethodTable.__init__(self, arity, W_ANY,
                                  argnames_before = ['space'])
        self.operatorsymbol = operatorsymbol
        if specialnames is None:
            specialnames = [operatorsymbol]
        assert isinstance(specialnames, list)
        self.specialnames = specialnames  # e.g. ['__xxx__', '__rxxx__']
        self.extras = extras
        # transform  '+'  =>  'add'  etc.
        for line in ObjSpace.MethodTable:
            realname, symbolname = line[:2]
            if symbolname == operatorsymbol:
                self.name = realname
                break
        else:
            self.name = operatorsymbol

        if extras.get('general__args__', False):
            self.argnames_after = ['__args__']
        if extras.get('varargs_w', False):
            self.argnames_after = ['args_w']
        self.argnames_after += extras.get('extra_args', [])

    def install_not_sliced(self, typeorder, baked_perform_call=True):
        return self.install(prefix = '__mm_' + self.name,
                list_of_typeorders = [typeorder]*self.arity,
                baked_perform_call=baked_perform_call)

    def merge_with(self, other):
        # Make a new 'merged' multimethod including the union of the two
        # tables.  In case of conflict, pick the entry from 'self'.
        if self.arity != other.arity:
            return self      # XXX that's the case of '**'
        operatorsymbol = '%s_merge_%s' % (self.name, other.name)
        assert self.extras == other.extras
        mm = StdObjSpaceMultiMethod(operatorsymbol, self.arity, **self.extras)
        #
        def merge(node1, node2):
            assert type(node1) is type(node2)
            if isinstance(node1, dict):
                d = node1.copy()
                d.update(node2)
                for key in node1:
                    if key in node2:
                        d[key] = merge(node1[key], node2[key])
                return d
            else:
                assert isinstance(node1, list)
                assert node1
                return node1     # pick the entry from 'self'
        #
        mm.dispatch_tree = merge(self.dispatch_tree, other.dispatch_tree)
        return mm

NOT_MULTIMETHODS = dict.fromkeys(
    ['delattr', 'delete', 'get', 'id', 'inplace_div', 'inplace_floordiv',
     'inplace_lshift', 'inplace_mod', 'inplace_pow', 'inplace_rshift',
     'inplace_truediv', 'is_', 'set', 'setattr', 'type', 'userdel',
     'isinstance', 'issubtype'])
# XXX should we just remove those from the method table or we're happy
#     with just not having multimethods?

class MM:
    """StdObjSpace multimethods"""

    call    = StdObjSpaceMultiMethod('call', 1, ['__call__'],
                                     general__args__=True)
    init    = StdObjSpaceMultiMethod('__init__', 1, general__args__=True)
    getnewargs = StdObjSpaceMultiMethod('__getnewargs__', 1)
    # special visible multimethods
    float_w = StdObjSpaceMultiMethod('float_w', 1, [])   # returns an unwrapped float
    # NOTE: when adding more sometype_w() methods, you need to write a
    # stub in default.py to raise a space.w_TypeError
    marshal_w = StdObjSpaceMultiMethod('marshal_w', 1, [], extra_args=['marshaller'])

    # add all regular multimethods here
    for _name, _symbol, _arity, _specialnames in ObjSpace.MethodTable:
        if _name not in locals() or _name in NOT_MULTIMETHODS:
            mm = StdObjSpaceMultiMethod(_symbol, _arity, _specialnames)
            locals()[_name] = mm
            del mm

    pow.extras['defaults'] = (None,)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.