Example #1
0
    def write_dt_wrappers(self, node, el):
        cls_name = ft.strip_type(el.type).title()
        cls_mod_name = self.types[ft.strip_type(el.type)].mod_name
        dct = dict(el_name=el.name,
                   mod_name=self.f90_mod_name,
                   prefix=self.prefix,
                   type_name=node.name,
                   cls_name=cls_name,
                   cls_mod_name=cls_mod_name,
                   handle=isinstance(node, ft.Type) and 'self._handle' or '')
        if isinstance(node, ft.Type):
            dct['set_args'] = '%(handle)s, %(el_name)s' % dct
        else:
            dct['set_args'] = '%(el_name)s' % dct
        self.write('''@property
def %(el_name)s(self):''' % dct)
        self.indent()
        self.write(self.format_doc_string(el))
        self.write(
            '''%(el_name)s_handle = %(mod_name)s.%(prefix)s%(type_name)s__get__%(el_name)s(%(handle)s)
if tuple(%(el_name)s_handle) in self._objs:
    %(el_name)s = self._objs[tuple(%(el_name)s_handle)]
else:
    %(el_name)s = %(cls_mod_name)s.%(cls_name)s.from_handle(%(el_name)s_handle)
    self._objs[tuple(%(el_name)s_handle)] = %(el_name)s
return %(el_name)s''' % dct)
        self.dedent()
        self.write()
        self.write('''@%(el_name)s.setter
def %(el_name)s(self, %(el_name)s):
    %(el_name)s = %(el_name)s._handle
    %(mod_name)s.%(prefix)s%(type_name)s__set__%(el_name)s(%(set_args)s)
''' % dct)
        self.write()
Example #2
0
def fix_subroutine_uses_clauses(tree, types):
    """Walk over all nodes in tree, updating subroutine uses
       clauses to include the parent module and all necessary
       modules from types

       Also rename any arguments that clash with module names.
    """

    for mod, sub, arguments in ft.walk_procedures(tree):
        sub.uses = set()
        sub.mod_name = None
        if mod is not None:
            sub_name = sub.name
            if hasattr(sub, 'call_name'):
                sub_name = sub.call_name
            sub.uses.add((mod.name, (sub_name, )))
            sub.mod_name = mod.name

        for arg in arguments:
            if arg.type.startswith('type') and ft.strip_type(
                    arg.type) in types:
                sub.uses.add((types[ft.strip_type(arg.type)].mod_name,
                              (ft.strip_type(arg.type), )))

    for mod, sub, arguments in ft.walk_procedures(tree):
        for arg in arguments:
            for (mod_name, type_name) in sub.uses:
                if arg.name == mod_name:
                    arg.name += '_'

    return tree
Example #3
0
def fix_subroutine_uses_clauses(tree, types):
    """Walk over all nodes in tree, updating subroutine uses
       clauses to include the parent module and all necessary
       modules from types

       Also rename any arguments that clash with module names.
    """

    for mod, sub, arguments in ft.walk_procedures(tree):
        sub.uses = set()
        sub.mod_name = None
        if mod is not None:
            sub_name = sub.name
            if hasattr(sub, 'call_name'):
                sub_name = sub.call_name
            sub.uses.add((mod.name, (sub_name,)))
            sub.mod_name = mod.name

        for arg in arguments:
            if arg.type.startswith('type') and ft.strip_type(arg.type) in types:
                sub.uses.add((types[ft.strip_type(arg.type)].mod_name, (ft.strip_type(arg.type),)))

    for mod, sub, arguments in ft.walk_procedures(tree):
        for arg in arguments:
            for (mod_name, type_name) in sub.uses:
                if arg.name == mod_name:
                    arg.name += '_'

    return tree
Example #4
0
    def visit_Procedure(self, node):
        def py_arg_value(arg):
            if 'optional' in arg.attributes or arg.value is None:
                return '=None'
            else:
                return ''

        logging.info('PythonWrapperGenerator visiting routine %s' % node.name)
        if 'constructor' in node.attributes:
            self.write_constructor(node)
        elif 'destructor' in node.attributes:
            self.write_destructor(node)
        else:
            dct = dict(func_name=node.name,
                       method_name=hasattr(node, 'method_name') and node.method_name or node.name,
                       prefix=self.prefix,
                       mod_name=self.f90_mod_name,
                       py_arg_names=', '.join([arg.py_name+py_arg_value(arg) for arg in node.arguments]),
                       f90_arg_names=', '.join(['%s=%s' % (arg.name, arg.py_value) for arg in node.arguments]),
                       call='')

            if isinstance(node, ft.Function):
                dct['result'] = ', '.join([ret_val.name for ret_val in node.ret_val])
                dct['call'] = '%(result)s = ' % dct

            if not self.make_package and node.mod_name is not None and node.type_name is None:
                # procedures outside of derived types become static methods
                self.write('@staticmethod')
            self.write("def %(method_name)s(%(py_arg_names)s):" % dct)
            self.indent()
            self.write(format_doc_string(node))
            for arg in node.arguments:
                if 'optional' in arg.attributes and '._handle' in arg.py_value:
                    dct['f90_arg_names'] = dct['f90_arg_names'].replace(arg.py_value,
                                                                        ('None if %(arg_py_name)s is None else %(arg_py_name)s._handle') %
                                                                        {'arg_py_name': arg.py_name})
            call_line = '%(call)s%(mod_name)s.%(prefix)s%(func_name)s(%(f90_arg_names)s)' % dct
            self.write(call_line)

            if isinstance(node, ft.Function):
                # convert any derived type return values to Python objects
                for ret_val in node.ret_val:
                    if ret_val.type.startswith('type'):
                        cls_name = normalise_class_name(ft.strip_type(ret_val.type), self.class_names)
                        cls_name = self.py_mod_name + '.' + cls_name
                        cls_name = 'f90wrap.runtime.lookup_class("%s")' % cls_name
                        cls_mod_name = self.types[ft.strip_type(ret_val.type)].mod_name
                        cls_mod_name = self.py_mod_names.get(cls_mod_name, cls_mod_name)
                        # if self.make_package:
                        #     if cls_mod_name != self.current_module:
                        #         self.imports.add((self.py_mod_name + '.' + cls_mod_name, cls_name))
                        # else:
                        #     cls_name = cls_mod_name + '.' + cls_name
                        self.write('%s = %s.from_handle(%s)' %
                                   (ret_val.name, cls_name, ret_val.name))
                self.write('return %(result)s' % dct)

            self.dedent()
            self.write()
Example #5
0
    def visit_Procedure(self, node):
        logging.info('PythonWrapperGenerator visiting routine %s' % node.name)
        if 'constructor' in node.attributes:
            self.write_constructor(node)
        elif 'destructor' in node.attributes:
            self.write_destructor(node)
        else:
            dct = dict(
                func_name=node.name,
                method_name=hasattr(node, 'method_name') and node.method_name
                or node.name,
                prefix=self.prefix,
                mod_name=self.f90_mod_name,
                py_arg_names=', '.join([
                    '%s%s' %
                    (arg.py_name,
                     ('optional' in arg.attributes or arg.value is None)
                     and '=None' or '') for arg in node.arguments
                ]),
                f90_arg_names=', '.join([
                    '%s=%s' % (arg.name, arg.py_value)
                    for arg in node.arguments
                ]),
                call='')

            if isinstance(node, ft.Function):
                dct['result'] = ', '.join(
                    [ret_val.name for ret_val in node.ret_val])
                dct['call'] = '%(result)s = ' % dct

            if not self.make_package and node.mod_name is not None and node.type_name is None:
                # procedures outside of derived types become static methods
                self.write('@staticmethod')
            self.write("def %(method_name)s(%(py_arg_names)s):" % dct)
            self.indent()
            self.write(format_doc_string(node))
            call_line = '%(call)s%(mod_name)s.%(prefix)s%(func_name)s(%(f90_arg_names)s)' % dct
            self.write(call_line)

            if isinstance(node, ft.Function):
                # convert any derived type return values to Python objects
                for ret_val in node.ret_val:
                    if ret_val.type.startswith('type'):
                        cls_name = ft.strip_type(ret_val.type).title()
                        cls_mod_name = self.types[ft.strip_type(
                            ret_val.type)].mod_name
                        if self.make_package:
                            if cls_mod_name != self.current_module:
                                self.imports.add(
                                    (self.py_mod_name + '.' + cls_mod_name,
                                     cls_name))
                        else:
                            cls_name = cls_mod_name + '.' + cls_name
                        self.write('%s = %s.from_handle(%s)' %
                                   (ret_val.name, cls_name, ret_val.name))
                self.write('return %(result)s' % dct)

            self.dedent()
            self.write()
Example #6
0
    def write_dt_wrappers(self, node, el):
        cls_name = ft.strip_type(el.type).title()
        cls_mod_name = self.types[ft.strip_type(el.type)].mod_name
        dct = dict(el_name=el.name,
                   el_name_get=el.name,
                   el_name_set=el.name,
                   mod_name=self.f90_mod_name,
                   prefix=self.prefix,
                   type_name=node.name,
                   cls_name=cls_name,
                   cls_mod_name=cls_mod_name + '.',
                   self='self',
                   selfdot='self.',
                   selfcomma='self, ',
                   handle=isinstance(node, ft.Type) and 'self._handle' or '')
        if isinstance(node, ft.Type):
            dct['set_args'] = '%(handle)s, %(el_name)s' % dct
        else:
            dct['set_args'] = '%(el_name)s' % dct
        if self.make_package:
            dct['cls_mod_name'] = ''
            if cls_mod_name != self.current_module:
                self.imports.add(
                    (self.py_mod_name + '.' + cls_mod_name, cls_name))

        if not isinstance(node, ft.Module) or not self.make_package:
            self.write('@property')
        else:
            dct['el_name_get'] = 'get_' + el.name
            dct['el_name_set'] = 'set_' + el.name
            dct['self'] = ''
            dct['selfdot'] = ''
            dct['selfcomma'] = ''

        self.write('def %(el_name_get)s(%(self)s):' % dct)
        self.indent()
        self.write(format_doc_string(el))
        if isinstance(node, ft.Module) and self.make_package:
            self.write('global %(el_name)s' % dct)
        self.write(
            '''%(el_name)s_handle = %(mod_name)s.%(prefix)s%(type_name)s__get__%(el_name)s(%(handle)s)
if tuple(%(el_name)s_handle) in %(selfdot)s_objs:
    %(el_name)s = %(selfdot)s_objs[tuple(%(el_name)s_handle)]
else:
    %(el_name)s = %(cls_mod_name)s%(cls_name)s.from_handle(%(el_name)s_handle)
    %(selfdot)s_objs[tuple(%(el_name)s_handle)] = %(el_name)s
return %(el_name)s''' % dct)
        self.dedent()
        self.write()

        if 'parameter' not in el.attributes:
            if not isinstance(node, ft.Module) or not self.make_package:
                self.write('@%(el_name_set)s.setter' % dct)
            self.write('''def %(el_name_set)s(%(selfcomma)s%(el_name)s):
    %(el_name)s = %(el_name)s._handle
    %(mod_name)s.%(prefix)s%(type_name)s__set__%(el_name)s(%(set_args)s)
    ''' % dct)
            self.write()
Example #7
0
    def write_dt_wrappers(self, node, el, properties):
        cls_name = ft.strip_type(el.type).title()
        cls_mod_name = self.types[ft.strip_type(el.type)].mod_name
        dct = dict(el_name=el.name,
                   el_name_get=el.name,
                   el_name_set=el.name,
                   mod_name=self.f90_mod_name,
                   prefix=self.prefix, type_name=node.name,
                   cls_name=cls_name,
                   cls_mod_name=cls_mod_name + '.',
                   self='self',
                   selfdot='self.',
                   selfcomma='self, ',
                   handle=isinstance(node, ft.Type) and 'self._handle' or '')
        if isinstance(node, ft.Type):
            dct['set_args'] = '%(handle)s, %(el_name)s' % dct
        else:
            dct['set_args'] = '%(el_name)s' % dct
        if self.make_package:
            dct['cls_mod_name'] = ''
            if cls_mod_name != self.current_module:
                self.imports.add((self.py_mod_name + '.' + cls_mod_name, cls_name))

        if not isinstance(node, ft.Module) or not self.make_package:
            self.write('@property')
            properties.append(el)
        else:
            dct['el_name_get'] = 'get_' + el.name
            dct['el_name_set'] = 'set_' + el.name
            dct['self'] = ''
            dct['selfdot'] = ''
            dct['selfcomma'] = ''

        self.write('def %(el_name_get)s(%(self)s):' % dct)
        self.indent()
        self.write(format_doc_string(el))
        if isinstance(node, ft.Module) and self.make_package:
            self.write('global %(el_name)s' % dct)
        self.write('''%(el_name)s_handle = %(mod_name)s.%(prefix)s%(type_name)s__get__%(el_name)s(%(handle)s)
if tuple(%(el_name)s_handle) in %(selfdot)s_objs:
    %(el_name)s = %(selfdot)s_objs[tuple(%(el_name)s_handle)]
else:
    %(el_name)s = %(cls_mod_name)s%(cls_name)s.from_handle(%(el_name)s_handle)
    %(selfdot)s_objs[tuple(%(el_name)s_handle)] = %(el_name)s
return %(el_name)s''' % dct)
        self.dedent()
        self.write()

        if 'parameter' not in el.attributes:
            if not isinstance(node, ft.Module) or not self.make_package:
                self.write('@%(el_name_set)s.setter' % dct)
            self.write('''def %(el_name_set)s(%(selfcomma)s%(el_name)s):
    %(el_name)s = %(el_name)s._handle
    %(mod_name)s.%(prefix)s%(type_name)s__set__%(el_name)s(%(set_args)s)
    ''' % dct)
            self.write()
Example #8
0
def fix_element_uses_clauses(tree, types):
    """
    Add uses clauses to derived type elements in modules
    """
    for mod in ft.walk_modules(tree):
        for el in mod.elements:
            el.uses = set()
            if el.type.startswith('type') and ft.strip_type(el.type) in types:
                el.uses.add((types[el.type].mod_name, (ft.strip_type(el.type),)))

    return tree
Example #9
0
def fix_element_uses_clauses(tree, types):
    """
    Add uses clauses to derived type elements in modules
    """
    for mod in ft.walk_modules(tree):
        for el in mod.elements:
            el.uses = set()
            if el.type.startswith('type') and ft.strip_type(el.type) in types:
                el.uses.add(
                    (types[el.type].mod_name, (ft.strip_type(el.type), )))

    return tree
Example #10
0
    def write_dt_array_wrapper(self, node, el, dims):
        if el.type.startswith('type') and len(
                ArrayDimensionConverter.split_dimensions(dims)) != 1:
            return

        func_name = 'init_array_%s' % el.name
        node.dt_array_initialisers.append(func_name)
        cls_name = normalise_class_name(ft.strip_type(el.type),
                                        self.class_names)
        mod_name = self.types[ft.strip_type(el.type)].mod_name
        cls_mod_name = self.py_mod_names.get(mod_name, mod_name)

        dct = dict(el_name=el.name,
                   func_name=func_name,
                   mod_name=node.name,
                   type_name=ft.strip_type(el.type).lower(),
                   f90_mod_name=self.f90_mod_name,
                   prefix=self.prefix,
                   self='self',
                   selfdot='self.',
                   parent='self',
                   doc=format_doc_string(el),
                   cls_name=cls_name,
                   cls_mod_name=cls_mod_name + '.')

        if isinstance(node, ft.Module):
            dct['parent'] = 'f90wrap.runtime.empty_type'
            if self.make_package:
                dct['selfdot'] = ''
                dct['self'] = ''
        if self.make_package:
            dct['cls_mod_name'] = ''
            if cls_mod_name != self.current_module:
                self.imports.add(
                    (self.py_mod_name + '.' + cls_mod_name, cls_name))

        self.write('def %(func_name)s(%(self)s):' % dct)
        self.indent()
        if isinstance(node, ft.Module) and self.make_package:
            self.write('global %(el_name)s' % dct)
        self.write(
            '''%(selfdot)s%(el_name)s = f90wrap.runtime.FortranDerivedTypeArray(%(parent)s,
                                %(f90_mod_name)s.%(prefix)s%(mod_name)s__array_getitem__%(el_name)s,
                                %(f90_mod_name)s.%(prefix)s%(mod_name)s__array_setitem__%(el_name)s,
                                %(f90_mod_name)s.%(prefix)s%(mod_name)s__array_len__%(el_name)s,
                                %(doc)s, %(cls_mod_name)s%(cls_name)s)''' %
            dct)
        self.write('return %(selfdot)s%(el_name)s' % dct)
        self.dedent()
        self.write()
Example #11
0
    def write_dt_array_wrapper(self, node, el, dims):
        if el.type.startswith('type') and len(ArrayDimensionConverter.split_dimensions(dims)) != 1:
            return

        func_name = 'init_array_%s' % el.name
        node.dt_array_initialisers.append(func_name)
        cls_name = normalise_class_name(ft.strip_type(el.type), self.class_names)
        mod_name = self.types[ft.strip_type(el.type)].mod_name
        cls_mod_name = self.py_mod_names.get(mod_name, mod_name)

        dct = dict(el_name=el.name,
                   func_name=func_name,
                   mod_name=node.name,
                   type_name=ft.strip_type(el.type).lower(),
                   f90_mod_name=self.f90_mod_name,
                   prefix=self.prefix,
                   self='self',
                   selfdot='self.',
                   parent='self',
                   doc=format_doc_string(el),
                   cls_name=cls_name,
                   cls_mod_name=cls_mod_name + '.')

        if isinstance(node, ft.Module):
            dct['parent'] = 'f90wrap.runtime.empty_type'
            if self.make_package:
                dct['selfdot'] = ''
                dct['self'] = ''
        if self.make_package:
            dct['cls_mod_name'] = ''
            if cls_mod_name != self.current_module:
                self.imports.add((self.py_mod_name + '.' + cls_mod_name, cls_name))

        self.write('def %(func_name)s(%(self)s):' % dct)
        self.indent()
        if isinstance(node, ft.Module) and self.make_package:
            self.write('global %(el_name)s' % dct)
        self.write('''%(selfdot)s%(el_name)s = f90wrap.runtime.FortranDerivedTypeArray(%(parent)s,
                                %(f90_mod_name)s.%(prefix)s%(mod_name)s__array_getitem__%(el_name)s,
                                %(f90_mod_name)s.%(prefix)s%(mod_name)s__array_setitem__%(el_name)s,
                                %(f90_mod_name)s.%(prefix)s%(mod_name)s__array_len__%(el_name)s,
                                %(doc)s, %(cls_mod_name)s%(cls_name)s)''' % dct)
        self.write('return %(selfdot)s%(el_name)s' % dct)
        self.dedent()
        self.write()
Example #12
0
    def write_type_lines(self, tname):
        """
        Write a pointer type for a given type name
        
        Parameters
        ----------
        tname : `str`
            Should be the name of a derived type in the wrapped code.
        """
        tname = ft.strip_type(tname)
        self.write("""type %(typename)s_ptr_type
    type(%(typename)s), pointer :: p => NULL()
end type %(typename)s_ptr_type""" % {'typename': tname})
Example #13
0
    def write_type_lines(self, tname):
        """
        Write a pointer type for a given type name
        
        Parameters
        ----------
        tname : `str`
            Should be the name of a derived type in the wrapped code.
        """
        tname = ft.strip_type(tname)
        self.write("""type %(typename)s_ptr_type
    type(%(typename)s), pointer :: p => NULL()
end type %(typename)s_ptr_type""" % {'typename': tname})
Example #14
0
def convert_derived_type_arguments(tree, init_lines, sizeof_fortran_t):
    for mod, sub, arguments in ft.walk_procedures(tree, include_ret_val=True):
        sub.types = set()
        sub.transfer_in = []
        sub.transfer_out = []
        sub.allocate = []
        sub.deallocate = []

        if 'constructor' in sub.attributes:
            sub.arguments[0].attributes = set_intent(
                sub.arguments[0].attributes, 'intent(out)')

        if 'destructor' in sub.attributes:
            logging.debug('deallocating arg "%s" in %s' %
                          (sub.arguments[0].name, sub.name))
            sub.deallocate.append(sub.arguments[0].name)

        for arg in arguments:
            if not hasattr(arg, 'type') or not arg.type.startswith('type'):
                continue

            # save original Fortran intent since we'll be overwriting it
            # with intent of the opaque pointer
            arg.attributes = arg.attributes + [
                'fortran_' + attr
                for attr in arg.attributes if attr.startswith('intent')
            ]

            typename = ft.strip_type(arg.type)
            arg.wrapper_type = 'integer'
            arg.wrapper_dim = sizeof_fortran_t
            sub.types.add(typename)

            if typename in init_lines:
                use, (exe, exe_optional) = init_lines[typename]
                if use is not None:
                    sub.uses.add((use, [typename]))
                arg.init_lines = (exe_optional, exe)

            if 'intent(out)' in arg.attributes:
                arg.attributes = set_intent(arg.attributes, 'intent(out)')
                sub.transfer_out.append(arg.name)
                if 'pointer' not in arg.attributes:
                    logging.debug('allocating arg "%s" in %s' %
                                  (arg.name, sub.name))
                    sub.allocate.append(arg.name)
            else:
                arg.attributes = set_intent(arg.attributes, 'intent(in)')
                sub.transfer_in.append(arg.name)

    return tree
Example #15
0
def convert_derived_type_arguments(tree, init_lines, sizeof_fortran_t):
    for mod, sub, arguments in ft.walk_procedures(tree, include_ret_val=True):
        sub.types = set()
        sub.transfer_in = []
        sub.transfer_out = []
        sub.allocate = []
        sub.deallocate = []

        if 'constructor' in sub.attributes:
            sub.arguments[0].attributes = set_intent(sub.arguments[0].attributes, 'intent(out)')

        if 'destructor' in sub.attributes:
            logging.debug('deallocating arg "%s" in %s' % (sub.arguments[0].name, sub.name))
            sub.deallocate.append(sub.arguments[0].name)

        for arg in arguments:
            if not hasattr(arg, 'type') or not arg.type.startswith('type'):
                continue

            # save original Fortran intent since we'll be overwriting it
            # with intent of the opaque pointer
            arg.attributes = arg.attributes + ['fortran_' + attr for attr in
                               arg.attributes if attr.startswith('intent')]

            typename = ft.strip_type(arg.type)
            arg.wrapper_type = 'integer'
            arg.wrapper_dim = sizeof_fortran_t
            sub.types.add(typename)

            if typename in init_lines:
                use, (exe, exe_optional) = init_lines[typename]
                if use is not None:
                    sub.uses.add((use, [typename]))
                arg.init_lines = (exe_optional, exe)

            if 'intent(out)' in arg.attributes:
                arg.attributes = set_intent(arg.attributes, 'intent(out)')
                sub.transfer_out.append(arg.name)
                if 'pointer' not in arg.attributes:
                    logging.debug('allocating arg "%s" in %s' % (arg.name, sub.name))
                    sub.allocate.append(arg.name)
            else:
                arg.attributes = set_intent(arg.attributes, 'intent(in)')
                sub.transfer_in.append(arg.name)

    return tree
Example #16
0
    def visit_Interface(self, node):
        logging.info('PythonWrapperGenerator visiting interface %s' %
                     node.name)

        # first output all the procedures within the interface
        self.generic_visit(node)
        cls_name = None
        if node.type_name is not None:
            cls_name = normalise_class_name(ft.strip_type(node.type_name),
                                            self.class_names)
        proc_names = []
        for proc in node.procedures:
            proc_name = ''
            if not self.make_package:
                proc_name += normalise_class_name(proc.mod_name,
                                                  self.class_names) + '.'
            elif cls_name is not None:
                proc_name += cls_name + '.'
            if hasattr(proc, 'method_name'):
                proc_name += proc.method_name
            else:
                proc_name += proc.name
            proc_names.append(proc_name)

        dct = dict(intf_name=node.method_name,
                   proc_names='[' + ', '.join(proc_names) + ']')
        if not self.make_package:
            # procedures outside of derived types become static methods
            self.write('@staticmethod')
        self.write('def %(intf_name)s(*args, **kwargs):' % dct)
        self.indent()
        self.write(format_doc_string(node))
        # try to call each in turn until no TypeError raised
        self.write('for proc in %(proc_names)s:' % dct)
        self.indent()
        self.write('try:')
        self.indent()
        self.write('return proc(*args, **kwargs)')
        self.dedent()
        self.write('except TypeError:')
        self.indent()
        self.write('continue')
        self.dedent()
        self.dedent()
        self.dedent()
        self.write()
Example #17
0
def fix_subroutine_uses_clauses(tree, types):
    """Walk over all nodes in tree, updating subroutine uses
       clauses to include the parent module and all necessary
       modules from types"""

    for mod, sub, arguments in ft.walk_procedures(tree):
        sub.uses = set()
        sub.mod_name = None
        if mod is not None:
            sub.uses.add((mod.name, (sub.name,)))
            sub.mod_name = mod.name

        for arg in arguments:
            if arg.type.startswith('type') and arg.type in types:
                sub.uses.add((types[arg.type].mod_name, (ft.strip_type(arg.type),)))

    return tree
Example #18
0
def fix_subroutine_uses_clauses(tree, types):
    """Walk over all nodes in tree, updating subroutine uses
       clauses to include the parent module and all necessary
       modules from types"""

    for mod, sub, arguments in ft.walk_procedures(tree):
        sub.uses = set()
        sub.mod_name = None
        if mod is not None:
            sub.uses.add((mod.name, (sub.name, )))
            sub.mod_name = mod.name

        for arg in arguments:
            if arg.type.startswith('type') and arg.type in types:
                sub.uses.add(
                    (types[arg.type].mod_name, (ft.strip_type(arg.type), )))

    return tree
Example #19
0
    def visit_Interface(self, node):
        logging.info('PythonWrapperGenerator visiting interface %s' % node.name)

        # first output all the procedures within the interface
        self.generic_visit(node)
        cls_name = None
        if node.type_name is not None:
            cls_name = normalise_class_name(ft.strip_type(node.type_name),
                                            self.class_names)
        proc_names = []
        for proc in node.procedures:
            proc_name = ''
            if not self.make_package:
                proc_name += proc.mod_name.title()+'.'
            elif cls_name is not None:
                proc_name += cls_name+'.'
            if hasattr(proc, 'method_name'):
                proc_name += proc.method_name
            else:
                proc_name += proc.name
            proc_names.append(proc_name)

        dct = dict(intf_name=node.method_name,
                   proc_names='[' + ', '.join(proc_names) + ']')
        if not self.make_package:
            # procedures outside of derived types become static methods
            self.write('@staticmethod')
        self.write('def %(intf_name)s(*args, **kwargs):' % dct)
        self.indent()
        self.write(format_doc_string(node))
        # try to call each in turn until no TypeError raised
        self.write('for proc in %(proc_names)s:' % dct)
        self.indent()
        self.write('try:')
        self.indent()
        self.write('return proc(*args, **kwargs)')
        self.dedent()
        self.write('except TypeError:')
        self.indent()
        self.write('continue')
        self.dedent()
        self.dedent()
        self.dedent()
        self.write()
Example #20
0
    def write_type_lines(self, tname, recursive=False):
        """
        Write a pointer type for a given type name

        Parameters
        ----------
        tname : `str`
            Should be the name of a derived type in the wrapped code.

        recursive : `boolean`
            Adjusts array pointer for recursive derived type array
        """
        tname = ft.strip_type(tname)
        if not recursive:
            self.write("""type %(typename)s_ptr_type
    type(%(typename)s), pointer :: p => NULL()
end type %(typename)s_ptr_type""" % {'typename': tname})
        else:
            self.write("""type %(typename)s_rec_ptr_type
    type(%(typename)s), pointer :: p => NULL()
end type %(typename)s_rec_ptr_type""" % {'typename': tname})
Example #21
0
    def _write_scalar_wrapper(self, t, el, sizeof_fortran_t, getset):
        """
        Write get/set routines for scalar derived-types.
        
        Parameters
        ----------
        t : `fortran.Type` node
            Derived-type node of the parse tree.
            
        el : `fortran.Element` node
            An element of a module which is derived-type array
            
        sizeof_fortan_t : `int`
            The size, in bytes, of a pointer to a fortran derived type ??
            
        getset : `str` {``"get"``,``"set"``}
            String indicating whether to write a get routine, or a set routine.
        """
        # getset and inout just change things simply from a get to a set routine.
        inout = "in"
        if getset == "get":
            inout = "out"

        if isinstance(t, ft.Type):
            this = 'this, '
        elif isinstance(t, ft.Module):
            this = ''
        else:
            raise ValueError("Don't know how to write scalar wrappers for %s type %s" (t, type(t)))

        self.write('subroutine %s%s__%s__%s(%s%s)' % (self.prefix, t.name,
                                                    getset, el.name, this, el.name))
        self.indent()
        self.write_uses_lines(t)
        if isinstance(t, ft.Module):
            use_only = []
            use_only.append('%s_%s => %s' % (t.name, el.name, el.name))
            use_only = ', '.join(use_only)
            self.write('use %s, only: ' % t.name + use_only)

        self.write('implicit none')
        if isinstance(t, ft.Type):
            self.write_type_lines(t.name)

        if el.type.startswith('type'):
            self.write_type_lines(el.type)

        if isinstance(t, ft.Type):
            self.write('integer, intent(in)   :: this(%d)' % sizeof_fortran_t)
            self.write('type(%s_ptr_type) :: this_ptr' % t.name)

        if el.type.startswith('type'):
            # For derived types elements, treat as opaque reference
            self.write('integer, intent(%s) :: %s(%d)' % (inout, el.name, sizeof_fortran_t))

            self.write('type(%s_ptr_type) :: %s_ptr' % (ft.strip_type(el.type), el.name))
            self.write()
            if isinstance(t, ft.Type):
                self.write('this_ptr = transfer(this, this_ptr)')
            if getset == "get":
                if isinstance(t, ft.Type):
                    self.write('%s_ptr%%p => this_ptr%%p%%%s' % (el.name, el.name))
                else:
                    self.write('%s_ptr%%p => %s_%s' % (el.name, t.name, el.name))
                self.write('%s = transfer(%s_ptr,%s)' % (el.name, el.name, el.name))
            else:
                self.write('%s_ptr = transfer(%s,%s_ptr)' % (el.name,
                                                             el.name,
                                                             el.name))
                if isinstance(t, ft.Type):
                    self.write('this_ptr%%p%%%s = %s_ptr%%p' % (el.name, el.name))
                else:
                    self.write('%s_%s = %s_ptr%%p' % (t.name, el.name, el.name))
        else:
            # Return/set by value
            if 'pointer' in el.attributes:
                el.attributes.remove('pointer')

            if el.attributes != []:
                self.write('%s, %s, intent(%s) :: %s' % (el.type,
                                                         ','.join(el.attributes),
                                                         inout, el.name))
            else:
                self.write('%s, intent(%s) :: %s' % (el.type, inout, el.name))
            self.write()
            if isinstance(t, ft.Type):
                self.write('this_ptr = transfer(this, this_ptr)')
            if getset == "get":
                if isinstance(t, ft.Type):
                    self.write('%s = this_ptr%%p%%%s' % (el.name, el.name))
                else:
                    self.write('%s = %s_%s' % (el.name, t.name, el.name))
            else:
                if isinstance(t, ft.Type):
                    self.write('this_ptr%%p%%%s = %s' % (el.name, el.name))
                else:
                    self.write('%s_%s = %s' % (t.name, el.name, el.name))
        self.dedent()
        self.write('end subroutine %s%s__%s__%s' % (self.prefix, t.name, getset,
                                                    el.name))
        self.write()
Example #22
0
    def write_dt_wrappers(self, node, el, properties):
        cls_name = normalise_class_name(ft.strip_type(el.type),
                                        self.class_names)
        mod_name = self.types[ft.strip_type(el.type)].mod_name
        cls_mod_name = self.py_mod_names.get(mod_name, mod_name)
        dct = dict(el_name=el.name,
                   el_name_get=el.name,
                   el_name_set=el.name,
                   mod_name=self.f90_mod_name,
                   prefix=self.prefix,
                   type_name=node.name,
                   cls_name=cls_name,
                   cls_mod_name=cls_mod_name + '.',
                   self='self',
                   selfdot='self.',
                   selfcomma='self, ',
                   handle=isinstance(node, ft.Type) and 'self._handle' or '')
        if isinstance(node, ft.Type):
            dct['set_args'] = '%(handle)s, %(el_name)s' % dct
        else:
            dct['set_args'] = '%(el_name)s' % dct
        if self.make_package:
            dct['cls_mod_name'] = ''
            if cls_mod_name != self.current_module:
                self.imports.add(
                    (self.py_mod_name + '.' + cls_mod_name, cls_name))

        if not isinstance(node, ft.Module) or not self.make_package:
            self.write('@property')
            properties.append(el)
        else:
            dct['el_name_get'] = 'get_' + el.name
            dct['el_name_set'] = 'set_' + el.name
            dct['self'] = ''
            dct['selfdot'] = ''
            dct['selfcomma'] = ''

        # check for name clashes with pre-existing routines
        if hasattr(node, 'procedures'):
            procs = [proc.name for proc in node.procedures]
            if dct['el_name_get'] in procs:
                dct['el_name_get'] += '_'
            if dct['el_name_set'] in procs:
                dct['el_name_set'] += '_'

        self.write('def %(el_name_get)s(%(self)s):' % dct)
        self.indent()
        self.write(format_doc_string(el))
        if isinstance(node, ft.Module) and self.make_package:
            self.write('global %(el_name)s' % dct)
        self.write(
            '''%(el_name)s_handle = %(mod_name)s.%(prefix)s%(type_name)s__get__%(el_name)s(%(handle)s)
if tuple(%(el_name)s_handle) in %(selfdot)s_objs:
    %(el_name)s = %(selfdot)s_objs[tuple(%(el_name)s_handle)]
else:
    %(el_name)s = %(cls_mod_name)s%(cls_name)s.from_handle(%(el_name)s_handle)
    %(selfdot)s_objs[tuple(%(el_name)s_handle)] = %(el_name)s
return %(el_name)s''' % dct)
        self.dedent()
        self.write()

        if 'parameter' not in el.attributes:
            if not isinstance(node, ft.Module) or not self.make_package:
                self.write('@%(el_name_set)s.setter' % dct)
            self.write('''def %(el_name_set)s(%(selfcomma)s%(el_name)s):
    %(el_name)s = %(el_name)s._handle
    %(mod_name)s.%(prefix)s%(type_name)s__set__%(el_name)s(%(set_args)s)
    ''' % dct)
            self.write()
Example #23
0
    def _write_scalar_wrapper(self, t, el, sizeof_fortran_t, getset):
        """
        Write get/set routines for scalar elements of derived-types and modules
        
        Parameters
        ----------
        t : `fortran.Type` node or `fortran.Module` node
            Node of the parse tree which contains this derived-type as an element
            
        el : `fortran.Element` node
            An element of a module which is derived-type array
            
        sizeof_fortan_t : `int`
            The size, in bytes, of a pointer to a fortran derived type ??
            
        getset : `str` {``"get"``,``"set"``}
            String indicating whether to write a get routine, or a set routine.
        """

        logging.debug('writing %s wrapper for %s.%s' %
                      (getset, t.name, el.name))

        # getset and inout just change things simply from a get to a set routine.
        inout = "in"
        if getset == "get":
            inout = "out"

        if isinstance(t, ft.Type):
            this = 'this, '
        elif isinstance(t, ft.Module):
            this = ''
        else:
            raise ValueError(
                "Don't know how to write scalar wrappers for %s type %s" (
                    t, type(t)))

        # Get appropriate use statements
        extra_uses = {}
        if isinstance(t, ft.Module):
            extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)]
        elif isinstance(t, ft.Type):
            extra_uses[self.types[t.name].mod_name] = [t.name]
        if el.type.startswith('type'):
            mod = self.types[el.type].mod_name
            el_tname = ft.strip_type(el.type)
            if mod in extra_uses:
                extra_uses[mod].append(el_tname)
            else:
                extra_uses[mod] = [el_tname]

        # If the var that is get/set has the same name as something in uses, then append _
        localvar = el.name
        if localvar in getattr(el, "uses", []) or localvar in extra_uses:
            localvar += "_"

        self.write('subroutine %s%s__%s__%s(%s%s)' %
                   (self.prefix, t.name, getset, el.name, this, localvar))
        self.indent()

        self.write_uses_lines(el, extra_uses)

        self.write('implicit none')
        if isinstance(t, ft.Type):
            self.write_type_lines(t.name)

        if el.type.startswith('type'):
            self.write_type_lines(el.type)

        if isinstance(t, ft.Type):
            self.write('integer, intent(in)   :: this(%d)' % sizeof_fortran_t)
            self.write('type(%s_ptr_type) :: this_ptr' % t.name)

        # Return/set by value
        attributes = [
            attr for attr in el.attributes if attr not in
            ['pointer', 'allocatable', 'public', 'parameter', 'save']
        ]

        if el.type.startswith('type'):
            # For derived types elements, treat as opaque reference
            self.write('integer, intent(%s) :: %s(%d)' %
                       (inout, localvar, sizeof_fortran_t))

            self.write('type(%s_ptr_type) :: %s_ptr' %
                       (ft.strip_type(el.type), el.name))
            self.write()
            if isinstance(t, ft.Type):
                self.write('this_ptr = transfer(this, this_ptr)')
            if getset == "get":
                if isinstance(t, ft.Type):
                    self.write('%s_ptr%%p => this_ptr%%p%%%s' %
                               (el.name, el.name))
                else:
                    self.write('%s_ptr%%p => %s_%s' %
                               (el.name, t.name, el.name))
                self.write('%s = transfer(%s_ptr,%s)' %
                           (localvar, el.name, localvar))
            else:
                self.write('%s_ptr = transfer(%s,%s_ptr)' %
                           (el.name, localvar, el.name))
                if isinstance(t, ft.Type):
                    self.write('this_ptr%%p%%%s = %s_ptr%%p' %
                               (el.name, el.name))
                else:
                    self.write('%s_%s = %s_ptr%%p' %
                               (t.name, el.name, el.name))
        else:
            if attributes != []:
                self.write('%s, %s, intent(%s) :: %s' %
                           (el.type, ','.join(attributes), inout, localvar))
            else:
                self.write('%s, intent(%s) :: %s' % (el.type, inout, localvar))
            self.write()
            if isinstance(t, ft.Type):
                self.write('this_ptr = transfer(this, this_ptr)')
            if getset == "get":
                if isinstance(t, ft.Type):
                    self.write('%s = this_ptr%%p%%%s' % (localvar, el.name))
                else:
                    self.write('%s = %s_%s' % (localvar, t.name, el.name))
            else:
                if isinstance(t, ft.Type):
                    self.write('this_ptr%%p%%%s = %s' % (el.name, localvar))
                else:
                    self.write('%s_%s = %s' % (t.name, el.name, localvar))
        self.dedent()
        self.write('end subroutine %s%s__%s__%s' %
                   (self.prefix, t.name, getset, el.name))
        self.write()
Example #24
0
    def _write_array_len(self, t, el, sizeof_fortran_t):
        """
        Write a subroutine which returns the length of a derived-type array
        
        Parameters
        ----------
        t : `fortran.Type` node or `fortran.Module` node
            Node of the parse tree which contains this derived-type as an element
            
        el : `fortran.Element` node
            An element of a module which is derived-type array
            
        sizeof_fortan_t : `int`
            The size, in bytes, of a pointer to a fortran derived type ??
        """
        if isinstance(t, ft.Type):
            this = 'this'
        else:
            this = 'dummy_this'

        self.write('subroutine %s%s__array_len__%s(%s, n)' %
                   (self.prefix, t.name, el.name, this))
        self.indent()
        self.write()
        extra_uses = {}
        if isinstance(t, ft.Module):
            extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)]
        elif isinstance(t, ft.Type):
            extra_uses[self.types[t.name].mod_name] = [t.name]
        mod = self.types[el.type].mod_name
        el_tname = ft.strip_type(el.type)
        if mod in extra_uses:
            extra_uses[mod].append(el_tname)
        else:
            extra_uses[mod] = [el_tname]
        self.write_uses_lines(el, extra_uses)
        self.write('implicit none')
        self.write()
        if isinstance(t, ft.Type):
            self.write_type_lines(t.name)
        self.write_type_lines(el.type)
        self.write('integer, intent(out) :: n')
        self.write('integer, intent(in) :: %s(%d)' % (this, sizeof_fortran_t))
        if isinstance(t, ft.Type):
            self.write('type(%s_ptr_type) :: this_ptr' % t.name)
            self.write()
            self.write('this_ptr = transfer(this, this_ptr)')
            array_name = 'this_ptr%%p%%%s' % el.name
        else:
            array_name = '%s_%s' % (t.name, el.name)

        if 'allocatable' in el.attributes:
            self.write('if (allocated(%s)) then' % array_name)
            self.indent()

        self.write('n = size(%s)' % array_name)

        if 'allocatable' in el.attributes:
            self.dedent()
            self.write('else')
            self.indent()
            self.write('n = 0')
            self.dedent()
            self.write('end if')

        self.dedent()
        self.write('end subroutine %s%s__array_len__%s' %
                   (self.prefix, t.name, el.name))
        self.write()
Example #25
0
    def _write_array_getset_item(self, t, el, sizeof_fortran_t, getset):
        """
        Write a subroutine to get/set items in a derived-type array.
        
        Parameters
        ----------
        t : `fortran.Type` node
            Derived-type node of the parse tree.
            
        el : `fortran.Element` node
            An element of a module which is derived-type array
            
        sizeof_fortan_t : `int`
            The size, in bytes, of a pointer to a fortran derived type ??
            
        getset : `str` {``"get"``,``"set"``}
            String indicating whether to write a get routine, or a set routine.
        """
        # getset and inout just change things simply from a get to a set routine.
        inout = "in"
        if getset == "get":
            inout = "out"

        if isinstance(t, ft.Type):
            this = 'this'
        else:
            this = 'dummy_this'

        self.write('subroutine %s%s__array_%sitem__%s(%s, i, %s)' %
                   (self.prefix, t.name, getset, el.name, this, el.name))
        self.indent()
        self.write()
        extra_uses = {}
        if isinstance(t, ft.Module):
            extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)]
        elif isinstance(t, ft.Type):
            mod = self.types[t.name].mod_name
            extra_uses[mod] = [t.name]
        mod = self.types[el.type].mod_name
        el_tname = ft.strip_type(el.type)
        if mod in extra_uses:
            extra_uses[mod].append(el_tname)
        else:
            extra_uses[mod] = [el_tname]
        self.write_uses_lines(el, extra_uses)
        self.write('implicit none')
        self.write()
        if isinstance(t, ft.Type):
            self.write_type_lines(t.name)
        self.write_type_lines(el.type)

        self.write('integer, intent(in) :: %s(%d)' % (this, sizeof_fortran_t))
        if isinstance(t, ft.Type):
            self.write('type(%s_ptr_type) :: this_ptr' % t.name)
            array_name = 'this_ptr%%p%%%s' % el.name
        else:
            array_name = '%s_%s' % (t.name, el.name)
        self.write('integer, intent(in) :: i')
        self.write('integer, intent(%s) :: %s(%d)' %
                   (inout, el.name, sizeof_fortran_t))
        self.write('type(%s_ptr_type) :: %s_ptr' %
                   (ft.strip_type(el.type), el.name))
        self.write()
        if isinstance(t, ft.Type):
            self.write('this_ptr = transfer(this, this_ptr)')

        if 'allocatable' in el.attributes:
            self.write('if (allocated(%s)) then' % array_name)
            self.indent()

        self.write('if (i < 1 .or. i > size(%s)) then' % array_name)
        self.indent()
        self.write('call %s("array index out of range")' % self.abort_func)
        self.dedent()
        self.write('else')
        self.indent()

        if getset == "get":
            self.write('%s_ptr%%p => %s(i)' % (el.name, array_name))
            self.write('%s = transfer(%s_ptr,%s)' %
                       (el.name, el.name, el.name))
        else:
            self.write('%s_ptr = transfer(%s,%s_ptr)' %
                       (el.name, el.name, el.name))
            self.write('%s(i) = %s_ptr%%p' % (array_name, el.name))

        self.dedent()
        self.write('endif')

        if 'allocatable' in el.attributes:
            self.dedent()
            self.write('else')
            self.indent()
            self.write('call %s("derived type array not allocated")' %
                       self.abort_func)
            self.dedent()
            self.write('end if')

        self.dedent()
        self.write('end subroutine %s%s__array_%sitem__%s' %
                   (self.prefix, t.name, getset, el.name))
        self.write()
Example #26
0
    def _write_array_getset_item(self, t, el, sizeof_fortran_t, getset):
        """
        Write a subroutine to get/set items in a derived-type array.

        Parameters
        ----------
        t : `fortran.Type` node
            Derived-type node of the parse tree.

        el : `fortran.Element` node
            An element of a module which is derived-type array

        sizeof_fortan_t : `int`
            The size, in bytes, of a pointer to a fortran derived type ??

        getset : `str` {``"get"``,``"set"``}
            String indicating whether to write a get routine, or a set routine.
        """
        # getset and inout just change things simply from a get to a set routine.
        inout = "in"
        if getset == "get":
            inout = "out"

        if isinstance(t, ft.Type):
            this = self.prefix + 'this'
        else:
            this = 'dummy_this'
        safe_i = self.prefix + 'i'  # YANN: i could be in the "uses" clauses
        # TODO: check if el.orig_name would be needed here instead of el.name
        self.write('subroutine %s%s__array_%sitem__%s(%s, %s, %s)' %
                   (self.prefix, t.name, getset, el.name, this, safe_i,
                    el.name + 'item'))
        self.indent()
        self.write()
        extra_uses = {}
        if isinstance(t, ft.Module):
            extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)]
        elif isinstance(t, ft.Type):
            if 'super-type' in t.doc:
                # YANN: propagate parameter uses
                for use in t.uses:
                    if use[0] in extra_uses and use[1][0] not in extra_uses[
                            use[0]]:
                        extra_uses[use[0]].append(use[1][0])
                    else:
                        extra_uses[use[0]] = [use[1][0]]
            else:
                extra_uses[t.mod_name] = [t.name]
        mod = self.types[el.type].mod_name
        el_tname = ft.strip_type(el.type)
        if mod in extra_uses:
            extra_uses[mod].append(el_tname)
        else:
            extra_uses[mod] = [el_tname]
        self.write_uses_lines(el, extra_uses)
        self.write('implicit none')
        self.write()

        if 'super-type' in t.doc:
            self.write_super_type_lines(t)

        if isinstance(t, ft.Type):
            self.write_type_lines(t.name)
        self.write_type_lines(el.type)

        self.write('integer, intent(in) :: %s(%d)' % (this, sizeof_fortran_t))
        if isinstance(t, ft.Type):
            self.write('type(%s_ptr_type) :: this_ptr' % t.name)
            array_name = 'this_ptr%%p%%%s' % el.name
        else:
            array_name = '%s_%s' % (t.name, el.name)
        self.write('integer, intent(in) :: %s' % (safe_i))
        self.write('integer, intent(%s) :: %s(%d)' %
                   (inout, el.name + 'item', sizeof_fortran_t))
        self.write('type(%s_ptr_type) :: %s_ptr' %
                   (ft.strip_type(el.type), el.name))
        self.write()
        if isinstance(t, ft.Type):
            self.write('this_ptr = transfer(%s, this_ptr)' % (this))

        if 'allocatable' in el.attributes:
            self.write('if (allocated(%s)) then' % array_name)
            self.indent()

        self.write('if (%s < 1 .or. %s > size(%s)) then' %
                   (safe_i, safe_i, array_name))
        self.indent()
        self.write('call %s("array index out of range")' % self.abort_func)
        self.dedent()
        self.write('else')
        self.indent()

        if getset == "get":
            self.write('%s_ptr%%p => %s(%s)' % (el.name, array_name, safe_i))
            self.write('%s = transfer(%s_ptr,%s)' %
                       (el.name + 'item', el.name, el.name + 'item'))
        else:
            self.write('%s_ptr = transfer(%s,%s_ptr)' %
                       (el.name, el.name + 'item', el.name))
            self.write('%s(%s) = %s_ptr%%p' % (array_name, safe_i, el.name))

        self.dedent()
        self.write('endif')

        if 'allocatable' in el.attributes:
            self.dedent()
            self.write('else')
            self.indent()
            self.write('call %s("derived type array not allocated")' %
                       self.abort_func)
            self.dedent()
            self.write('end if')

        self.dedent()
        self.write('end subroutine %s%s__array_%sitem__%s' %
                   (self.prefix, t.name, getset, el.name))
        self.write()
Example #27
0
    def _write_array_len(self, t, el, sizeof_fortran_t):
        """
        Write a subroutine which returns the length of a derived-type array

        Parameters
        ----------
        t : `fortran.Type` node or `fortran.Module` node
            Node of the parse tree which contains this derived-type as an element

        el : `fortran.Element` node
            An element of a module which is derived-type array

        sizeof_fortan_t : `int`
            The size, in bytes, of a pointer to a fortran derived type ??
        """
        if isinstance(t, ft.Type):
            this = self.prefix + 'this'
        else:
            this = 'dummy_this'
        safe_n = self.prefix + 'n'  # YANN: "n" could be in the "uses"

        self.write('subroutine %s%s__array_len__%s(%s, %s)' %
                   (self.prefix, t.name, el.name, this, safe_n))
        self.indent()
        self.write()
        extra_uses = {}
        if isinstance(t, ft.Module):
            extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)]
        elif isinstance(t, ft.Type):
            if 'super-type' in t.doc:
                # YANN: propagate parameter uses
                for use in t.uses:
                    if use[0] in extra_uses and use[1][0] not in extra_uses[
                            use[0]]:
                        extra_uses[use[0]].append(use[1][0])
                    else:
                        extra_uses[use[0]] = [use[1][0]]
            else:
                extra_uses[self.types[t.name].mod_name] = [t.name]

        mod = self.types[el.type].mod_name
        el_tname = ft.strip_type(el.type)
        if mod in extra_uses:
            extra_uses[mod].append(el_tname)
        else:
            extra_uses[mod] = [el_tname]
        self.write_uses_lines(el, extra_uses)
        self.write('implicit none')
        self.write()
        if 'super-type' in t.doc:
            self.write_super_type_lines(t)

        # Check if the type has recursive definition:
        same_type = (ft.strip_type(t.name) == ft.strip_type(el.type))
        if isinstance(t, ft.Type):
            self.write_type_lines(t.name)
        self.write_type_lines(el.type, same_type)
        self.write('integer, intent(out) :: %s' % (safe_n))
        self.write('integer, intent(in) :: %s(%d)' % (this, sizeof_fortran_t))
        if isinstance(t, ft.Type):
            self.write('type(%s_ptr_type) :: this_ptr' % t.name)
            self.write()
            self.write('this_ptr = transfer(%s, this_ptr)' % (this))
            array_name = 'this_ptr%%p%%%s' % el.name
        else:
            array_name = '%s_%s' % (t.name, el.name)

        if 'allocatable' in el.attributes:
            self.write('if (allocated(%s)) then' % array_name)
            self.indent()

        self.write('%s = size(%s)' % (safe_n, array_name))

        if 'allocatable' in el.attributes:
            self.dedent()
            self.write('else')
            self.indent()
            self.write('%s = 0' % (safe_n))
            self.dedent()
            self.write('end if')

        self.dedent()
        self.write('end subroutine %s%s__array_len__%s' %
                   (self.prefix, t.name, el.name))
        self.write()
Example #28
0
    def _write_array_getset_item(self, t, el, sizeof_fortran_t, getset):
        """
        Write a subroutine to get/set items in a derived-type array.
        
        Parameters
        ----------
        t : `fortran.Type` node
            Derived-type node of the parse tree.
            
        el : `fortran.Element` node
            An element of a module which is derived-type array
            
        sizeof_fortan_t : `int`
            The size, in bytes, of a pointer to a fortran derived type ??
            
        getset : `str` {``"get"``,``"set"``}
            String indicating whether to write a get routine, or a set routine.
        """
        # getset and inout just change things simply from a get to a set routine.
        inout = "in"
        if getset == "get":
            inout = "out"

        if isinstance(t, ft.Type):
            this = 'this'
        else:
            this = 'dummy_this'

        self.write('subroutine %s%s__array_%sitem__%s(%s, i, %s)' % (self.prefix, t.name,
                                                                     getset, el.name,
                                                                     this,
                                                                     el.name))
        self.indent()
        self.write()
        extra_uses = {}
        if isinstance(t, ft.Module):
            extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)]
        elif isinstance(t, ft.Type):
            mod = self.types[t.name].mod_name
            extra_uses[mod] = [t.name]
        mod = self.types[el.type].mod_name
        el_tname = ft.strip_type(el.type)
        if mod in extra_uses:
            extra_uses[mod].append(el_tname)
        else:
            extra_uses[mod] = [el_tname]
        self.write_uses_lines(el, extra_uses)
        self.write('implicit none')
        self.write()
        if isinstance(t, ft.Type):
            self.write_type_lines(t.name)
        self.write_type_lines(el.type)

        self.write('integer, intent(in) :: %s(%d)' % (this, sizeof_fortran_t))
        if isinstance(t, ft.Type):
            self.write('type(%s_ptr_type) :: this_ptr' % t.name)
            array_name = 'this_ptr%%p%%%s' % el.name
        else:
            array_name = '%s_%s' % (t.name, el.name)
        self.write('integer, intent(in) :: i')
        self.write('integer, intent(%s) :: %s(%d)' % (inout, el.name, sizeof_fortran_t))
        self.write('type(%s_ptr_type) :: %s_ptr' % (ft.strip_type(el.type), el.name))
        self.write()
        if isinstance(t, ft.Type):
            self.write('this_ptr = transfer(this, this_ptr)')

        if 'allocatable' in el.attributes:
            self.write('if (allocated(%s)) then' % array_name)
            self.indent()

        self.write('if (i < 1 .or. i > size(%s)) then' % array_name)
        self.indent()
        self.write('call %s("array index out of range")' % self.abort_func)
        self.dedent()
        self.write('else')
        self.indent()

        if getset == "get":
            self.write('%s_ptr%%p => %s(i)' % (el.name, array_name))
            self.write('%s = transfer(%s_ptr,%s)' % (el.name, el.name, el.name))
        else:
            self.write('%s_ptr = transfer(%s,%s_ptr)' % (el.name, el.name, el.name))
            self.write('%s(i) = %s_ptr%%p' % (array_name, el.name))

        self.dedent()
        self.write('endif')

        if 'allocatable' in el.attributes:
            self.dedent()
            self.write('else')
            self.indent()
            self.write('call %s("derived type array not allocated")' % self.abort_func)
            self.dedent()
            self.write('end if')

        self.dedent()
        self.write('end subroutine %s%s__array_%sitem__%s' % (self.prefix, t.name,
                                                              getset, el.name))
        self.write()
Example #29
0
    def _write_array_len(self, t, el, sizeof_fortran_t):
        """
        Write a subroutine which returns the length of a derived-type array
        
        Parameters
        ----------
        t : `fortran.Type` node or `fortran.Module` node
            Node of the parse tree which contains this derived-type as an element
            
        el : `fortran.Element` node
            An element of a module which is derived-type array
            
        sizeof_fortan_t : `int`
            The size, in bytes, of a pointer to a fortran derived type ??
        """
        if isinstance(t, ft.Type):
            this = 'this'
        else:
            this = 'dummy_this'

        self.write('subroutine %s%s__array_len__%s(%s, n)' % (self.prefix, t.name, el.name, this))
        self.indent()
        self.write()
        extra_uses = {}
        if isinstance(t, ft.Module):
            extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)]
        elif isinstance(t, ft.Type):
            extra_uses[self.types[t.name].mod_name] = [t.name]
        mod = self.types[el.type].mod_name
        el_tname = ft.strip_type(el.type)
        if mod in extra_uses:
            extra_uses[mod].append(el_tname)
        else:
            extra_uses[mod] = [el_tname]
        self.write_uses_lines(el, extra_uses)
        self.write('implicit none')
        self.write()
        if isinstance(t, ft.Type):
            self.write_type_lines(t.name)
        self.write_type_lines(el.type)
        self.write('integer, intent(out) :: n')
        self.write('integer, intent(in) :: %s(%d)' % (this, sizeof_fortran_t))
        if isinstance(t, ft.Type):
            self.write('type(%s_ptr_type) :: this_ptr' % t.name)
            self.write()
            self.write('this_ptr = transfer(this, this_ptr)')
            array_name = 'this_ptr%%p%%%s' % el.name
        else:
            array_name = '%s_%s' % (t.name, el.name)

        if 'allocatable' in el.attributes:
            self.write('if (allocated(%s)) then' % array_name)
            self.indent()

        self.write('n = size(%s)' % array_name)

        if 'allocatable' in el.attributes:
            self.dedent()
            self.write('else')
            self.indent()
            self.write('n = 0')
            self.dedent()
            self.write('end if')

        self.dedent()
        self.write('end subroutine %s%s__array_len__%s' % (self.prefix, t.name, el.name))
        self.write()
Example #30
0
    def _write_scalar_wrapper(self, t, el, sizeof_fortran_t, getset):
        """
        Write get/set routines for scalar elements of derived-types and modules
        
        Parameters
        ----------
        t : `fortran.Type` node or `fortran.Module` node
            Node of the parse tree which contains this derived-type as an element
            
        el : `fortran.Element` node
            An element of a module which is derived-type array
            
        sizeof_fortan_t : `int`
            The size, in bytes, of a pointer to a fortran derived type ??
            
        getset : `str` {``"get"``,``"set"``}
            String indicating whether to write a get routine, or a set routine.
        """

        logging.debug('writing %s wrapper for %s.%s' % (getset, t.name, el.name))

        # getset and inout just change things simply from a get to a set routine.
        inout = "in"
        if getset == "get":
            inout = "out"

        if isinstance(t, ft.Type):
            this = 'this, '
        elif isinstance(t, ft.Module):
            this = ''
        else:
            raise ValueError("Don't know how to write scalar wrappers for %s type %s" (t, type(t)))

        # Get appropriate use statements
        extra_uses = {}
        if isinstance(t, ft.Module):
            extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)]
        elif isinstance(t, ft.Type):
            extra_uses[self.types[t.name].mod_name] = [t.name]
        if el.type.startswith('type'):
            mod = self.types[el.type].mod_name
            el_tname = ft.strip_type(el.type)
            if mod in extra_uses:
                extra_uses[mod].append(el_tname)
            else:
                extra_uses[mod] = [el_tname]

        # If the var that is get/set has the same name as something in uses, then append _
        localvar = el.name
        if localvar in getattr(el, "uses", []) or localvar in extra_uses:
            localvar += "_"

        self.write('subroutine %s%s__%s__%s(%s%s)' % (self.prefix, t.name,
                                                    getset, el.name, this, localvar))
        self.indent()

        self.write_uses_lines(el, extra_uses)

        self.write('implicit none')
        if isinstance(t, ft.Type):
            self.write_type_lines(t.name)

        if el.type.startswith('type'):
            self.write_type_lines(el.type)

        if isinstance(t, ft.Type):
            self.write('integer, intent(in)   :: this(%d)' % sizeof_fortran_t)
            self.write('type(%s_ptr_type) :: this_ptr' % t.name)

        # Return/set by value
        attributes = [attr for attr in el.attributes if attr not in
                      ['pointer', 'allocatable', 'public', 'parameter', 'save'] ]

        if el.type.startswith('type'):
            # For derived types elements, treat as opaque reference
            self.write('integer, intent(%s) :: %s(%d)' % (inout, localvar, sizeof_fortran_t))

            self.write('type(%s_ptr_type) :: %s_ptr' % (ft.strip_type(el.type), el.name))
            self.write()
            if isinstance(t, ft.Type):
                self.write('this_ptr = transfer(this, this_ptr)')
            if getset == "get":
                if isinstance(t, ft.Type):
                    self.write('%s_ptr%%p => this_ptr%%p%%%s' % (el.name, el.name))
                else:
                    self.write('%s_ptr%%p => %s_%s' % (el.name, t.name, el.name))
                self.write('%s = transfer(%s_ptr,%s)' % (localvar, el.name, localvar))
            else:
                self.write('%s_ptr = transfer(%s,%s_ptr)' % (el.name,
                                                             localvar,
                                                             el.name))
                if isinstance(t, ft.Type):
                    self.write('this_ptr%%p%%%s = %s_ptr%%p' % (el.name, el.name))
                else:
                    self.write('%s_%s = %s_ptr%%p' % (t.name, el.name, el.name))
        else:
            if attributes != []:
                self.write('%s, %s, intent(%s) :: %s' % (el.type,
                                                         ','.join(attributes),
                                                         inout, localvar))
            else:
                self.write('%s, intent(%s) :: %s' % (el.type, inout, localvar))
            self.write()
            if isinstance(t, ft.Type):
                self.write('this_ptr = transfer(this, this_ptr)')
            if getset == "get":
                if isinstance(t, ft.Type):
                    self.write('%s = this_ptr%%p%%%s' % (localvar, el.name))
                else:
                    self.write('%s = %s_%s' % (localvar, t.name, el.name))
            else:
                if isinstance(t, ft.Type):
                    self.write('this_ptr%%p%%%s = %s' % (el.name, localvar))
                else:
                    self.write('%s_%s = %s' % (t.name, el.name, localvar))
        self.dedent()
        self.write('end subroutine %s%s__%s__%s' % (self.prefix, t.name, getset,
                                                    el.name))
        self.write()
Example #31
0
    def visit_Procedure(self, node):

        logging.info('PythonWrapperGenerator visiting routine %s' % node.name)
        if 'classmethod' in node.attributes:
            self.write_classmethod(node)
        elif 'constructor' in node.attributes:
            self.write_constructor(node)
        elif 'destructor' in node.attributes:
            self.write_destructor(node)
        else:
            dct = dict(
                func_name=node.name,
                method_name=hasattr(node, 'method_name') and node.method_name
                or node.name,
                prefix=self.prefix,
                mod_name=self.f90_mod_name,
                py_arg_names=', '.join([
                    arg.py_name + py_arg_value(arg) for arg in node.arguments
                ]),
                f90_arg_names=', '.join([
                    '%s=%s' % (arg.name, arg.py_value)
                    for arg in node.arguments
                ]),
                call='')

            if isinstance(node, ft.Function):
                dct['result'] = ', '.join(
                    [ret_val.name for ret_val in node.ret_val])
                dct['call'] = '%(result)s = ' % dct

            if not self.make_package and node.mod_name is not None and node.type_name is None:
                # procedures outside of derived types become static methods
                self.write('@staticmethod')
            self.write("def %(method_name)s(%(py_arg_names)s):" % dct)
            self.indent()
            self.write(format_doc_string(node))
            for arg in node.arguments:
                if 'optional' in arg.attributes and '._handle' in arg.py_value:
                    dct['f90_arg_names'] = dct['f90_arg_names'].replace(
                        arg.py_value,
                        ('None if %(arg_py_name)s is None else %(arg_py_name)s._handle'
                         ) % {'arg_py_name': arg.py_name})
            call_line = '%(call)s%(mod_name)s.%(prefix)s%(func_name)s(%(f90_arg_names)s)' % dct
            self.write(call_line)

            if isinstance(node, ft.Function):
                # convert any derived type return values to Python objects
                for ret_val in node.ret_val:
                    if ret_val.type.startswith('type'):
                        cls_name = normalise_class_name(
                            ft.strip_type(ret_val.type), self.class_names)
                        cls_name = self.py_mod_name + '.' + cls_name
                        cls_name = 'f90wrap.runtime.lookup_class("%s")' % cls_name
                        cls_mod_name = self.types[ft.strip_type(
                            ret_val.type)].mod_name
                        cls_mod_name = self.py_mod_names.get(
                            cls_mod_name, cls_mod_name)
                        # if self.make_package:
                        #     if cls_mod_name != self.current_module:
                        #         self.imports.add((self.py_mod_name + '.' + cls_mod_name, cls_name))
                        # else:
                        #     cls_name = cls_mod_name + '.' + cls_name
                        self.write('%s = %s.from_handle(%s, alloc=True)' %
                                   (ret_val.name, cls_name, ret_val.name))
                self.write('return %(result)s' % dct)

            self.dedent()
            self.write()