Source

pypy / pypy / objspace / std / model.py

Samuele Pedroni ca4b87c 






Christian Tismer 83c5568 

Samuele Pedroni ca4b87c 
Benjamin Peterso… 7e2f9bc 





Carl Friedrich B… d81e3f3 
Mark Pearse a467cb7 
Lukas Diekmann c65a0b6 
Carl Friedrich B… d81e3f3 
Armin Rigo 0be8d85 
Antonio Cuni 1728bcd 
Samuele Pedroni d6fad3d 

Carl Friedrich B… d81e3f3 
Stephan Diehl 2fcdf17 
Christian Tismer d818531 




Samuele Pedroni ca4b87c 

Carl Friedrich B… d81e3f3 
Samuele Pedroni ab94a6a 
Carl Friedrich B… ac2c83a 
Samuele Pedroni ca4b87c 





Stephan Diehl 0efc85f 
Stephan Diehl 500bc82 

Samuele Pedroni ca4b87c 




Amaury Forgeot d… b45228f 
Samuele Pedroni ca4b87c 



Samuele Pedroni 5c4a706 

Samuele Pedroni ca4b87c 









Stephan Diehl 0efc85f 
Stephan Diehl 500bc82 
Samuele Pedroni ca4b87c 

Michael Hudson-D… 269e333 
Samuele Pedroni ca4b87c 
Amaury Forgeot d… b45228f 
Samuele Pedroni ca4b87c 





Armin Rigo 7e6ef91 
Samuele Pedroni d6fad3d 
Samuele Pedroni ca4b87c 
Samuele Pedroni 6137ccb 

Jason Creighton 74ec425 

Samuele Pedroni ca4b87c 








Carl Friedrich B… 5deba59 
Maciej Fijalkows… b085853 


Samuele Pedroni ca4b87c 
Amaury Forgeot d… b45228f 
Samuele Pedroni ca4b87c 



Carl Friedrich B… b232c42 
Carl Friedrich B… 3663cca 
Carl Friedrich B… b232c42 


Samuele Pedroni ca4b87c 
Maciej Fijalkows… b5a2e0b 

Anders Lehmann 98a1e8b 
Samuele Pedroni ca4b87c 
Amaury Forgeot d… 3974ad2 


Christian Tismer 83c5568 

Samuele Pedroni ca4b87c 
Carl Friedrich B… d81e3f3 
Carl Friedrich B… 4ffbfaf 
Carl Friedrich B… 5deba59 
Maciej Fijalkows… b085853 


Carl Friedrich B… c443a98 
Carl Friedrich B… 4ffbfaf 
Maciej Fijalkows… b5a2e0b 
Carl Friedrich B… d81e3f3 



Armin Rigo 3c33282 





Carl Friedrich B… d81e3f3 


Carl Friedrich B… 4ffbfaf 
Carl Friedrich B… d81e3f3 
Benjamin Peterso… 7e2f9bc 
Carl Friedrich B… d81e3f3 
Bartosz Skowron d45def5 

Carl Friedrich B… d81e3f3 
Carl Friedrich B… 4ffbfaf 
Carl Friedrich B… d81e3f3 


Carl Friedrich B… 3c17a8f 

Carl Friedrich B… 01d9d9e 
Samuele Pedroni ca4b87c 


Benjamin Peterso… 7e2f9bc 
Carl Friedrich B… d81e3f3 
Armin Rigo 3c33282 
Armin Rigo fe6b9a4 




Armin Rigo fb4db3b 
Armin Rigo fe6b9a4 



Maciej Fijalkows… 80f65c2 



Samuele Pedroni ca4b87c 
Armin Rigo fe6b9a4 
Armin Rigo fb4db3b 
Samuele Pedroni ca4b87c 
Stephan Diehl 0efc85f 
Samuele Pedroni ca4b87c 

Armin Rigo fb4db3b 
Samuele Pedroni ca4b87c 
Stephan Diehl 0efc85f 
Samuele Pedroni ca4b87c 
Armin Rigo 0be8d85 
Armin Rigo 3c33282 
Armin Rigo 0be8d85 






Armin Rigo b0d7d2f 
Armin Rigo 0be8d85 


Samuele Pedroni ca4b87c 
Christian Tismer 8a24463 
Benjamin Peterso… 7e2f9bc 
Stephan Diehl 0efc85f 
Stephan Diehl 5289696 

Benjamin Peterso… 7e2f9bc 
Stephan Diehl 0efc85f 
Samuele Pedroni ca4b87c 
Carl Friedrich B… 3663cca 





Alex Gaynor 73f1193 


Alex Gaynor ae4392b 
Armin Rigo 3c33282 
Antonio Cuni 1728bcd 





Lukas Diekmann c65a0b6 
Armin Rigo 3c33282 
Lukas Diekmann c65a0b6 

Armin Rigo be1560a 
Mark Pearse a467cb7 
Armin Rigo 4f1c5b7 
Mark Pearse a467cb7 


Samuele Pedroni ca4b87c 


Samuele Pedroni d6fad3d 


Samuele Pedroni ca4b87c 

Maciej Fijalkows… b5a2e0b 

Carl Friedrich B… d81e3f3 













Maciej Fijalkows… b5a2e0b 





Carl Friedrich B… 3663cca 
Maciej Fijalkows… b5a2e0b 
Carl Friedrich B… ac2c83a 
Maciej Fijalkows… b5a2e0b 











Samuele Pedroni ca4b87c 
Benjamin Peterso… 7e2f9bc 





















































Samuele Pedroni ca4b87c 



Armin Rigo fca0236 



Armin Rigo 5ef4529 
Samuele Pedroni ca4b87c 

Armin Rigo 96124ba 



Samuele Pedroni d5dfe29 

Samuele Pedroni ca4b87c 


Armin Rigo fca0236 
Samuele Pedroni ca4b87c 





Carl Friedrich B… 8cbab1d 
Samuele Pedroni ca4b87c 








Armin Rigo deb2e22 
Samuele Pedroni ca4b87c 









Benjamin Peterso… 7e2f9bc 
Samuele Pedroni ca4b87c 


Benjamin Peterso… 7e2f9bc 
Samuele Pedroni edf77e6 
Samuele Pedroni ca4b87c 




Armin Rigo 75d7c16 

























Benjamin Peterso… 7e2f9bc 
Maciej Fijalkows… 801bde9 


Maciej Fijalkows… b03531b 

Maciej Fijalkows… 801bde9 

Benjamin Peterso… 7e2f9bc 















Maciej Fijalkows… 514091a 
Benjamin Peterso… 7e2f9bc 




Maciej Fijalkows… 514091a 
  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
"""
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"],
    "withstrbuf"     : ["strbufobject.W_StringBufferObject"],
    "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
        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_DictMultiIterKeysObject: [],
            dictmultiobject.W_DictMultiIterValuesObject: [],
            dictmultiobject.W_DictMultiIterItemsObject: [],
            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_DictMultiIterKeysObject: True,
            dictmultiobject.W_DictMultiIterValuesObject: True,
            dictmultiobject.W_DictMultiIterItemsObject: 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

        # 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),
                ]

        if config.objspace.usemodules.micronumpy:
            from pypy.module.micronumpy.stdobjspace import register_delegates
            register_delegates(self.typeorder)

        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)
            ]
        self.typeorder[stringobject.W_StringObject] += [
            (unicodeobject.W_UnicodeObject, unicodeobject.delegate_String2Unicode),
            ]
        if 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,)