Example #1
0
class HasAttributes(object):

    known_attributes = []
    a = AttributeHolder(attributes=[])

    def topyf(self, tab=''):
        s = ''
        for attr in self.a.attributes:
            s += tab + attr + '\n'
        return s

    def update_attributes(self, *attrs):
        attributes = self.a.attributes
        known_attributes = self.known_attributes
        if len(attrs) == 1 and isinstance(attrs[0], (tuple, list)):
            attrs = attrs[0]
        for attr in attrs:
            uattr = attr.upper()
            if uattr not in attributes:
                if isinstance(known_attributes, (list, tuple)):
                    if uattr not in known_attributes:
                        self.warning('unknown attribute %r' % (attr))
                elif not known_attributes(uattr):
                    self.warning('unknown attribute %r' % (attr))
                attributes.append(uattr)
            else:
                self.warning('multiple specification of attribute %r' % (attr))
        return
Example #2
0
class HasUseStmt(object):

    a = AttributeHolder(use={}, use_provides={})

    def get_entity(self, name):
        for modname, modblock in list(self.top.a.module.items()):
            for stmt in modblock.content:
                if getattr(stmt, 'name', '') == name:
                    return stmt
        return

    def topyf(self, tab='  '):
        sys.stderr.write('HasUseStmt.topyf not implemented\n')
        return ''
Example #3
0
class HasTypeDecls(object):

    a = AttributeHolder(type_decls={})

    def topyf(self, tab=''):
        s = ''
        for name, stmt in list(self.a.type_decls.items()):
            s += stmt.topyf(tab='  ' + tab)
        return s

    def get_type_decl_by_kind(self, kind):
        type_decls = self.a.type_decls
        type_decl = type_decls.get(kind, None)
        if type_decl is None:
            return self.get_entity(kind)
        return type_decl
Example #4
0
class AccessSpecs(object):

    a = AttributeHolder(private_id_list=[], public_id_list=[])

    def topyf(self, tab='  '):
        private_list = self.a.private_id_list
        public_list = self.a.public_id_list
        lines = []
        if '' in private_list:
            lines.append(tab + 'PRIVATE\n')
        if '' in public_list:
            lines.append(tab + 'PUBLIC\n')
        for a in private_list:
            if not a:
                continue
            lines.append(tab + 'PRIVATE :: %s\n' % (a))
        for a in public_list:
            if not a:
                continue
            lines.append(tab + 'PUBLIC :: %s\n' % (a))
        return ''.join(lines)
Example #5
0
class HasVariables(object):

    a = AttributeHolder(
        variables={},
        variable_names=[]  # defines the order of declarations
    )

    def get_variable_by_name(self, name):
        variables = self.a.variables
        if name in variables:
            var = variables[name]
        else:
            var = variables[name] = Variable(self, name)
            self.a.variable_names.append(name)
        return var

    def topyf(self, tab='', only_variables=None):
        s = ''
        if only_variables is None:
            only_variables = list(self.a.variables.keys())
        for name in only_variables:
            var = self.a.variables[name]
            s += tab + str(var) + '\n'
        return s
Example #6
0
class HasImplicitStmt(object):
    '''
    Class encapsulating information about any Implicit statements
    contained within a scoping block.
    '''
    a = AttributeHolder(implicit_rules={})

    def get_type_by_name(self, name):
        '''
        Returns an object of the correct type (Integer or Real) using
        Fortran's implicit typing rules for the supplied variable name.

        :param str name: The variable name.
        :returns: Object describing the variable.
        :rtype: Either :py:class:`fparser.one.typedecl_statements.Real` \
                or :py:class:`fparser.one.typedecl_statements.Integer`.

        '''
        # The implicit_rules dict is populated by the analyze() method
        # of one.typedecl_statements.Implicit
        implicit_rules = self.a.implicit_rules
        if implicit_rules is None:
            raise AnalyzeError('Implicit rules mapping is null '
                               'while getting %r type' % (name))
        line = name[0].lower()
        if line in implicit_rules:
            return implicit_rules[line]
        # default rules:
        if line in 'ijklmn':
            line = 'default_integer'
        else:
            line = 'default_real'
        var = implicit_rules.get(line, None)
        if var is None:
            if line[8:] == 'real':
                implicit_rules[line] = var = Real(self, self.item.copy('real'))
            else:
                implicit_rules[line] = var = Integer(self,
                                                     self.item.copy('integer'))
        return var

    def topyf(self, tab='  '):
        '''
        Constructs a pyf representation of this class.

        :param str tab: White space to prepend to output.
        :returns: pyf code for this implicit statement.
        :rtype: str
        '''
        implicit_rules = self.a.implicit_rules
        if implicit_rules is None:
            return tab + 'IMPLICIT NONE\n'
        # Construct a dict where the keys are types and the items are
        # the list of initial letters mapped to that type
        items = {}
        for char, itype in list(implicit_rules.items()):
            if char.startswith('default'):
                continue
            type_str = itype.tostr()
            if type_str in items:
                items[type_str].append(char)
            else:
                items[type_str] = [char]
        if not items:
            return tab + '! default IMPLICIT rules apply\n'
        stmt = 'IMPLICIT'
        impl_list = []
        for itype, letter_list in list(items.items()):
            letter_list.sort()
            impl_list.append(itype + ' (%s)' % (', '.join(letter_list)))
        stmt += ' ' + ', '.join(impl_list)
        return tab + stmt + '\n'
Example #7
0
class SubProgramStatement(BeginStatement, ProgramBlock, HasImplicitStmt,
                          HasAttributes, HasUseStmt, HasVariables,
                          HasTypeDecls, AccessSpecs):
    """
    [<prefix>] <FUNCTION|SUBROUTINE> <name> [( <args> )] [<suffix>]
    """

    a = AttributeHolder(internal_subprogram={})
    known_attributes = ['RECURSIVE', 'PURE', 'ELEMENTAL']

    def process_item(self):
        clsname = self.__class__.__name__.lower()
        item = self.item
        line = item.get_line()
        m = self.match(line)
        i = line.lower().find(clsname)
        assert i != -1, repr((clsname, line))
        self.prefix = line[:i].rstrip()
        self.name = line[i:m.end()].lstrip()[len(clsname):].strip()
        line = line[m.end():].lstrip()
        args = []
        if line.startswith('('):
            i = line.find(')')
            assert i != -1, repr(line)
            line2 = item.apply_map(line[:i + 1])
            for a in line2[1:-1].split(','):
                a = a.strip()
                if not a:
                    continue
                args.append(a)
            line = line[i + 1:].lstrip()
        suffix = item.apply_map(line)
        self.bind, suffix = parse_bind(suffix, item)
        self.result = None
        if isinstance(self, Function):
            self.result, suffix = parse_result(suffix, item)
            if suffix:
                assert self.bind is None, repr(self.bind)
                self.bind, suffix = parse_result(suffix, item)
            if self.result is None:
                self.result = self.name
        assert not suffix, repr(suffix)
        self.args = args
        self.typedecl = None
        return BeginStatement.process_item(self)

    def tostr(self):
        clsname = self.__class__.__name__.upper()
        s = ''
        if self.prefix:
            s += self.prefix + ' '
        if self.typedecl is not None:
            assert isinstance(self, Function), repr(self.__class__.__name__)
            s += self.typedecl.tostr() + ' '
        s += clsname
        suf = ''
        if self.result and self.result != self.name:
            suf += ' RESULT ( %s )' % (self.result)
        if self.bind:
            suf += ' BIND ( %s )' % (', '.join(self.bind))
        return '%s %s (%s)%s' % (s, self.name, ', '.join(self.args), suf)

    def get_classes(self):
        return f2py_stmt + specification_part + execution_part \
               + internal_subprogram_part

    def analyze(self):
        content = self.content[:]

        if self.prefix:
            self.update_attributes(self.prefix.upper().split())

        variables = self.a.variables
        for a in self.args:
            assert a not in variables
            if is_name(a):
                variables[a] = Variable(self, a)
            elif a == '*':
                variables[a] = Variable(self, a)  # XXX: fix me appropriately
            else:
                message = 'argument must be a name or * but got %r'
                raise AnalyzeError(message % (a))

        if isinstance(self, Function):
            var = variables[self.result] = Variable(self, self.result)
            if self.typedecl is not None:
                var.set_type(self.typedecl)

        while content:
            stmt = content.pop(0)
            if isinstance(stmt, Contains):
                for stmt in filter_stmts(content, SubProgramStatement):
                    stmt.analyze()
                    self.a.internal_subprogram[stmt.name] = stmt
                stmt = content.pop(0)
                while isinstance(stmt, Comment):
                    stmt = content.pop(0)
                assert isinstance(stmt, self.end_stmt_cls), repr(stmt)
            elif isinstance(stmt, self.end_stmt_cls):
                continue
            else:
                if hasattr(stmt, "analyze"):
                    stmt.analyze()
                else:
                    message = 'Failed to parse: {0}'
                    raise AnalyzeError(message.format(str(stmt)))

        if content:
            logger.info('Not analyzed content: %s' % content)
            # self.show_message('Not analyzed content: %s' % content)

        parent_provides = self.parent.get_provides()
        if parent_provides is not None:
            if self.name in parent_provides:
                message = 'module subprogram name conflict with %s, ' \
                          + 'overriding.'
                self.warning(message % (self.name))
            if self.is_public():
                parent_provides[self.name] = self

        if self.is_recursive() and self.is_elemental():
            message = 'C1241 violation: prefix cannot specify both ' \
                      + 'ELEMENTAL and RECURSIVE'
            self.warning(message)
        return

    def topyf(self, tab=''):
        s = tab + self.__class__.__name__.upper()
        s += ' ' + self.name + ' (%s)' % (', '.join(self.args))
        if isinstance(self, Function) and self.result != self.name:
            s += ' RESULT (%s)' % (self.result)
        s += '\n'
        s += HasImplicitStmt.topyf(self, tab=tab + '  ')
        s += AccessSpecs.topyf(self, tab=tab + '  ')
        s += HasTypeDecls.topyf(self, tab=tab + '  ')
        s += HasVariables.topyf(self, tab=tab + '  ', only_variables=self.args)
        s += tab + 'END ' + self.__class__.__name__.upper() \
            + ' ' + self.name + '\n'
        return s

    def is_public(self):
        return not self.is_private()

    def is_private(self):
        return self.parent.check_private(self.name)

    def is_recursive(self):
        return 'RECURSIVE' in self.a.attributes

    def is_pure(self):
        return 'PURE' in self.a.attributes

    def is_elemental(self):
        return 'ELEMENTAL' in self.a.attributes
Example #8
0
class Interface(BeginStatement, HasAttributes, HasImplicitStmt, HasUseStmt,
                HasModuleProcedures, AccessSpecs):
    """
    INTERFACE [<generic-spec>] | ABSTRACT INTERFACE
    END INTERFACE [<generic-spec>]

    <generic-spec> = <generic-name>
                   | OPERATOR ( <defined-operator> )
                   | ASSIGNMENT ( = )
                   | <dtio-generic-spec>
    <dtio-generic-spec> = READ ( FORMATTED )
                        | READ ( UNFORMATTED )
                        | WRITE ( FORMATTED )
                        | WRITE ( UNFORMATTED )

    """
    modes = ['free', 'fix', 'pyf']
    pattern = r'(interface\s*(\w+\s*\(.*\)|\w*)|abstract\s*interface)\Z'
    match = re.compile(pattern, re.I).match
    end_stmt_cls = EndInterface
    blocktype = 'interface'

    a = AttributeHolder(interface_provides={})

    def get_classes(self):
        line = intrinsic_type_spec + interface_specification
        if self.reader.format.mode == 'pyf':
            return [Subroutine, Function] + line
        return line

    def process_item(self):
        line = self.item.get_line()
        line = self.item.apply_map(line)
        self.isabstract = line.startswith('abstract')
        if self.isabstract:
            self.generic_spec = ''
        else:
            self.generic_spec = line[len(self.blocktype):].strip()
        self.name = self.generic_spec  # XXX
        return BeginStatement.process_item(self)

    def tostr(self):
        if self.isabstract:
            return 'ABSTRACT INTERFACE'
        return 'INTERFACE ' + str(self.generic_spec)

    def analyze(self):
        content = self.content[:]

        while content:
            stmt = content.pop(0)
            if isinstance(stmt, self.end_stmt_cls):
                break
            stmt.analyze()
        if content:
            logger.info('Not analyzed content: %s' % content)
            # self.show_message('Not analyzed content: %s' % content)

        if self.name in self.parent.a.variables:
            var = self.parent.a.variables.pop(self.name)
            self.update_attributes(var.attributes)

        if isinstance(self.parent, Module):  # XXX
            parent_interface = self.parent.get_interface()
            if self.name in parent_interface:
                p = parent_interface[self.name]
                last = p.content.pop()
                assert isinstance(last, EndInterface), repr(last.__class__)
                p.content += self.content
                p.update_attributes(self.a.attributes)
            else:
                parent_interface[self.name] = self
            return

    def topyf(self, tab=''):
        s = tab + self.tostr() + '\n'
        s += HasImplicitStmt.topyf(self, tab=tab + '  ')
        s += HasAttributes.topyf(self, tab=tab + '  ')
        s += HasUseStmt.topyf(self, tab=tab + '  ')
        s += tab + 'END' + self.tostr() + '\n'
        return s
Example #9
0
class Module(BeginStatement, HasAttributes, HasImplicitStmt, HasUseStmt,
             HasVariables, HasTypeDecls, AccessSpecs):
    """
    MODULE <name>
     ..
    END [MODULE [name]]
    """
    match = re.compile(r'module\s*\w+\Z', re.I).match
    end_stmt_cls = EndModule

    a = AttributeHolder(
        module_subprogram={},
        module_provides={},  # all symbols that are public and
        # so can be imported via USE
        # statement by other blocks
        module_interface={})

    known_attributes = ['PUBLIC', 'PRIVATE']

    def get_classes(self):
        return access_spec + specification_part + module_subprogram_part

    def process_item(self):
        name = self.item.get_line().replace(' ', '')
        name = name[len(self.blocktype):].strip()
        self.name = name
        return BeginStatement.process_item(self)

    def get_provides(self):
        return self.a.module_provides

    def get_interface(self):
        return self.a.module_interface

    def analyze(self):
        content = self.content[:]

        while content:
            stmt = content.pop(0)
            if isinstance(stmt, Contains):
                for stmt in filter_stmts(content, SubProgramStatement):
                    stmt.analyze()
                    self.a.module_subprogram[stmt.name] = stmt
                stmt = content.pop(0)
                while isinstance(stmt, Comment):
                    stmt = content.pop(0)
                if not isinstance(stmt, EndModule):
                    stmt.error('Expected END MODULE statement (analyzer).')
                continue
            stmt.analyze()

        if content:
            logger.info('Not analyzed content: %s' % content)
            # self.show_message('Not analyzed content: %s' % content)

        module_provides = self.a.module_provides
        for name, var in list(self.a.variables.items()):
            if var.is_public():
                if name in module_provides:
                    message = 'module data object name conflict with %s, ' \
                              + 'overriding.'
                    self.warning(message % (name))
                module_provides[name] = var

        return

    def topyf(self, tab=''):
        s = tab + 'MODULE ' + self.name + '\n'
        s += HasImplicitStmt.topyf(self, tab=tab + '  ')
        s += AccessSpecs.topyf(self, tab=tab + '  ')
        s += HasAttributes.topyf(self, tab=tab + '  ')
        s += HasTypeDecls.topyf(self, tab=tab + '  ')
        s += HasVariables.topyf(self, tab=tab + '  ')
        for name, stmt in list(self.a.module_interface.items()):
            s += stmt.topyf(tab=tab + '    ')
        s += tab + '  CONTAINS\n'
        for name, stmt in list(self.a.module_subprogram.items()):
            s += stmt.topyf(tab=tab + '    ')
        s += tab + 'END MODULE ' + self.name + '\n'
        return s

    def check_private(self, name):
        if name in self.a.public_id_list:
            return False
        if name in self.a.private_id_list:
            return True
        if '' in self.a.public_id_list:
            return False
        if '' in self.a.private_id_list:
            return True
        # todo: handle generic-spec-s in id-lists.
        return
Example #10
0
class BeginSource(BeginStatement):
    """
    Fortran source content.
    """
    match = staticmethod(lambda s: True)
    end_stmt_cls = EndSource
    a = AttributeHolder(
        module={},
        external_subprogram={},
        blockdata={},
    )

    #    def tofortran(self, isfix=None):
    #        if isfix:
    #            tab = 'C'
    #        else:
    #            tab = self.get_indent_tab(isfix=isfix) + '!'
    #        return BeginStatement.tofortran(self, isfix=isfix)

    def tostr(self):
        return None

    def process_item(self):
        self.name = self.reader.name
        self.top = self
        self.fill(end_flag=True)
        return

    def analyze(self):
        for stmt in self.content:
            if isinstance(stmt, Module):
                stmt.analyze()
                self.a.module[stmt.name] = stmt
            elif isinstance(stmt, SubProgramStatement):
                stmt.analyze()
                self.a.external_subprogram[stmt.name] = stmt
            elif isinstance(stmt, BlockData):
                stmt.analyze()
                self.a.blockdata[stmt.name] = stmt
            else:
                stmt.analyze()
        return

    def get_classes(self):
        if self.reader.format.is_pyf:
            return [PythonModule] + program_unit
        return program_unit

    def process_subitem(self, item):
        # MAIN block does not define start/end line conditions,
        # so it should never end until all lines are read.
        # However, sometimes F77 programs lack the PROGRAM statement,
        # and here we fix that:
        if self.reader.format.is_f77:
            line = item.get_line()
            if line == 'end':
                message = item.reader.format_message(
                    'WARNING',
                    'assuming the end of undefined PROGRAM statement',
                    item.span[0], item.span[1])
                logger.warning(message)
                # print >> sys.stderr, message
                p = Program(self)
                p.content.extend(self.content)
                p.content.append(EndProgram(p, item))
                self.content[:] = [p]
                return
        return BeginStatement.process_subitem(self, item)

    def topyf(self, tab=''):  # XXXX
        s = ''
        for name, stmt in list(self.a.module.items()):
            s += stmt.topyf(tab=tab)
        for name, stmt in list(self.a.external_subprogram.items()):
            s += stmt.topyf(tab=tab)
        for name, stmt in list(self.a.blockdata.items()):
            s += stmt.topyf(tab=tab)
        return s
Example #11
0
class HasModuleProcedures(object):

    a = AttributeHolder(module_procedures=[])
Example #12
0
class Type(BeginStatement, HasVariables, HasAttributes, AccessSpecs):
    """
    TYPE [[, <typ-attr-spec-list>] ::] <type-name> [( <type-param-name-list> )]
    <typ-attr-spec> = <access-spec> | EXTENDS ( <parent-type-name> )
                      | ABSTRACT | BIND(C)
    """
    match = re.compile(r'type\b\s*').match
    end_stmt_cls = EndType

    a = AttributeHolder(
        extends=None,
        parameters={},
        component_names=[],  # Order for sequence types
        components={})
    pattern = r'\A(PUBLIC|PRIVATE|SEQUENCE|ABSTRACT|BIND\s*\(.*\))\Z'
    known_attributes = re.compile(pattern, re.I).match

    def process_item(self):
        line = self.item.get_line()[4:].lstrip()
        if line.startswith('('):
            self.isvalid = False
            return
        specs = []
        i = line.find('::')
        if i != -1:
            for s in line[:i].split(','):
                s = s.strip()
                if s:
                    specs.append(s)
            line = line[i + 2:].lstrip()
        self.specs = specs
        i = line.find('(')
        if i != -1:
            self.name = line[:i].rstrip()
            assert line[-1] == ')', repr(line)
            self.params = split_comma(line[i + 1:-1].lstrip())
        else:
            self.name = line
            self.params = []
        if not is_name(self.name):
            self.isvalid = False
            return
        return BeginStatement.process_item(self)

    def tostr(self):
        s = 'TYPE'
        if self.specs:
            s += ', '.join([''] + self.specs) + ' ::'
        s += ' ' + self.name
        if self.params:
            s += ' (' + ', '.join(self.params) + ')'
        return s

    def get_classes(self):
        return [Integer] + private_or_sequence + component_part +\
               type_bound_procedure_part

    def analyze(self):
        for spec in self.specs:
            i = spec.find('(')
            if i != -1:
                assert spec.endswith(')'), repr(spec)
                s = spec[:i].rstrip().upper()
                n = spec[i + 1:-1].strip()
                if s == 'EXTENDS':
                    self.a.extends = n
                    continue
                elif s == 'BIND':
                    args, rest = parse_bind(spec)
                    assert not rest, repr(rest)
                    spec = 'BIND(%s)' % (', '.join(args))
                else:
                    spec = '%s(%s)' % (s, n)
            else:
                spec = spec.upper()
            self.update_attributes(spec)

        component_names = self.a.component_names
        content = self.content[:]
        while content:
            stmt = content.pop(0)
            if isinstance(stmt, self.end_stmt_cls):
                break
            stmt.analyze()

        if content:
            message = 'Not analyzed content: %s' % content
            logging.getLogger(__class__).info(message)

        parameters = self.a.parameters
        components = self.a.components
        component_names = self.a.component_names
        for name in self.a.variable_names:
            var = self.a.variables[name]
            if name in self.params:
                parameters[name] = var
            else:
                component_names.append(name)
                components[name] = var

        self.parent.a.type_decls[self.name] = self

        parent_provides = self.parent.get_provides()
        if parent_provides is not None:
            if self.is_public():
                if self.name in parent_provides:
                    message = 'type declaration name conflict with {}, ' \
                              + 'overriding.'
                    self.warning(message.format(self.name))
                parent_provides[self.name] = self

        return

    def topyf(self, tab=''):
        s = tab + 'TYPE'
        if self.a.extends is not None:
            s += ', EXTENDS(%s) ::' % (self.a.extends)
        s += ' ' + self.name
        if self.a.parameters:
            s += ' (%s)' % (', '.join(self.a.parameters))
        s += '\n'
        s += AccessSpecs.topyf(self, tab=tab + '  ')
        s += HasAttributes.topyf(self, tab=tab + '  ')
        s += HasVariables.topyf(self, tab=tab + '  ')
        s += tab + 'END TYPE ' + self.name + '\n'
        return s

    # Wrapper methods:

    def is_public(self):
        return not self.is_private()

    def is_private(self):
        if 'PUBLIC' in self.a.attributes:
            return False
        if 'PRIVATE' in self.a.attributes:
            return True
        return self.parent.check_private(self.name)