示例#1
0
 def __init__(self, name, ddts=None, logger=None):
     "Our dict is DDT definition headers, key is type"
     self._name = '{}_ddt_lib'.format(name)
     self._ddt_fields = {}  # DDT field to DDT access map
     self._max_mod_name_len = 0
     super(DDTLibrary, self).__init__()
     if ddts is None:
         ddts = list()
     elif not isinstance(ddts, list):
         ddts = [ddts]
     # End if
     # Add all the DDT headers, then process
     for ddt in ddts:
         if not isinstance(ddt, MetadataSection):
             errmsg = 'Invalid DDT metadata type, {}'
             raise ParseInternalError(errmsg.format(type(ddt)))
         # End if
         if not ddt.header_type == 'ddt':
             errmsg = 'Metadata table header is for a {}, should be DDT'
             raise ParseInternalError(errmsg.format(ddt.header_type))
         # End if
         if ddt.title in self:
             errmsg = "Duplicate DDT, {}, found{}, original{}"
             ctx = context_string(ddt.source.context)
             octx = context_string(self[ddt.title].source.context)
             raise CCPPError(errmsg.format(ddt.title, ctx, octx))
         # End if
         if logger is not None:
             lmsg = 'Adding DDT {} to {}'
             logger.debug(lmsg.format(ddt.title, self.name))
         # End if
         self[ddt.title] = ddt
         dlen = len(ddt.module)
         if dlen > self._max_mod_name_len:
             self._max_mod_name_len = dlen
示例#2
0
 def add_variable(self,
                  newvar,
                  exists_ok=False,
                  gen_unique=False,
                  adjust_intent=False):
     """Add <newvar> if it does not conflict with existing entries.
     For the host model, this includes entries in used DDT variables.
     If <exists_ok> is True, attempting to add an identical copy is okay.
     If <gen_unique> is True, a new local_name will be created if a
     local_name collision is detected.
     if <adjust_intent> is True, adjust conflicting intents to inout."""
     standard_name = newvar.get_prop_value('standard_name')
     cvar = self.find_variable(standard_name=standard_name, any_scope=False)
     if cvar is None:
         # Check the DDT dictionary
         cvar = self.__ddt_dict.find_variable(standard_name=standard_name,
                                              any_scope=False)
     # end if
     if cvar and (not exists_ok):
         emsg = "Attempt to add duplicate host model variable, {}{}."
         emsg += "\nVariable originally defined{}"
         ntx = context_string(newvar.context)
         ctx = context_string(cvar.context)
         raise CCPPError(emsg.format(standard_name, ntx, ctx))
     # end if
     # No collision, proceed normally
     super(HostModel, self).add_variable(newvar=newvar,
                                         exists_ok=exists_ok,
                                         gen_unique=gen_unique,
                                         adjust_intent=False)
示例#3
0
 def get_default_val(self, prop_dict, context=None):
     if self._default_fn is not None:
         return self._default_fn(prop_dict, context)
     elif self._default is not None:
         return self._default
     else:
         ctxt = context_string(context)
         raise CCPPError('No default for variable property {}{}'.format(self.name, ctxt))
示例#4
0
def dims_comp(mheader, mvar, fvar, title, logger, case_sensitive=False):
    ###############################################################################
    "Compare the dimensions attribute of two variables"
    errors = ''
    mdims = mvar.get_dimensions()
    fdims = mheader.convert_dims_to_standard_names(fvar, logger=logger)
    comp = len(mdims) == len(fdims)
    if not comp:
        errmsg = 'Error: rank mismatch in {}/{} ({} != {}){}'
        stdname = mvar.get_prop_value('standard_name')
        ctx = context_string(mvar.context)
        errors = add_error(
            errors, errmsg.format(title, stdname, len(mdims), len(fdims), ctx))
    # end if
    if comp:
        # Now, compare the dims
        for dim_ind, mdim in enumerate(mdims):
            if ':' in mdim:
                mdim = ':'.join([x.strip() for x in mdim.split(':')])
            # end if
            fdim = fdims[dim_ind].strip()
            if ':' in fdim:
                fdim = ':'.join([x.strip() for x in fdim.split(':')])
            # end if
            if not case_sensitive:
                mdim = mdim.lower()
                fdim = fdim.lower()
            # end if
            # Naked colon is okay for Fortran side
            comp = fdim in (':', fdim)
            if not comp:
                errmsg = 'Error: dim {} mismatch ({} != {}) in {}/{}{}'
                stdname = mvar.get_prop_value('standard_name')
                ctx = context_string(mvar.context)
                errmsg = errmsg.format(dim_ind + 1, mdim, fdims[dim_ind],
                                       title, stdname, ctx)
                errors = add_error(errors, errmsg)
            # end if
        # end for
    # end if
    return errors
示例#5
0
def default_kind_val(prop_dict, context=None):
########################################################################
    """Choose a default kind based on a variable's type
    >>> default_kind_val({'type':'REAL'})
    'kind_phys'
    >>> default_kind_val({'type':'complex'})
    'kind_phys'
    >>> default_kind_val({'type':'double precision'})
    'kind_phys'
    >>> default_kind_val({'type':'integer'})
    ''
    >>> default_kind_val({'type':'character'})
    ''
    >>> default_kind_val({'type':'logical'})
    ''
    >>> default_kind_val({'local_name':'foo'}) #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    CCPPError: No type to find default kind for foo
    >>> default_kind_val({}) #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    CCPPError: No type to find default kind
    >>> default_kind_val({'local_name':'foo'}, context=ParseContext(linenum=3, filename='foo.F90')) #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    CCPPError: No type to find default kind for foo at foo.F90:3
    >>> default_kind_val({}, context=ParseContext(linenum=3, filename='foo.F90')) #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    CCPPError: No type to find default kind at foo.F90:3
    """
    if 'type' in prop_dict:
        vtype = prop_dict['type'].lower()
        if vtype == 'real':
            kind = 'kind_phys'
        elif vtype == 'complex':
            kind = 'kind_phys'
        elif FORTRAN_DP_RE.match(vtype) is not None:
            kind = 'kind_phys'
        else:
            kind = ''
        # End if
    else:
        kind = ''
        if 'local_name' in prop_dict:
            lname = ' {}'.format(prop_dict['local_name'])
        else:
            lname = ''
        # End if
        ctxt = context_string(context)
        raise CCPPError('No type to find default kind for {}{}'.format(lname, ctxt))
    # End if
    return kind
示例#6
0
 def check_ddt_type(self, var, header, lname=None):
     """If <var> is a DDT, check to make sure it is in this DDT library.
     If not, raise an exception.
     """
     if var.is_ddt():
         # Make sure we know this DDT type
         vtype = var.get_prop_value('type')
         if vtype not in self:
             if lname is None:
                 lname = var.get_prop_value('local_name')
             # End if
             errmsg = 'Variable {} is of unknown type ({}) in {}'
             ctx = context_string(var.context)
             raise CCPPError(errmsg.format(lname, vtype, header.title, ctx))
示例#7
0
 def collect_ddt_fields(self, var_dict, var, run_env, ddt=None):
     """Add all the reachable fields from DDT variable <var> of type,
     <ddt> to <var_dict>. Each field is added as a VarDDT.
     """
     if ddt is None:
         vtype = var.get_prop_value('type')
         if vtype in self:
             ddt = self[vtype]
         else:
             lname = var.get_prop_value('local_name')
             ctx = context_string(var.context)
             errmsg = "Variable, {}, is not a known DDT{}"
             raise ParseInternalError(errmsg.format(lname, ctx))
         # End if
     # End if
     for dvar in ddt.variable_list():
         subvar = VarDDT(dvar, var, self.run_env)
         dvtype = dvar.get_prop_value('type')
         if (dvar.is_ddt()) and (dvtype in self):
             # If DDT in our library, we need to add sub-fields recursively.
             subddt = self[dvtype]
             self.collect_ddt_fields(var_dict, subvar, run_env, ddt=subddt)
         else:
             # add_variable only checks the current dictionary. For a
             # DDT, the variable also cannot be in our parent dictionaries.
             stdname = dvar.get_prop_value('standard_name')
             pvar = var_dict.find_variable(standard_name=stdname,
                                           any_scope=True)
             if pvar:
                 emsg = "Attempt to add duplicate DDT sub-variable, {}{}."
                 emsg += "\nVariable originally defined{}"
                 ntx = context_string(dvar.context)
                 ctx = context_string(pvar.context)
                 raise CCPPError(emsg.format(stdname, ntx, ctx))
             # end if
             # Add this intrinsic to <var_dict>
             var_dict.add_variable(subvar, run_env)
示例#8
0
 def find_loop_subst(self, standard_name, any_scope=True, context=None):
     """If <standard_name> is of the form <standard_name>_extent and that
     variable is not in the dictionary, substitute a tuple of variables,
     (<standard_name>_begin, <standard_name>_end), if those variables are
     in the dictionary.
     If <standard_name>_extent *is* present, return that variable as a
     range, (__var_one, <standard_name>_extent)
     In other cases, return None
     """
     loop_var = VarDictionary.loop_subst_match(standard_name)
     logger_str = None
     if loop_var is not None:
         # Let us see if we can fix a loop variable
         dict_var = self.find_variable(standard_name,
                                       any_scope=any_scope, loop_subst=False)
         if dict_var is not None:
             my_var = (VarDictionary.__var_one, dict_var)
             if self._logger is not None:
                 logger_str = "loop_subst: found {}{}".format(standard_name, context_string(context))
             # End if
         else:
             my_vars = [self.find_variable(x) for x in loop_var]
             if None not in my_vars:
                 my_var = tuple(my_vars)
                 if self._logger is not None:
                     names = [x.get_prop_value('local_name') for x in my_vars]
                     logger_str = "loop_subst: {} ==> (){}".format(standard_name, ', '.join(names), context_string(context))
                 # End if
             else:
                 if self._logger is not None:
                     logger_str = "loop_subst: {} ==> ({}, {}) FAILED{}".format(standard_name, beg_name, end_name, context_string(context))
                 # End if
                 my_var = None
             # End if
         # End if
     else:
         if self._logger is not None:
             logger_str = "loop_subst: {} is not a loop variable{}".format(standard_name, context_string(context))
         # End if
         my_var = None
     # End if
     if logger_str is not None:
         self._logger.debug(logger_str)
     # End if
     return my_var
示例#9
0
def standard_name_to_long_name(prop_dict, context=None):
########################################################################
    """Translate a standard_name to its default long_name
    >>> standard_name_to_long_name({'standard_name':'cloud_optical_depth_layers_from_0p55mu_to_0p99mu'})
    'Cloud optical depth layers from 0.55mu to 0.99mu'
    >>> standard_name_to_long_name({'local_name':'foo'}) #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    CCPPError: No standard name to convert foo to long name
    >>> standard_name_to_long_name({}) #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    CCPPError: No standard name to convert to long name
    >>> standard_name_to_long_name({'local_name':'foo'}, context=ParseContext(linenum=3, filename='foo.F90')) #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    CCPPError: No standard name to convert foo to long name at foo.F90:3
    >>> standard_name_to_long_name({}, context=ParseContext(linenum=3, filename='foo.F90')) #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    CCPPError: No standard name to convert to long name at foo.F90:3
    """
    # We assume that standar_name has been checked for validity
    # Make the first char uppercase and replace each underscore with a space
    if 'standard_name' in prop_dict:
        standard_name = prop_dict['standard_name']
        if len(standard_name) > 0:
            long_name = standard_name[0].upper() + re.sub("_", " ", standard_name[1:])
        else:
            long_name = ''
        # End if
        # Next, substitute a decimal point for the p in [:digit]p[:digit]
        match = real_subst_re.match(long_name)
        while match is not None:
            long_name = match.group(1) + '.' + match.group(2)
            match = real_subst_re.match(long_name)
        # End while
    else:
        long_name = ''
        if 'local_name' in prop_dict:
            lname = ' {}'.format(prop_dict['local_name'])
        else:
            lname = ''
        # End if
        ctxt = context_string(context)
        raise CCPPError('No standard name to convert{} to long name{}'.format(lname, ctxt))
    # End if
    return long_name
示例#10
0
def parse_program(pobj, statements, logger=None):
    """Parse a Fortran PROGRAM and return any leftover statements
    and metadata tables encountered in the PROGRAM."""
    # The first statement should be a program statement, grab the name
    pmatch = _PROGRAM_RE.match(statements[0])
    if pmatch is None:
        raise ParseSyntaxError('PROGRAM statement', statements[0])
    # End if
    prog_name = pmatch.group(1)
    pobj.enter_region('PROGRAM', region_name=prog_name, nested_ok=False)
    if logger is not None:
        ctx = context_string(pobj, nodir=True)
        msg = "Parsing Fortran program, {}{}"
        logger.debug(msg.format(prog_name, ctx))
    # End if
    # After the program name is the specification part
    statements, mtables = parse_specification(pobj, statements[1:],
                                              prog_name=prog_name,
                                              logger=logger)
    # We really cannot have tables inside a program's executable section
    # Just read until end
    statements = read_statements(pobj, statements)
    inprogram = True
    while inprogram and (statements is not None):
        while len(statements) > 0:
            statement = statements.pop(0)
            # End program
            pmatch = _ENDPROGRAM_RE.match(statement)
            if pmatch is not None:
                prog_name = pmatch.group(1)
                pobj.leave_region('PROGRAM', region_name=prog_name)
                inprogram = False
            # End if
        # End while
        if inprogram and (len(statements) == 0):
            statements = read_statements(pobj)
        # End if
    # End while
    return statements, mtables
示例#11
0
def var_comp(prop_name, mvar, fvar, title, case_sensitive=False):
    ###############################################################################
    "Compare a property between two variables"
    errors = ''
    mprop = mvar.get_prop_value(prop_name)
    fprop = fvar.get_prop_value(prop_name)
    if not case_sensitive:
        if isinstance(mprop, str):
            mprop = mprop.lower()
        # end if
        if isinstance(fprop, str):
            fprop = fprop.lower()
        # end if
    # end if
    comp = mprop == fprop
    if not comp:
        errmsg = '{} mismatch ({} != {}) in {}{}'
        ctx = context_string(mvar.context)
        errors = add_error(errors,
                           errmsg.format(prop_name, mprop, fprop, title, ctx))
    # end if
    return errors
示例#12
0
def parse_preamble_data(statements, pobj, spec_name, endmatch, logger):
    """Parse module variables or DDT definitions from a module preamble
    or parse program variables from the beginning of a program.
    """
    inspec = True
    mheaders = list()
    var_dict = VarDictionary(spec_name)
    psrc = ParseSource(spec_name, 'MODULE', pobj)
    active_table = None
    if logger is not None:
        ctx = context_string(pobj, nodir=True)
        msg = "Parsing preamble variables of {}{}"
        logger.debug(msg.format(spec_name, ctx))
    # End if
    while inspec and (statements is not None):
        while len(statements) > 0:
            statement = statements.pop(0)
            # End program or module
            pmatch = endmatch.match(statement)
            asmatch = _ARG_TABLE_START_RE.match(statement)
            type_def = fortran_type_definition(statement)
            if asmatch is not None:
                active_table = asmatch.group(1)
            elif (pmatch is not None) or is_contains_statement(statement,
                                                               inspec):
                # We are done with the specification
                inspec = False
                # Put statement back so caller knows where we are
                statements.insert(0, statement)
                # Add the header (even if we found no variables)
                mheader = MetadataTable(table_name_in=spec_name,
                                        table_type_in='module',
                                        module=spec_name,
                                        var_dict=var_dict, logger=logger)
                mheaders.append(mheader)
                if logger is not None:
                    ctx = context_string(pobj, nodir=True)
                    msg = 'Adding header {}{}'
                    logger.debug(msg.format(mheader.table_name, ctx))
                break
            elif ((type_def is not None) and
                  (type_def[0].lower() == active_table.lower())):
                # Put statement back so caller knows where we are
                statements.insert(0, statement)
                statements, ddt = parse_type_def(statements, type_def,
                                                 spec_name, pobj, logger)
                if ddt is None:
                    ctx = context_string(pobj, nodir=True)
                    msg = "No DDT found at '{}'{}"
                    raise CCPPError(msg.format(statement, ctx))
                # End if
                mheaders.append(ddt)
                if logger is not None:
                    ctx = context_string(pobj, nodir=True)
                    msg = 'Adding DDT {}{}'
                    logger.debug(msg.format(ddt.table_name, ctx))
                # End if
                active_table = None
            elif active_table is not None:
                # We should have a variable definition to add
                if ((not is_comment_statement(statement)) and
                    (not parse_use_statement(statement, logger)) and
                    (active_table.lower() == spec_name.lower())):
                    dvars = parse_fortran_var_decl(statement, psrc,
                                                   logger=logger)
                    for var in dvars:
                        var_dict.add_variable(var)
                    # End for
                # End if
            # End if (else we are not in an active table so just skip)
        # End while
        if inspec and (len(statements) == 0):
            statements = read_statements(pobj)
        # End if
    # End while
    return statements, mheaders
示例#13
0
def parse_specification(pobj, statements, mod_name=None,
                        prog_name=None, logger=None):
    """Parse specification part of a module or (sub)program"""
    if (mod_name is not None) and (prog_name is not None):
        raise ParseInternalError("<mod_name> and <prog_name> cannot both be used")
    # end if
    if mod_name is not None:
        spec_name = mod_name
        endmatch = _ENDMODULE_RE
        inmod = True
    elif prog_name is not None:
        spec_name = prog_name
        endmatch = _ENDPROGRAM_RE
        inmod = False
    else:
        raise ParseInternalError("One of <mod_name> or <prog_name> must be used")
    # End if
    if logger is not None:
        ctx = context_string(pobj, nodir=True)
        msg = "Parsing specification of {}{}"
        logger.debug(msg.format(spec_name, ctx))
    # End if

    inspec = True
    mtables = list()
    while inspec and (statements is not None):
        while len(statements) > 0:
            statement = statements.pop(0)
            # End program or module
            pmatch = endmatch.match(statement)
            asmatch = _ARG_TABLE_START_RE.match(statement)
            if pmatch is not None:
                # We never found a contains statement
                inspec = False
                break
            elif asmatch is not None:
                # Put table statement back to re-read
                statements.insert(0, statement)
                statements, new_tbls = parse_preamble_data(statements,
                                                           pobj, spec_name,
                                                           endmatch, logger)
                for tbl in new_tbls:
                    title = tbl.table_name
                    if title in mtables:
                        errmsg = duplicate_header(mtables[title], tbl)
                        raise CCPPError(errmsg)
                    # end if
                    if logger is not None:
                        ctx = tbl.start_context()
                        mtype = tbl.table_type
                        msg = "Adding metadata from {}, {}{}"
                        logger.debug(msg.format(mtype, title, ctx))
                    # End if
                    mtables.append(tbl)
                # End if
                inspec = pobj.in_region('MODULE', region_name=mod_name)
                break
            elif is_contains_statement(statement, inmod):
                inspec = False
                break
            # End if
        # End while
        if inspec and (len(statements) == 0):
            statements = read_statements(pobj)
        # End if
    # End while
    return statements, mtables
示例#14
0
def parse_module(pobj, statements, logger=None):
    """Parse a Fortran MODULE and return any leftover statements
    and metadata tables encountered in the MODULE."""
    # The first statement should be a module statement, grab the name
    pmatch = _MODULE_RE.match(statements[0])
    if pmatch is None:
        raise ParseSyntaxError('MODULE statement', statements[0])
    # End if
    mod_name = pmatch.group(1)
    pobj.enter_region('MODULE', region_name=mod_name, nested_ok=False)
    if logger is not None:
        ctx = context_string(pobj, nodir=True)
        msg = "Parsing Fortran module, {}{}"
        logger.debug(msg.format(mod_name, ctx))
    # End if
    # After the module name is the specification part
    statements, mtables = parse_specification(pobj, statements[1:], mod_name=mod_name, logger=logger)
    # Look for metadata tables
    statements = read_statements(pobj, statements)
    inmodule = pobj.in_region('MODULE', region_name=mod_name)
    active_table = None
    while inmodule and (statements is not None):
        while statements:
            statement = statements.pop(0)
            # End module
            pmatch = _ENDMODULE_RE.match(statement)
            asmatch = _ARG_TABLE_START_RE.match(statement)
            if asmatch is not None:
                active_table = asmatch.group(1)
            elif pmatch is not None:
                mod_name = pmatch.group(1)
                pobj.leave_region('MODULE', region_name=mod_name)
                inmodule = False
                break
            elif active_table is not None:
                statements, mheader = parse_scheme_metadata(statements, pobj,
                                                            mod_name,
                                                            active_table,
                                                            logger)
                if mheader is not None:
                    title = mheader.table_name
                    if title in mtables:
                        errmsg = duplicate_header(mtables[title], mheader)
                        raise CCPPError(errmsg)
                    # end if
                    if logger is not None:
                        mtype = mheader.table_type
                        ctx = mheader.start_context()
                        msg = "Adding metadata from {}, {}{}"
                        logger.debug(msg.format(mtype, title, ctx))
                    # End if
                    mtables.append(mheader)
                # End if
                active_table = None
                inmodule = pobj.in_region('MODULE', region_name=mod_name)
                break
            # End if
        # End while
        if inmodule and (statements is not None) and (len(statements) == 0):
            statements = read_statements(pobj)
        # End if
    # End while
    return statements, mtables
示例#15
0
 def __init__(self, prop_dict, source, invalid_ok=False, logger=None):
     """NB: invalid_ok=True is dangerous because it allows creation
     of a Var object with invalid properties.
     In order to prevent silent failures, invalid_ok requires a logger
     in order to take effect."""
     if source.type is 'SCHEME':
         required_props = Var.__required_var_props
         master_propdict = Var.__var_propdict
     else:
         required_props = Var.__required_spec_props
         master_propdict = Var.__spec_propdict
     # End if
     self._source = source
     # Grab a frozen copy of the context
     self._context = ParseContext(context=source.context)
     # First, check the input
     if 'ddt_type' in prop_dict:
         # Special case to bypass normal type rules
         if 'type' not in prop_dict:
             prop_dict['type'] = prop_dict['ddt_type']
         # End if
         if 'units' not in prop_dict:
             prop_dict['units'] = ""
         # End if
         prop_dict['kind'] = prop_dict['ddt_type']
         del prop_dict['ddt_type']
     # End if
     for key in prop_dict:
         if Var.get_prop(key) is None:
             raise ParseSyntaxError("Invalid metadata variable property, '{}'".format(key), context=self.context)
         # End if
     # End for
     # Make sure required properties are present
     for propname in required_props:
         if propname not in prop_dict:
             if invalid_ok and (logger is not None):
                 ctx = context_string(self.context)
                 logger.warning("Required property, '{}', missing{}".format(propname, ctx))
             else:
                 raise ParseSyntaxError("Required property, '{}', missing".format(propname), context=self.context)
             # End if
         # End if
     # End for
     # Check for any mismatch
     if ('constant' in prop_dict) and ('intent' in prop_dict):
         if prop_dict['intent'].lower() != 'in':
             if invalid_ok and (logger is not None):
                 ctx = context_string(self.context)
                 logger.warning("{} is marked constant but is intent {}{}".format(prop_dict['local_name'], prop_dict['intent'], ctx))
             else:
                 raise ParseSyntaxError("{} is marked constant but is intent {}".format(prop_dict['local_name'], prop_dict['intent']), context=self.context)
             # End if
         # End if
     # End if
     # Steal dict from caller
     self._prop_dict = prop_dict
     # Fill in default values for missing properties
     for propname in master_propdict:
         if (propname not in prop_dict) and master_propdict[propname].optional:
             self._prop_dict[propname] = master_propdict[propname].get_default_val(self._prop_dict, context=self.context)
         # End if
     # End for
     # Make sure all the variable values are valid
     try:
         for prop in self._prop_dict.keys():
             check = Var.get_prop(prop).valid_value(self._prop_dict[prop],
                                                    error=True)
         # End for
     except CCPPError as cp:
         if invalid_ok and (logger is not None):
             ctx = context_string(self.context)
             logger.warning("{}: {}{}".format(self._prop_dict['local_name'], cp, ctx))
         else:
             raise ParseSyntaxError("{}: {}".format(self._prop_dict['local_name'], cp),
                                    context=self.context)
示例#16
0
def parse_fortran_var_decl(line, source, logger=None):
    ########################################################################
    """Parse a Fortran variable declaration line and return a list of
    Var objects representing the variables declared on <line>.
    >>> _var_id_re_.match('foo') #doctest: +ELLIPSIS
    <_sre.SRE_Match object at 0x...>
    >>> _var_id_re_.match("foo()")

    >>> _var_id_re_.match('foo').group(1)
    'foo'
    >>> _var_id_re_.match('foo').group(2)

    >>> _var_id_re_.match("foo(bar)").group(1)
    'foo'
    >>> _var_id_re_.match("foo(bar)").group(2)
    '(bar)'
    >>> _var_id_re_.match("foo(bar)").group(2)
    '(bar)'
    >>> _var_id_re_.match("foo(bar, baz)").group(2)
    '(bar, baz)'
    >>> _var_id_re_.match("foo(bar : baz)").group(2)
    '(bar : baz)'
    >>> _var_id_re_.match("foo(bar:)").group(2)
    '(bar:)'
    >>> _var_id_re_.match("foo(: baz)").group(2)
    '(: baz)'
    >>> _var_id_re_.match("foo(:, :,:)").group(2)
    '(:, :,:)'
    >>> _var_id_re_.match("foo(8)").group(2)
    '(8)'
    >>> _var_id_re_.match("foo(::,a:b,a:,:b)").group(2)
    '(::,a:b,a:,:b)'
    >>> parse_fortran_var_decl("integer :: foo", ParseSource('foo.F90', 'MODULE', ParseContext()))[0].get_prop_value('local_name')
    'foo'
    >>> parse_fortran_var_decl("integer :: foo = 0", ParseSource('foo.F90', 'MODULE', ParseContext()))[0].get_prop_value('local_name')
    'foo'
    >>> parse_fortran_var_decl("integer :: foo", ParseSource('foo.F90', 'MODULE', ParseContext()))[0].get_prop_value('optional')
    False
    >>> parse_fortran_var_decl("integer, optional :: foo", ParseSource('foo.F90', 'MODULE', ParseContext()))[0].get_prop_value('optional')
    'True'
    >>> parse_fortran_var_decl("integer, dimension(:) :: foo", ParseSource('foo.F90', 'MODULE', ParseContext()))[0].get_prop_value('dimensions')
    '(:)'
    >>> parse_fortran_var_decl("integer, dimension(:) :: foo(bar)", ParseSource('foo.F90', 'MODULE', ParseContext()))[0].get_prop_value('dimensions')
    '(bar)'
    >>> parse_fortran_var_decl("integer, dimension(:) :: foo(:,:), baz", ParseSource('foo.F90', 'MODULE', ParseContext()))[0].get_prop_value('dimensions')
    '(:,:)'
    >>> parse_fortran_var_decl("integer, dimension(:) :: foo(:,:), baz", ParseSource('foo.F90', 'MODULE', ParseContext()))[1].get_prop_value('dimensions')
    '(:)'
    >>> parse_fortran_var_decl("real (kind=kind_phys), pointer :: phii  (:,:) => null()   !< interface geopotential height", ParseSource('foo.F90', 'MODULE', ParseContext()))[0].get_prop_value('dimensions')
    '(:,:)'
    >>> parse_fortran_var_decl("real(kind=kind_phys), dimension(im, levs, ntrac), intent(in) :: qgrs", ParseSource('foo.F90', 'MODULE', ParseContext()))[0].get_prop_value('dimensions')
    '(im, levs, ntrac)'
    >>> parse_fortran_var_decl("character(len=*), intent(out) :: errmsg", ParseSource('foo.F90', 'MODULE', ParseContext()))[0].get_prop_value('local_name')
    'errmsg'
    """
    context = source.context
    sline = line.strip()
    # Strip comments first
    if '!' in sline:
        sline = sline[0:sline.index('!')].rstrip()
    # End if
    tobject = Ftype_factory(sline, context)
    newvars = list()
    if tobject is not None:
        varprops = sline[tobject.type_len:].strip()
        def_dims = None  # Default dimensions
        intent = None
        dimensions = None
        if '::' in varprops:
            elements = varprops.split('::')
            varlist = elements[1].strip()
            varprops = Ftype.parse_attr_specs(elements[0].strip(), context)
            for prop in varprops:
                if prop[0:6] == 'intent':
                    intent = prop[6:].strip()[1:-1].strip()
                elif prop[0:9:] == 'dimension':
                    dimensions = prop[9:].strip()
                # End if
            # End for
        else:
            # No attr_specs
            varlist = varprops
            varprops = list()
        # End if
        # Create Vars from these pieces
        # We may need to reassemble multi-dimensional specs
        vars = Ftype.reassemble_parens(varlist, 'variable_list', context)
        for var in vars:
            prop_dict = {}
            if '=' in var:
                # We do not care about initializers
                var = var[0:var.rindex('=')].rstrip()
            # End if
            # Scan <var> and gather variable pieces
            inchar = None  # Character context
            var_len = len(var)
            ploc = var.find('(')
            if ploc < 0:
                varname = var.strip()
                dimspec = None
            else:
                varname = var[0:ploc].strip()
                begin, end = check_balanced_paren(var)
                if (begin < 0) or (end < 0):
                    if logger is not None:
                        ctx = context_string(context)
                        logger.warning(
                            "WARNING: Invalid variable declaration, {}{}".
                            format(var, ctx))
                    else:
                        raise ParseSyntaxError('variable declaration',
                                               token=var,
                                               context=context)
                    # End if
                else:
                    dimspec = var[begin:end + 1]
                # End if
            # End if
            prop_dict['local_name'] = varname
            prop_dict['standard_name'] = Ftype.unique_standard_name()
            prop_dict['units'] = ''
            prop_dict['type'] = tobject.typestr
            if tobject.kind is not None:
                prop_dict['kind'] = tobject.kind
            # End if
            if 'optional' in varprops:
                prop_dict['optional'] = 'True'
            # End if
            if 'allocatable' in varprops:
                prop_dict['allocatable'] = 'True'
            # End if
            if intent is not None:
                prop_dict['intent'] = intent
            # End if
            if dimspec is not None:
                prop_dict['dimensions'] = dimspec
            elif dimensions is not None:
                prop_dict['dimensions'] = dimensions
            else:
                prop_dict['dimensions'] = '()'
            # End if
            # XXgoldyXX: I am nervous about allowing invalid Var objects here
            newvars.append(
                Var(prop_dict,
                    source,
                    invalid_ok=(logger is not None),
                    logger=logger))
        # End for
    # No else (not a variable declaration)
    # End if
    return newvars
示例#17
0
 def find_dimension_subst(self, standard_name, any_scope=True, context=None):
     """If <standard_name> is of the form <standard_name>_loop_extent
     attempt to find a variable of the form <standard_name>_dimension
     and return that. If such a variable is not found, raise an exception.
     If <standard_name> is not of the form <standard_name>_extent, return
     None.
     """
     loop_var = standard_name in VarDictionary.__ccpp_dim_subst__
     logger_str = None
     if loop_var:
         # Let us see if we can replace the variable
         dim_name = VarDictionary.__ccpp_dim_subst__[standard_name]
         my_var = self.find_variable(dim_name, any_scope=any_scope)
         if my_var is None:
             raise CCPPError("Dimension variable, {} not found{}".format(dim_name, context_string(context)))
         # End if
     else:
         my_var = None
     # End if
     return my_var
示例#18
0
def parse_scheme_metadata(statements, pobj, spec_name, table_name, logger):
    "Parse dummy argument information from a subroutine"
    psrc = None
    mheader = None
    var_dict = None
    scheme_name = None
    # Find the subroutine line, should be first executable statement
    inpreamble = False
    insub = True
    if logger is not None:
        ctx = context_string(pobj, nodir=True)
        msg = "Parsing specification of {}{}"
        logger.debug(msg.format(table_name, ctx))
    # End if
    ctx = context_string(pobj) # Save initial context with directory
    vdict = None # Initialized when we parse the subroutine arguments
    while insub and (statements is not None):
        while statements:
            statement = statements.pop(0)
            smatch = _SUBROUTINE_RE.match(statement)
            esmatch = _END_SUBROUTINE_RE.match(statement)
            pmatch = _ENDMODULE_RE.match(statement)
            asmatch = _ARG_TABLE_START_RE.match(statement)
            if asmatch is not None:
                # We have run off the end of something, hope that is okay
                # Put this statement back for the caller to deal with
                statements.insert(0, statement)
                insub = False
                break
            # End if
            if pmatch is not None:
                # We have run off the end of the module, hope that is okay
                pobj.leave_region('MODULE', region_name=spec_name)
                insub = False
                break
            # End if
            if smatch is not None:
                scheme_name = smatch.group(1)
                inpreamble = scheme_name.lower() == table_name.lower()
                if inpreamble:
                    if smatch.group(2) is not None:
                        smstr = smatch.group(2).strip()
                        if len(smstr) > 0:
                            smlist = smstr.strip().split(',')
                        else:
                            smlist = list()
                        # End if
                        scheme_args = [x.strip().lower() for x in smlist]
                    else:
                        scheme_args = list()
                    # End if
                    # Create a dict template with all the scheme's arguments
                    # in the correct order
                    vdict = OrderedDict()
                    for arg in scheme_args:
                        if len(arg) == 0:
                            errmsg = 'Empty argument{}'
                            raise ParseInternalError(errmsg.format(pobj))
                        # End if
                        if arg in vdict:
                            errmsg = 'Duplicate dummy argument, {}'
                            raise ParseSyntaxError(errmsg.format(arg),
                                                   context=pobj)
                        # End if
                        vdict[arg] = None
                    # End for
                    psrc = ParseSource(scheme_name, 'scheme', pobj)
                # End if
            elif inpreamble:
                # Process a preamble statement (use or argument declaration)
                if esmatch is not None:
                    inpreamble = False
                    insub = False
                elif ((not is_comment_statement(statement)) and
                      (not parse_use_statement(statement, logger)) and
                      is_dummy_argument_statement(statement)):
                    dvars = parse_fortran_var_decl(statement, psrc,
                                                   logger=logger)
                    for var in dvars:
                        lname = var.get_prop_value('local_name').lower()
                        if lname in vdict:
                            if vdict[lname] is not None:
                                emsg = "Error: duplicate dummy argument, {}"
                                raise ParseSyntaxError(emsg.format(lname),
                                                       context=pobj)
                            # End if
                            vdict[lname] = var
                        else:
                            raise ParseSyntaxError('dummy argument',
                                                   token=lname, context=pobj)
                        # End if
                    # End for
                # End if
            # End if
        # End while
        if insub and (len(statements) == 0):
            statements = read_statements(pobj)
        # End if
    # End while
    # Check for missing declarations
    missing = list()
    if vdict is None:
        errmsg = 'Subroutine, {}, not found{}'
        raise CCPPError(errmsg.format(scheme_name, ctx))
    # End if
    for lname in vdict.keys():
        if vdict[lname] is None:
            missing.append(lname)
        # End if
    # End for
    if len(missing) > 0:
        errmsg = 'Missing local_variables, {} in {}'
        raise CCPPError(errmsg.format(missing, scheme_name))
    # End if
    var_dict = VarDictionary(scheme_name, variables=vdict)
    if (scheme_name is not None) and (var_dict is not None):
        mheader = MetadataTable(table_name_in=scheme_name,
                                table_type_in='scheme', module=spec_name,
                                var_dict=var_dict, logger=logger)
    # End if
    return statements, mheader
示例#19
0
def parse_fortran_var_decl(line, source, run_env):
    ########################################################################
    """Parse a Fortran variable declaration line and return a list of
    Var objects representing the variables declared on <line>.
    >>> _VAR_ID_RE.match('foo') #doctest: +ELLIPSIS
    <re.Match object; span=(0, 3), match='foo'>
    >>> _VAR_ID_RE.match("foo()")

    >>> _VAR_ID_RE.match('foo').group(1)
    'foo'
    >>> _VAR_ID_RE.match('foo').group(2)

    >>> _VAR_ID_RE.match("foo(bar)").group(1)
    'foo'
    >>> _VAR_ID_RE.match("foo(bar)").group(2)
    '(bar)'
    >>> _VAR_ID_RE.match("foo(bar)").group(2)
    '(bar)'
    >>> _VAR_ID_RE.match("foo(bar, baz)").group(2)
    '(bar, baz)'
    >>> _VAR_ID_RE.match("foo(bar : baz)").group(2)
    '(bar : baz)'
    >>> _VAR_ID_RE.match("foo(bar:)").group(2)
    '(bar:)'
    >>> _VAR_ID_RE.match("foo(: baz)").group(2)
    '(: baz)'
    >>> _VAR_ID_RE.match("foo(:, :,:)").group(2)
    '(:, :,:)'
    >>> _VAR_ID_RE.match("foo(8)").group(2)
    '(8)'
    >>> _VAR_ID_RE.match("foo(::,a:b,a:,:b)").group(2)
    '(::,a:b,a:,:b)'
    >>> parse_fortran_var_decl("integer :: foo", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('local_name')
    'foo'
    >>> parse_fortran_var_decl("integer :: foo = 0", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('local_name')
    'foo'
    >>> parse_fortran_var_decl("integer :: foo", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('optional')

    >>> parse_fortran_var_decl("integer, optional :: foo", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('optional')
    'True'
    >>> parse_fortran_var_decl("integer, dimension(:) :: foo", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('dimensions')
    '(:)'
    >>> parse_fortran_var_decl("integer, dimension(:) :: foo(bar)", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('dimensions')
    '(bar)'
    >>> parse_fortran_var_decl("integer, dimension(:) :: foo(:,:), baz", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('dimensions')
    '(:,:)'
    >>> parse_fortran_var_decl("integer, dimension(:) :: foo(:,:), baz", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[1].get_prop_value('dimensions')
    '(:)'
    >>> parse_fortran_var_decl("real (kind=kind_phys), pointer :: phii  (:,:) => null()   !< interface geopotential height", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('dimensions')
    '(:,:)'
    >>> parse_fortran_var_decl("real(kind=kind_phys), dimension(im, levs, ntrac), intent(in) :: qgrs", ParseSource('foo.F90', 'scheme', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('dimensions')
    '(im, levs, ntrac)'
    >>> parse_fortran_var_decl("character(len=*), intent(out) :: errmsg", ParseSource('foo.F90', 'scheme', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('local_name')
    'errmsg'
    >>> parse_fortran_var_decl("character(len=512), intent(out) :: errmsg", ParseSource('foo.F90', 'scheme', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('kind')
    'len=512'
    >>> parse_fortran_var_decl("real(kind_phys), intent(out) :: foo(8)", ParseSource('foo.F90', 'scheme', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('dimensions')
    '(8)'
    >>> parse_fortran_var_decl("real(kind_phys), intent(out) :: foo(8)", ParseSource('foo.F90', 'scheme', ParseContext()), _DUMMY_RUN_ENV)[0].get_dimensions()
    ['8']
    >>> parse_fortran_var_decl("character(len=*), intent(out) :: errmsg", ParseSource('foo.F90', 'module', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('local_name') #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    ParseSyntaxError: Invalid variable declaration, character(len=*), intent(out) :: errmsg, intent not allowed in module variable, in <standard input>

    ## NB: Expressions (including function calls) not currently supported here
    #>>> parse_fortran_var_decl("real(kind_phys), intent(out) :: foo(size(bar))", ParseSource('foo.F90', 'scheme', ParseContext()), _DUMMY_RUN_ENV)[0].get_prop_value('dimensions')
    #'(size(bar))'
    """
    context = source.context
    sline = line.strip()
    # Strip comments first
    if '!' in sline:
        sline = sline[0:sline.index('!')].rstrip()
    # end if
    tobject = ftype_factory(sline, context)
    newvars = list()
    if tobject is not None:
        varprops = sline[tobject.type_len:].strip()
        def_dims = None  # Default dimensions
        intent = None
        dimensions = None
        if '::' in varprops:
            elements = varprops.split('::')
            varlist = elements[1].strip()
            varprops = Ftype.parse_attr_specs(elements[0].strip(), context)
            for prop in varprops:
                if prop[0:6] == 'intent':
                    if source.type != 'scheme':
                        typ = source.type
                        errmsg = 'Invalid variable declaration, {}, intent'
                        errmsg = errmsg + ' not allowed in {} variable'
                        if run_env.logger is not None:
                            ctx = context_string(context)
                            errmsg = "WARNING: " + errmsg + "{}"
                            run_env.logger.warning(
                                errmsg.format(sline, typ, ctx))
                        else:
                            raise ParseSyntaxError(errmsg.format(sline, typ),
                                                   context=context)
                        # end if
                    else:
                        intent = prop[6:].strip()[1:-1].strip()
                    # end if
                elif prop[0:9:] == 'dimension':
                    dimensions = prop[9:].strip()
                # end if
            # end for
        else:
            # No attr_specs
            varlist = varprops
            varprops = list()
        # end if
        # Create Vars from these pieces
        # We may need to reassemble multi-dimensional specs
        var_list = Ftype.reassemble_parens(varlist, 'variable_list', context)
        for var in var_list:
            prop_dict = {}
            if '=' in var:
                # We do not care about initializers
                var = var[0:var.rindex('=')].rstrip()
            # end if
            # Scan <var> and gather variable pieces
            inchar = None  # Character context
            var_len = len(var)
            ploc = var.find('(')
            if ploc < 0:
                varname = var.strip()
                dimspec = None
            else:
                varname = var[0:ploc].strip()
                begin, end = check_balanced_paren(var)
                if (begin < 0) or (end < 0):
                    if run_env.logger is not None:
                        ctx = context_string(context)
                        errmsg = "WARNING: Invalid variable declaration, {}{}"
                        run_env.logger.warning(errmsg.format(var, ctx))
                    else:
                        raise ParseSyntaxError('variable declaration',
                                               token=var,
                                               context=context)
                    # end if
                else:
                    dimspec = var[begin:end + 1]
                # end if
            # end if
            prop_dict['local_name'] = varname
            prop_dict['standard_name'] = unique_standard_name()
            prop_dict['units'] = ''
            if isinstance(tobject, FtypeTypeDecl):
                prop_dict['ddt_type'] = tobject.typestr
            else:
                prop_dict['type'] = tobject.typestr
            # end if
            if tobject.kind() is not None:
                prop_dict['kind'] = tobject.kind()
            # end if
            if 'optional' in varprops:
                prop_dict['optional'] = 'True'
            # end if
            if 'allocatable' in varprops:
                prop_dict['allocatable'] = 'True'
            # end if
            if intent is not None:
                prop_dict['intent'] = intent
            # end if
            if dimspec is not None:
                prop_dict['dimensions'] = dimspec
            elif dimensions is not None:
                prop_dict['dimensions'] = dimensions
            else:
                prop_dict['dimensions'] = '()'
            # end if
            # XXgoldyXX: I am nervous about allowing invalid Var objects here
            # Also, this tends to cause an exception that ends up back here
            # which is not a good idea.
            var = FortranVar(prop_dict, source, run_env)
            newvars.append(var)
        # end for
    # No else (not a variable declaration)
    # end if
    return newvars
示例#20
0
 def __init__(self, meta_tables, name_in, logger):
     self.__name = name_in
     self.__var_locations = {}  # Local name to module map
     self.__loop_vars = None  # Loop control vars in interface calls
     self.__used_variables = None  # Local names which have been requested
     self.__deferred_finds = None  # Used variables that were missed at first
     # First, process DDT headers
     meta_headers = list()
     for sect in [x.sections() for x in meta_tables.values()]:
         meta_headers.extend(sect)
     # end for
     # Initialize our dictionaries
     # Initialize variable dictionary
     super(HostModel, self).__init__(self.name, logger=logger)
     self.__ddt_lib = DDTLibrary(
         '{}_ddts'.format(self.name),
         ddts=[d for d in meta_headers if d.header_type == 'ddt'],
         logger=logger)
     self.__ddt_dict = VarDictionary("{}_ddt_vars".format(self.name),
                                     parent_dict=self,
                                     logger=logger)
     # Now, process the code headers by type
     self.__metadata_tables = meta_tables
     for header in [h for h in meta_headers if h.header_type != 'ddt']:
         title = header.title
         if logger is not None:
             msg = 'Adding {} {} to host model'
             logger.debug(msg.format(header.header_type, title))
         # End if
         if header.header_type == 'module':
             # Set the variable modules
             modname = header.title
             for var in header.variable_list():
                 self.add_variable(var)
                 lname = var.get_prop_value('local_name')
                 self.__var_locations[lname] = modname
                 self.ddt_lib.check_ddt_type(var, header, lname=lname)
                 if var.is_ddt():
                     self.ddt_lib.collect_ddt_fields(self.__ddt_dict, var)
                 # End if
             # End for
         elif header.header_type == 'host':
             if self.__name is None:
                 # Grab the first host name we see
                 self.__name = header.name
             # End if
             for var in header.variable_list():
                 self.add_variable(var)
                 self.ddt_lib.check_ddt_type(var, header)
                 if var.is_ddt():
                     self.ddt_lib.collect_ddt_fields(self.__ddt_dict, var)
                 # End if
             # End for
             loop_vars = header.variable_list(std_vars=False,
                                              loop_vars=True,
                                              consts=False)
             if loop_vars:
                 # loop_vars are part of the host-model interface call
                 # at run time. As such, they override the host-model
                 # array dimensions.
                 self.__loop_vars = VarDictionary(self.name)
             # End if
             for hvar in loop_vars:
                 std_name = hvar.get_prop_value('standard_name')
                 if std_name not in self.__loop_vars:
                     self.__loop_vars.add_variable(hvar)
                 else:
                     ovar = self.__loop_vars[std_name]
                     ctx1 = context_string(ovar.context)
                     ctx2 = context_string(hvar.context)
                     lname1 = ovar.get_prop_value('local_name')
                     lname2 = hvar.get_prop_value('local_name')
                     errmsg = ("Duplicate host loop var for {n}:\n"
                               "  Dup:  {l1}{c1}\n  Orig: {l2}{c2}")
                     raise CCPPError(
                         errmsg.format(n=self.name,
                                       l1=lname1,
                                       c1=ctx1,
                                       l2=lname2,
                                       c2=ctx2))
                 # End if
             # End for
         else:
             errmsg = "Invalid host model metadata header type, {} ({}){}"
             errmsg += "\nType must be 'module' or 'host'"
             ctx = context_string(header.context)
             raise CCPPError(
                 errmsg.format(header.title, header.header_type, ctx))
         # End if
     # End while
     if self.name is None:
         errmsg = 'No name found for host model, add a host metadata entry'
         raise CCPPError(errmsg)
     # End if
     # Finally, turn on the use meter so we know which module variables
     #    to 'use' in a host cap.
     self.__used_variables = set()  # Local names which have been requested
     self.__deferred_finds = set(
     )  # Used variables that were missed at first