Exemplo n.º 1
0
    def generate_function(self, elem: Cursor, depth=0, **kwargs):
        """Generate a type alias

        Examples
        --------
        >>> from tide.generators.clang_utils import parse_clang
        >>> tu, index = parse_clang('float add(float a, float b);')
        >>> module = BindingGenerator().generate(tu)
        >>> print(compact(unparse(module)))
        <BLANKLINE>
        add = _bind('add', [c_float, c_float], c_float, arg_names=['a', 'b'])
        <BLANKLINE>
        """
        log.debug(f'{d(depth)}Generate function `{elem.spelling}`')
        definition: Cursor = elem.get_definition()

        if definition is None:
            definition = elem

        rtype = self.generate_type(definition.result_type, depth + 1)
        args = definition.get_arguments()
        docstring = get_comment(elem)

        pyargs = []
        arg_names = []
        for a in args:
            atype = self.generate_type(a.type, depth + 1)
            pyargs.append(atype)
            if a.spelling != '':
                arg_names.append(T.Constant(a.spelling))

        funnane = definition.spelling
        if not pyargs:
            pyargs = T.Name('None')
        else:
            pyargs = T.List(elts=pyargs)

        kwargs = []
        if len(docstring) > 0:
            kwargs.append(
                T.Keyword('docstring', T.Constant(docstring, docstring=True)))

        if arg_names:
            kwargs.append(T.Keyword('arg_names', T.List(arg_names)))

        binding_call = T.Call(T.Name('_bind'),
                              [T.Constant(funnane), pyargs, rtype], kwargs)
        return T.Assign([T.Name(funnane)], binding_call)
Exemplo n.º 2
0
    def get_references(cursor: clang.Cursor) -> typing.Generator[clang.Cursor, None, None]:
        """
        Retrieves the reference dependencies from the AST node pointed to by the given cursor.

        :param cursor: The cursor pointing to the node.
        :return: The cursors of the nodes referred to by the node.
        """
        # If the cursor is not a reference, there are no reference dependencies
        if not cursor.kind.is_reference():
            yield from ()

        referenced = cursor.referenced
        declaration = cursor.get_definition()

        if referenced is not None:
            yield referenced
        if declaration is not None and referenced != declaration:
            yield declaration
Exemplo n.º 3
0
def parse_VAR_DECL(cursor: Cursor) -> ast.Node:
    assign: Optional[Cursor] = cursor.get_definition()
    value: Optional[ast.Expression] = None
    if assign is not None:
        got_eq: bool = False
        for t in assign.get_tokens():
            if value is not None:
                logging.debug(
                    'c_compat: error: unhandled token while getting value: {}'.
                    format(t.spelling))
            elif got_eq:
                value = value_to_ehlit(t.spelling, cursor.type)
            elif t.spelling == '=':
                got_eq = True
        if got_eq is False:
            logging.debug('c_compat: error: unhandled assignment')
    typ: ast.Node = type_to_ehlit(cursor.type)
    assert isinstance(typ, ast.Symbol)
    return ast.VariableDeclaration(
        typ, ast.Identifier(0, cursor.spelling),
        ast.Assignment(value) if value is not None else None)
Exemplo n.º 4
0
    def generate_function(self, elem: Cursor):
        """Generate the Python function corresponding to the c function

        Examples
        --------
         >>> from tide.generators.clang_utils import parse_clang
        >>> tu, index = parse_clang('double add(double a, double b);')
        >>> modules = APIGenerator().generate(tu)
        >>> for k, m in modules.items():
        ...     print(f'# {k}')
        ...     print(unparse(m))
        # temporary_buffer_1234.c
        <BLANKLINE>
        <BLANKLINE>
        <BLANKLINE>
        def add(a: double, b: double) -> double:
            return add(a, b)
        <BLANKLINE>
        """
        definition: Cursor = elem.get_definition()

        if definition is None:
            definition = elem

        log.debug(f'Generate function {definition.spelling}')
        rtype = self.get_typename(definition.result_type)
        args = definition.get_arguments()

        pyargs = []
        cargs = []
        for a in args:
            atype = self.get_typename(a.type)
            aname = a.displayname
            pyargs.append(T.Arg(arg=aname, annotation=T.Name(atype)))
            cargs.append(T.Name(aname))

        c_function = definition.spelling
        module, names = self.parse_name(c_function)

        fundef = T.FunctionDef(self.topyfunname(names), T.Arguments(args=pyargs))
        fundef.returns = T.Name(rtype)
        fundef.body = [
            # this is docstring but it is not unparsed correctly
            # T.Expr(T.Str(get_comment(elem))),
            T.Return(T.Call(T.Name(c_function), cargs))
        ]

        # This could be a method
        if len(pyargs) > 0:
            # log.debug(f'Looking for {pyargs[0].annotation} in {self.type_registry}')

            selftype = pyargs[0].annotation
            classdef = None

            # For class grouping the first arg needs to be a reference to the class type
            lookuptype = selftype.id
            if isinstance(lookuptype, Ref):
                lookuptype = lookuptype.base
                classdef: T.ClassDef = self.type_registry.get(lookuptype)

                if isinstance(classdef, T.ClassDef):
                    log.debug(f'found {classdef} for {lookuptype}')
                else:
                    classdef = None

            if classdef is not None:
                # Remove annotation for `self`
                pyargs[0].arg = 'self'
                pyargs[0].annotation = None
                # replace the object by self.handle
                cargs[0] = T.Attribute(T.Name('self'), 'handle')

                # Generate Accessor properties
                if len(pyargs) == 1 and names[0] == 'get':
                    # @property
                    # def x(self):
                    #     return SDL_GetX(self.handle)
                    offset = 1
                    if names[1] == 'set':
                        offset = 2

                    fundef.name = self.topyfunname(names[offset:])
                    fundef.decorator_list.append(T.Name('property'))

                if len(pyargs) == 2 and (names[0] == 'get' or names[1] == 'get') and is_ref(pyargs[1].annotation):
                    rtype = pyargs[1].annotation
                    cargs[1] = T.Name('result')

                    offset = 1
                    if names[1] == 'get':
                        offset = 2

                    fundef.name = self.topyfunname(names[offset:])
                    fundef.decorator_list.append(T.Name('property'))
                    fundef.returns = rtype

                    fundef.args.args = [fundef.args.args[0]]
                    fundef.body = [
                        # T.Expr(T.Str(get_comment(elem))),
                        T.Assign([T.Name('result')], T.Call(rtype)),
                        T.Expr(T.Call(T.Name(c_function), cargs)),
                        # T.Assign([T.Name('err')], T.Call(T.Name(c_function), cargs)),
                        # T.If(T.Name('err'), T.Return(T.Name('None'))),
                        T.Return(T.Name('result'))
                    ]

                if len(pyargs) == 2 and (names[0] == 'set' or names[1] == 'set'):
                    # @x.setter
                    # def x(self, x):
                    #     return SDL_SetX(self.handle, x)
                    offset = 1
                    if names[1] == 'set':
                        offset = 2

                    fundef.name = self.topyfunname(names[offset:])
                    fundef.decorator_list.append(T.Attribute(T.Name(fundef.name), 'setter'))

                # Standard method
                log.debug(f'Adding method to {classdef.name}')
                classdef.body.append(fundef)
                return None

        return fundef