示例#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
示例#2
0
class HasUseStmt(object):

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

    def get_entity(self, name):
        for modname, modblock in 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 ''
示例#3
0
class HasImplicitStmt(object):

    a = AttributeHolder(implicit_rules={})

    def get_type_by_name(self, name):
        implicit_rules = self.a.implicit_rules
        if implicit_rules is None:
            raise AnalyzeError, 'Implicit rules mapping is null while getting %r type' % (
                name)
        l = name[0].lower()
        if l in implicit_rules:
            return implicit_rules[l]
        # default rules:
        if l in 'ijklmn':
            l = 'default_integer'
        else:
            l = 'default_real'
        t = implicit_rules.get(l, None)
        if t is None:
            if l[8:] == 'real':
                implicit_rules[l] = t = Real(self, self.item.copy('real'))
            else:
                implicit_rules[l] = t = Integer(self,
                                                self.item.copy('integer'))
        return t

    def topyf(self, tab='  '):
        implicit_rules = self.a.implicit_rules
        if implicit_rules is None:
            return tab + 'IMPLICIT NONE\n'
        items = {}
        for c, t in implicit_rules.items():
            if c.startswith('default'):
                continue
            st = t.tostr()
            if st in items:
                items[st].append(c)
            else:
                items[st] = [c]
        if not items:
            return tab + '! default IMPLICIT rules apply\n'
        s = 'IMPLICIT'
        ls = []
        for st, l in items.items():
            l.sort()
            ls.append(st + ' (%s)' % (', '.join(l)))
        s += ' ' + ', '.join(ls)
        return tab + s + '\n'
示例#4
0
class HasTypeDecls(object):

    a = AttributeHolder(type_decls={})

    def topyf(self, tab=''):
        s = ''
        for name, stmt in 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
示例#5
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
        l = []
        if '' in private_list: l.append(tab + 'PRIVATE\n')
        if '' in public_list: l.append(tab + 'PUBLIC\n')
        for a in private_list:
            if not a: continue
            l.append(tab + 'PRIVATE :: %s\n' % (a))
        for a in public_list:
            if not a: continue
            l.append(tab + 'PUBLIC :: %s\n' % (a))
        return ''.join(l)
示例#6
0
class HasVariables:

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

    def get_variable_by_name(self, name):
        variables = self.a.variables
        if variables.has_key(name):
            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 = self.a.variables.keys()
        for name in only_variables:
            var = self.a.variables[name]
            s += tab + str(var) + '\n'
        return s
示例#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, ` 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, ` 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, ` self.bind `
                self.bind, suffix = parse_result(suffix, item)
            if self.result is None:
                self.result = self.name
        assert not suffix, ` 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), ` 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:
                raise AnalyzeError('argument must be a name or * but got %r' %
                                   (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), ` stmt `
            elif isinstance(stmt, self.end_stmt_cls):
                continue
            else:
                stmt.analyze()

        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:
                self.warning(
                    'module subprogram name conflict with %s, overriding.' %
                    (self.name))
            if self.is_public():
                parent_provides[self.name] = self

        if self.is_recursive() and self.is_elemental():
            self.warning(
                'C1241 violation: prefix cannot specify both ELEMENTAL and RECURSIVE'
            )
        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
示例#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']
    match = re.compile(
        r'(interface\s*(\w+\s*\(.*\)|\w*)|abstract\s*interface)\Z', re.I).match
    end_stmt_cls = EndInterface
    blocktype = 'interface'

    a = AttributeHolder(interface_provides={})

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

    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 get_provides(self):
    #    return self.a.interface_provides

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

        while content:
            stmt = content.pop(0)
            if isinstance(stmt, self.end_stmt_cls):
                break
            stmt.analyze()
            #assert isinstance(stmt, SubProgramStatement),`stmt.__class__.__name__`
        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), ` 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
示例#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(' ',
                                            '')[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 self.a.variables.items():
            if var.is_public():
                if name in module_provides:
                    self.warning(
                        'module data object name conflict with %s, overriding.'
                        % (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 self.a.module_interface.items():
            s += stmt.topyf(tab=tab + '    ')
        s += tab + '  CONTAINS\n'
        for name, stmt in 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
示例#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 tab + BeginStatement.tofortran(self, isfix=isfix)

    def tostr(self):
        return self.blocktype.upper() + ' ' + self.name

    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.ispyf:
            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.isf77:
            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 self.a.module.items():
            s += stmt.topyf(tab=tab)
        for name, stmt in self.a.external_subprogram.items():
            s += stmt.topyf(tab=tab)
        for name, stmt in self.a.blockdata.items():
            s += stmt.topyf(tab=tab)
        return s
示例#11
0
class HasModuleProcedures(object):

    a = AttributeHolder(module_procedures=[])
示例#12
0
class Type(BeginStatement, HasVariables, HasAttributes, AccessSpecs):
    """
    TYPE [ [ , <type-attr-spec-list>] :: ] <type-name> [ ( <type-param-name-list> ) ]
    <type-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=[],  # specifies component order for sequence types
        components={})
    known_attributes = re.compile(
        r'\A(PUBLIC|PRIVATE|SEQUENCE|ABSTRACT|BIND\s*\(.*\))\Z', 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] == ')', ` 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(')'), ` 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, ` 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:
            logging.info('Not analyzed content: %s' % content)
            # self.show_message('Not analyzed content: %s' % content)

        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:
                    self.warning(
                        'type declaration name conflict with %s, overriding.' %
                        (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 get_bit_size(self, _cache={}):
        try:
            return _cache[id(self)]
        except KeyError:
            s = 0
            for name, var in self.a.components.items():
                s += var.get_bit_size()
            _cache[id(self)] = s
        return s

    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)