예제 #1
0
    def __getattr__(self, name):
        """ Any non-__pydyty_* attributes will be routed to here. There are
        methods and fields, which are distinguished by checking '__call__'
        attribute on the attribute being routed for."""

        def __method_missing__(*args, **kwargs):
            """ This nested function is invoked when the attribute (method)
            is invoked. It records the types of the arguments, runs the
            original method, records the return type, and returns the actual
            result of the original method call."""

            # Try to get the caller information
            loc = Location.create(traceback.extract_stack()[-2])

            # Get types of the arguments
            arg_types = []
            for arg in args:
                if hasattr(arg, "__pydyty__"):
                    arg_types.append(arg.__pydyty_type__)
                else:
                    arg_types.append(types.NominalType(arg, is_object=True,
                                     loc=loc))

            # Get types of the dictionary arguments
            kwarg_types = {}
            for kwarg_name, kwarg_val in kwargs.iteritems():
                if hasattr(kwarg_val, '__pydyty__'):
                    kwarg_type = kwarg_val.__pydyty_type__
                else:
                    kwarg_type = types.NominalType(kwarg_val, is_object=True,
                                                   loc=loc)
                kwarg_types[kwarg_name] = kwarg_type

            # Lastly, return type. Run the original method first.
            ret_val = attr(*args, **kwargs)
            ret_type = types.NominalType(ret_val, is_object=True, loc=loc)
            method_type = types.MethodType(arg_types, kwarg_types, ret_type,
                                           loc=loc)

            self.__pydyty_type__.add_attr(name, method_type)
            return ret_val

        # Two possibilities: method and field
        # If it's a method, return __method_missing__ which will be executed
        # at the method invocation. If it's a field, get the type and return
        # the value.

        attr = getattr(self.__pydyty_obj__, name)
        if hasattr(attr, '__call__'):
            return __method_missing__

        # Try to get the caller information
        loc = Location.create(traceback.extract_stack()[-1])

        self.__pydyty_type__.add_attr(
            name, types.NominalType(attr, is_object=True, loc=loc))

        return attr
예제 #2
0
    def __add__(self, other):
        """ Strip off the argument and apply the original operator. Unless
        __add__ is overriden, it is NOT possible to wrap the argument. So do
        not wrap it. We will just NOT support structural type for the
        argument for now. """

        if hasattr(other, "__pydyty__"):
            other_obj = other.__pydyty_obj__
        else:
            other_obj = other
        ret_val = self.__pydyty_obj__ + other_obj

        if not isinstance(self.__pydyty_type__, types.NominalType):
            # Try to get the caller information
            loc = Location.create(traceback.extract_stack()[-1])
            arg_types = [types.NominalType(other, is_object=True, loc=loc)]
            ret_type = types.NominalType(ret_val, is_object=True, loc=loc)
            method_type = types.MethodType(arg_types, {}, ret_type, loc=loc)
            self.__pydyty_type__.add_attr("__add__", method_type)

        return ret_val
예제 #3
0
        def __method_missing__(*args, **kwargs):
            """ This nested function is invoked when the attribute (method)
            is invoked. It records the types of the arguments, runs the
            original method, records the return type, and returns the actual
            result of the original method call."""

            # Try to get the caller information
            loc = Location.create(traceback.extract_stack()[-2])

            # Get types of the arguments
            arg_types = []
            for arg in args:
                if hasattr(arg, "__pydyty__"):
                    arg_types.append(arg.__pydyty_type__)
                else:
                    arg_types.append(types.NominalType(arg, is_object=True,
                                     loc=loc))

            # Get types of the dictionary arguments
            kwarg_types = {}
            for kwarg_name, kwarg_val in kwargs.iteritems():
                if hasattr(kwarg_val, '__pydyty__'):
                    kwarg_type = kwarg_val.__pydyty_type__
                else:
                    kwarg_type = types.NominalType(kwarg_val, is_object=True,
                                                   loc=loc)
                kwarg_types[kwarg_name] = kwarg_type

            # Lastly, return type. Run the original method first.
            ret_val = attr(*args, **kwargs)
            ret_type = types.NominalType(ret_val, is_object=True, loc=loc)
            method_type = types.MethodType(arg_types, kwarg_types, ret_type,
                                           loc=loc)

            self.__pydyty_type__.add_attr(name, method_type)
            return ret_val