descriptor support for __get__ and __set__

Descriptor support for `__get__` and `__set__` in the `getattr`, `getclsattr`, and `callattr` paths.

- The `getattr` path follows the protocol described at https://docs.python.org/2/howto/descriptor.html. There are two cases: the object is an instance and the instance is a class.
  - For instances, It looks up attribute in the object's dictionary and the attribute from the class using `typeLookup`. In the latter, it looks for the `__get__` method, but if the attribute exists in _both_ it also checks that `__set__` exists.
  - For classes, it's simpler; it just looks if `__get__` exists in the looked-up item.
- The `getclsattr` path is sort of a mix - it looks up the attribute just in the class but will call `__get__` with the object rather than `None`.
- For `callattr`, the code for looking up the value seemed completely wrong (e.g., it was doing custom lookups through `__getattr__` before looking up the class object) so I scrapped that part. I figured this should basically share all logic with `getattr` or `getclsattr` as appropriate - except that it shouldn't wrap functions in instancemethods. So I refactored `getattr_internal` out into `getattr_internal_general` which takes an additional flag which species that it should not wrap functions, and `callattr` just calls that. (So `callattr` still does binding if necessary.) Similarly, I factored `clsattr_internal` into `clsattr_internal_general`.

One thing of note is that it currently doesn't rewrite the path where `callattr` calls `__get__`, since that involves _two_ function calls: one to `__get__` and another to the function that `__get__` returns. Of course, this path is basically just a getattr and a call, each of which could be written by itself, so this clearly isn't a fundamental limitation.

I got rid of `_handleClsAttr` which already had special-case descriptor logic for functions and member descriptors. Those cases are still handled specially though, just in getattr and getclsattr with the other descriptor logic.

Finally, for `setattr`, I check if `__set__` exists and if so call that.
yeah it's out-of-date


On Tue, Aug 12, 2014 at 4:10 PM, Kevin Modzelewski <notifications@github.com
> wrote:

> In src/runtime/objmodel.cpp:
>
> > @@ -1300,26 +1813,14 @@ extern "C" void dump(void* p) {
> >
> >  // For rewriting purposes, this function assumes that nargs will be constant.
> >  // That's probably fine for some uses (ex binops), but otherwise it should be guarded on beforehand.
> > +// TODO this needs significant re-working, especially to handle descriptors
> > +// current approach of calling getattr_internal with custom=true first is fundamentally
> > +// broken since __getattr__ should be checked last
>
> Hmm I don't quite get this comment -- is it out of date?
>
> —
> Reply to this email directly or view it on GitHub
> <https://github.com/dropbox/pyston/pull/123/files#r16149223>.
>