示例#1
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
    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).lower()
            elif (pmatch is not None) or is_contains_statement(
                    statement, inspec):
                # We are done with the specification
                inspec = False
                if len(var_dict.variable_list()) > 0:
                    mheader = MetadataHeader(title=spec_name,
                                             type_in='MODULE',
                                             module=spec_name,
                                             var_dict=var_dict,
                                             logger=logger)
                    mheaders.append(mheader)
                # End if
                break
            elif (type_def is not None) and (type_def[0].lower()
                                             == active_table):
                statements, ddt = parse_type_def(statements, type_def,
                                                 spec_name, pobj, logger)
                mheaders.append(ddt)
                active_table = None
            else:
                # We should have a variable definition to add
                if ((not is_comment_statement(statement, logger)) and
                    (not parse_use_statement({}, statement, pobj, logger))
                        and (active_table == spec_name)):
                    vars = parse_fortran_var_decl(statement,
                                                  psrc,
                                                  logger=logger)
                    for var in vars:
                        var_dict.add_variable(var)
                    # End for
                # End if
            # End if
        # End while
        if inspec and (len(statements) == 0):
            statements = read_statements(pobj)
        # End if
    # End while
    return statements, mheaders
 def __init__(self,
              parse_object=None,
              title=None,
              type_in=None,
              module=None,
              var_dict=None,
              property_table=False,
              logger=None):
     self._pobj = parse_object
     """If <parse_object> is not None, initialize from the current file and
     location in <parse_object>.
     If <parse_object> is None, initialize from <title>, <type>, <module>,
     and <var_dict>. Note that if <parse_object> is not None, <title>,
     <type>, <module>, and <var_dict> are ignored.
     """
     if parse_object is None:
         if title is None:
             raise ParseInternalError('MetadataHeader requires a title')
         else:
             self._table_title = title
         # End if
         if type_in is None:
             raise ParseInternalError(
                 'MetadataHeader requires a header type')
         else:
             self._header_type = type
         # End if
         if module is None:
             raise ParseInternalError(
                 'MetadataHeader requires a module name')
         else:
             self._module_name = module
         # End if
         #  Initialize our ParseSource parent
         super(MetadataHeader, self).__init__(self.title, self.header_type,
                                              self._pobj)
         self._variables = VarDictionary(self.title, logger=logger)
         for var in var_dict.variable_list():  # Let this crash if no dict
             self._variables.add_variable(var)
         # End for
     else:
         self.__init_from_file__(parse_object, property_table, logger)
     # End if
     # Categorize the variables
     self._var_intents = {'in': list(), 'out': list(), 'inout': list()}
     for var in self.variable_list():
         intent = var.get_prop_value('intent')
         if intent is not None:
             self._var_intents[intent].append(var)
示例#3
0
def parse_type_def(statements, type_def, mod_name, pobj, logger):
    """Parse a type definition from <statements> and return the
    remaining statements along with a MetadataTable object representing
    the type's variables."""
    psrc = ParseSource(mod_name, 'ddt', pobj)
    seen_contains = False
    mheader = None
    var_dict = VarDictionary(type_def[0])
    inspec = True
    while inspec and (statements is not None):
        while len(statements) > 0:
            statement = statements.pop(0)
            # End program or module
            pmatch = _END_TYPE_RE.match(statement)
            if pmatch is not None:
                # We hit the end of the type, make a header
                mheader = MetadataTable(table_name_in=type_def[0],
                                        table_type_in='ddt',
                                        module=mod_name, var_dict=var_dict,
                                        logger=logger)
                inspec = False
            elif is_contains_statement(statement, inspec):
                seen_contains = True
            elif not seen_contains:
                # Comment of variable
                if ((not is_comment_statement(statement)) and
                    (not parse_use_statement(statement, logger))):
                    dvars = parse_fortran_var_decl(statement, psrc,
                                                   logger=logger)
                    for var in dvars:
                        var_dict.add_variable(var)
                    # End for
                # End if
            else:
                # We are just skipping lines until the end type
                pass
            # End if
        # End while
        if inspec and (len(statements) == 0):
            statements = read_statements(pobj)
        # End if
    # End while
    return statements, mheader
示例#4
0
def parse_type_def(statements, type_def, mod_name, pobj, logger):
    psrc = ParseSource(mod_name, 'DDT', pobj)
    seen_contains = False
    mheader = None
    var_dict = VarDictionary(type_def[0])
    inspec = True
    while inspec and (statements is not None):
        while len(statements) > 0:
            statement = statements.pop(0)
            # End program or module
            pmatch = end_type_re.match(statement)
            if pmatch is not None:
                # We hit the end of the type, make a header
                mheader = MetadataHeader(title=type_def[0],
                                         type_in='DDT',
                                         module=mod_name,
                                         var_dict=var_dict,
                                         logger=logger)
                inspec = False
            elif is_contains_statement(statement, inspec):
                seen_contains = True
            elif not seen_contains:
                # Comment of variable
                if ((not is_comment_statement(statement, logger)) and
                    (not parse_use_statement({}, statement, pobj, logger))):
                    vars = parse_fortran_var_decl(statement,
                                                  psrc,
                                                  logger=logger)
                    for var in vars:
                        var_dict.add_variable(var)
                    # End for
                # End if
            else:
                # We are just skipping lines until the end type
                pass
            # End if
        # End while
        if inspec and (len(statements) == 0):
            statements = read_statements(pobj)
        # End if
    # End while
    return statements, mheader
示例#5
0
def write_host_cap(host_model, api, output_dir, logger):
###############################################################################
    """Write an API to allow <host_model> to call any configured CCPP suite"""
    module_name = "{}_ccpp_cap".format(host_model.name)
    cap_filename = os.path.join(output_dir, '{}.F90'.format(module_name))
    if logger is not None:
        msg = 'Writing CCPP Host Model Cap for {} to {}'
        logger.info(msg.format(host_model.name, cap_filename))
    # End if
    header = _HEADER.format(host_model=host_model.name)
    with FortranWriter(cap_filename, 'w', header, module_name) as cap:
        # Write module use statements
        maxmod = len(KINDS_MODULE)
        cap.write('   use {kinds}'.format(kinds=KINDS_MODULE), 1)
        modules = host_model.variable_locations()
        if modules:
            mlen = max([len(x[0]) for x in modules])
            maxmod = max(maxmod, mlen)
        # End if
        mlen = max([len(x.module) for x in api.suites])
        maxmod = max(maxmod, mlen)
        maxmod = max(maxmod, len(CONST_DDT_MOD))
        for mod in modules:
            mspc = (maxmod - len(mod[0]))*' '
            cap.write("use {}, {}only: {}".format(mod[0], mspc, mod[1]), 1)
        # End for
        mspc = ' '*(maxmod - len(CONST_DDT_MOD))
        cap.write("use {}, {}only: {}".format(CONST_DDT_MOD, mspc,
                                              CONST_DDT_NAME), 1)
        cap.write_preamble()
        max_suite_len = 0
        for suite in api.suites:
            max_suite_len = max(max_suite_len, len(suite.module))
        # End for
        cap.write("! Public Interfaces", 1)
        # CCPP_STATE_MACH.transitions represents the host CCPP interface
        for stage in CCPP_STATE_MACH.transitions():
            stmt = "public :: {host_model}_ccpp_physics_{stage}"
            cap.write(stmt.format(host_model=host_model.name, stage=stage), 1)
        # End for
        API.declare_inspection_interfaces(cap)
        # Write the host-model interfaces for constituents
        reg_name = constituent_register_subname(host_model)
        cap.write("public :: {}".format(reg_name), 1)
        numconsts_name = constituent_num_consts_funcname(host_model)
        cap.write("public :: {}".format(numconsts_name), 1)
        copyin_name = constituent_copyin_subname(host_model)
        cap.write("public :: {}".format(copyin_name), 1)
        copyout_name = constituent_copyout_subname(host_model)
        cap.write("public :: {}".format(copyout_name), 1)
        cap.write("", 0)
        cap.write("! Private module variables", 1)
        const_dict = add_constituent_vars(cap, host_model, api.suites, logger)
        cap.end_module_header()
        for stage in CCPP_STATE_MACH.transitions():
            # Create a dict of local variables for stage
            host_local_vars = VarDictionary("{}_{}".format(host_model.name,
                                                           stage))
            # Create part call lists
            # Look for any loop-variable mismatch
            for suite in api.suites:
                spart_list = suite_part_list(suite, stage)
                for spart in spart_list:
                    spart_args = spart.call_list.variable_list()
                    for sp_var in spart_args:
                        stdname = sp_var.get_prop_value('standard_name')
                        hvar = const_dict.find_variable(standard_name=stdname,
                                                        any_scope=True)
                        if hvar is None:
                            errmsg = 'No host model variable for {} in {}'
                            raise CCPPError(errmsg.format(stdname, spart.name))
                        # End if
                    # End for (loop over part variables)
                # End for (loop of suite parts)
            # End for (loop over suites)
            run_stage = stage == 'run'
            # All interfaces need the suite name
            apivars = [_SUITE_NAME_VAR]
            if run_stage:
                # Only the run phase needs a suite part name
                apivars.append(_SUITE_PART_VAR)
            # End if
            # Create a list of dummy arguments with correct intent settings
            callvars = host_model.call_list(stage) # Host interface dummy args
            hdvars = list()
            subst_dict = {}
            for hvar in callvars:
                protected = hvar.get_prop_value('protected')
                stdname = hvar.get_prop_value('standard_name')
                if stdname in CCPP_LOOP_VAR_STDNAMES:
                    protected = True # Cannot modify a loop variable
                # End if
                if protected:
                    subst_dict['intent'] = 'in'
                else:
                    subst_dict['intent'] = 'inout'
                # End if
                hdvars.append(hvar.clone(subst_dict,
                                         source_name=_API_SRC_NAME))
            # End for
            lnames = [x.get_prop_value('local_name') for x in apivars + hdvars]
            api_vlist = ", ".join(lnames)
            cap.write(_SUBHEAD.format(api_vars=api_vlist,
                                      host_model=host_model.name,
                                      stage=stage), 1)
            # Write out any suite part use statements
            for suite in api.suites:
                mspc = (max_suite_len - len(suite.module))*' '
                spart_list = suite_part_list(suite, stage)
                for spart in spart_list:
                    stmt = "use {}, {}only: {}"
                    cap.write(stmt.format(suite.module, mspc, spart.name), 2)
                # End for
            # End for
            # Write out any host model DDT input var use statements
            host_model.ddt_lib.write_ddt_use_statements(hdvars, cap, 2,
                                                        pad=max_suite_len)

            cap.write("", 1)
            # Write out dummy arguments
            for var in apivars:
                var.write_def(cap, 2, host_model)
            # End for
            for var in hdvars:
                var.write_def(cap, 2, host_model)
            # End for
            for var in host_local_vars.variable_list():
                var.write_def(cap, 2, host_model)
            # End for
            cap.write('', 0)
            # Write out the body clauses
            errmsg_name, errflg_name = api.get_errinfo_names()
            # Initialize err variables
            cap.write('{errflg} = 0'.format(errflg=errflg_name), 2)
            cap.write('{errmsg} = ""'.format(errmsg=errmsg_name), 2)
            else_str = ''
            for suite in api.suites:
                stmt = "{}if (trim(suite_name) == '{}') then"
                cap.write(stmt.format(else_str, suite.name), 2)
                if stage == 'run':
                    el2_str = ''
                    spart_list = suite_part_list(suite, stage)
                    for spart in spart_list:
                        pname = spart.name[len(suite.name)+1:]
                        stmt = "{}if (trim(suite_part) == '{}') then"
                        cap.write(stmt.format(el2_str, pname), 3)
                        call_str = suite_part_call_list(host_model, const_dict,
                                                        spart, True)
                        cap.write("call {}({})".format(spart.name, call_str), 4)
                        el2_str = 'else '
                    # End for
                    cap.write("else", 3)
                    emsg = "write({errmsg}, '(3a)')".format(errmsg=errmsg_name)
                    emsg += '"No suite part named ", '
                    emsg += 'trim(suite_part), '
                    emsg += '" found in suite {sname}"'.format(sname=suite.name)
                    cap.write(emsg, 4)
                    cap.write("{errflg} = 1".format(errflg=errflg_name), 4)
                    cap.write("end if", 3)
                else:
                    spart = suite.phase_group(stage)
                    call_str = suite_part_call_list(host_model, const_dict,
                                                    spart, False)
                    stmt = "call {}_{}({})"
                    cap.write(stmt.format(suite.name, stage, call_str), 3)
                # End if
                else_str = 'else '
            # End for
            cap.write("else", 2)
            emsg = "write({errmsg}, '(3a)')".format(errmsg=errmsg_name)
            emsg += '"No suite named ", '
            emsg += 'trim(suite_name), "found"'
            cap.write(emsg, 3)
            cap.write("{errflg} = 1".format(errflg=errflg_name), 3)
            cap.write("end if", 2)
            cap.write(_SUBFOOT.format(host_model=host_model.name,
                                      stage=stage), 1)
        # End for
        # Write the API inspection routines (e.g., list of suites)
        api.write_inspection_routines(cap)
        # Write the constituent initialization interfaces
        err_vars = host_model.find_error_variables()
        const_obj_name = constituent_model_object_name(host_model)
        cap.write("", 0)
        const_names_name = constituent_model_const_stdnames(host_model)
        const_indices_name = constituent_model_const_indices(host_model)
        ConstituentVarDict.write_host_routines(cap, host_model, reg_name,
                                               numconsts_name, copyin_name,
                                               copyout_name, const_obj_name,
                                               const_names_name,
                                               const_indices_name,
                                               api.suites, err_vars)
    # End with
    return cap_filename
示例#6
0
def add_constituent_vars(cap, host_model, suite_list, logger):
###############################################################################
    """Create a DDT library containing array reference variables
    for each constituent field for all suites in <suite_list>.
    Create and return a dictionary containing an index variable for each of the
    constituents as well as the variables from the DDT object.
    Also, write declarations for these variables to <cap>.
    Since the constituents are in a DDT (ccpp_constituent_properties_t),
    create a metadata table with the required information, then parse it
    to create the dictionary.
    """
    # First create a MetadataTable for the constituents DDT
    stdname_layer = "ccpp_constituents_num_layer_consts"
    stdname_interface = "ccpp_constituents_num_interface_consts"
    stdname_2d = "ccpp_constituents_num_2d_consts"
    horiz_dim = "horizontal_dimension"
    vert_layer_dim = "vertical_layer_dimension"
    vert_interface_dim = "vertical_interface_dimension"
    array_layer = "vars_layer"
    array_interface = "vars_interface"
    array_2d = "vars_2d"
    # Table preamble (leave off ccpp-table-properties header)
    ddt_mdata = [
        #"[ccpp-table-properties]",
        " name = {}".format(CONST_DDT_NAME), " type = ddt",
        "[ccpp-arg-table]",
        " name = {}".format(CONST_DDT_NAME), " type = ddt",
        "[ num_layer_vars ]",
        " standard_name = {}".format(stdname_layer),
        " units = count", " dimensions = ()", " type = integer",
        "[ num_interface_vars ]",
        " standard_name = {}".format(stdname_interface),
        " units = count", " dimensions = ()", " type = integer",
        "[ num_2d_vars ]",
        " standard_name = {}".format(stdname_2d),
        " units = count", " dimensions = ()", " type = integer",
        "[ {} ]".format(array_layer),
        " standard_name = ccpp_constituents_array_of_layer_consts",
        " units = none",
        " dimensions = ({}, {}, {})".format(horiz_dim, vert_layer_dim,
                                            stdname_layer),
        " type = real", " kind = kind_phys",
        "[ {} ]".format(array_interface),
        " standard_name = ccpp_constituents_array_of_interface_consts",
        " units = none",
        " dimensions = ({}, {}, {})".format(horiz_dim,
                                            vert_interface_dim,
                                            stdname_interface),
        " type = real", " kind = kind_phys",
        "[ {} ]".format(array_2d),
        " standard_name = ccpp_constituents_array_of_2d_consts",
        " units = none",
        " dimensions = ({}, {})".format(horiz_dim, stdname_2d),
        " type = real", " kind = kind_phys"]
    # Add entries for each constituent (once per standard name)
    const_stdnames = set()
    for suite in suite_list:
        if logger is not None:
            lmsg = "Adding constituents from {} to {}"
            logger.debug(lmsg.format(suite.name, host_model.name))
        # end if
        scdict = suite.constituent_dictionary()
        for cvar in scdict.variable_list():
            std_name = cvar.get_prop_value('standard_name')
            if std_name not in const_stdnames:
                # Add a metadata entry for this constituent
                # Check dimensions and figure vertical dimension
                # Currently, we only support variables with first dimension,
                #   horizontal_dimension, and second (optional) dimension,
                #   vertical_layer_dimension or vertical_interface_dimension
                dims = cvar.get_dimensions()
                if (len(dims) < 1) or (len(dims) > 2):
                    emsg = "Unsupported constituent dimensions, '{}'"
                    dimstr = "({})".format(", ".join(dims))
                    raise CCPPError(emsg.format(dimstr))
                # end if
                hdim = dims[0].split(':')[-1]
                if hdim != 'horizontal_dimension':
                    emsg = "Unsupported first constituent dimension, '{}', "
                    emsg += "must be 'horizontal_dimension'"
                    raise CCPPError(emsg.format(hdim))
                # end if
                if len(dims) > 1:
                    vdim = dims[1].split(':')[-1]
                    if vdim == vert_layer_dim:
                        cvar_array_name = array_layer
                    elif vdim == vert_interface_dim:
                        cvar_array_name = array_interface
                    else:
                        emsg = "Unsupported vertical constituent dimension, "
                        emsg += "'{}', must be '{}' or '{}'"
                        raise CCPPError(emsg.format(vdim, vert_layer_dim,
                                                    vert_interface_dim))
                    # end if
                else:
                    cvar_array_name = array_2d
                # end if
                # First, create an index variable for <cvar>
                ind_std_name = "index_of_{}".format(std_name)
                loc_name = "{}(:,:,{})".format(cvar_array_name, ind_std_name)
                ddt_mdata.append("[ {} ]".format(loc_name))
                ddt_mdata.append(" standard_name = {}".format(std_name))
                units = cvar.get_prop_value('units')
                ddt_mdata.append(" units = {}".format(units))
                dimstr = "({})".format(", ".join(dims))
                ddt_mdata.append(" dimensions = {}".format(dimstr))
                vtype = cvar.get_prop_value('type')
                vkind = cvar.get_prop_value('kind')
                ddt_mdata.append(" type = {} | kind = {}".format(vtype, vkind))
                const_stdnames.add(std_name)
            # end if
        # end for
    # end for
    # Parse this table using a fake filename
    parse_obj = ParseObject("{}_constituent_mod.meta".format(host_model.name),
                            ddt_mdata)
    ddt_table = MetadataTable(parse_object=parse_obj, logger=logger)
    ddt_name = ddt_table.sections()[0].title
    ddt_lib = DDTLibrary('{}_constituent_ddtlib'.format(host_model.name),
                         ddts=ddt_table.sections(), logger=logger)
    # A bit of cleanup
    del parse_obj
    del ddt_mdata
    # Now, create the "host constituent module" dictionary
    const_dict = VarDictionary("{}_constituents".format(host_model.name),
                               parent_dict=host_model)
    # Add in the constituents object
    prop_dict = {'standard_name' : "ccpp_model_constituents_object",
                 'local_name' : constituent_model_object_name(host_model),
                 'dimensions' : '()', 'units' : "None", 'ddt_type' : ddt_name}
    const_var = Var(prop_dict, _API_SOURCE)
    const_var.write_def(cap, 1, const_dict)
    ddt_lib.collect_ddt_fields(const_dict, const_var)
    # Declare variable for the constituent standard names array
    max_csname = max([len(x) for x in const_stdnames]) if const_stdnames else 0
    num_const_fields = len(const_stdnames)
    cs_stdname = constituent_model_const_stdnames(host_model)
    const_list = sorted(const_stdnames)
    if const_list:
        const_strs = ['"{}{}"'.format(x, ' '*(max_csname - len(x)))
                      for x in const_list]
        cs_stdame_initstr = " = (/ " + ", ".join(const_strs) + " /)"
    else:
        cs_stdame_initstr = ""
    # end if
    cap.write("character(len={}) :: {}({}){}".format(max_csname, cs_stdname,
                                                     num_const_fields,
                                                     cs_stdame_initstr), 1)
    # Declare variable for the constituent standard names array
    array_name = constituent_model_const_indices(host_model)
    cap.write("integer :: {}({}) = -1".format(array_name, num_const_fields), 1)
    # Add individual variables for each index var to the const_dict
    for index, std_name in enumerate(const_list):
        ind_std_name = "index_of_{}".format(std_name)
        ind_loc_name = "{}({})".format(array_name, index + 1)
        prop_dict = {'standard_name' : ind_std_name,
                     'local_name' : ind_loc_name, 'dimensions' : '()',
                     'units' : 'index', 'protected' : "True",
                     'type' : 'integer', 'kind' : ''}
        ind_var = Var(prop_dict, _API_SOURCE)
        const_dict.add_variable(ind_var)
    # end for
    # Add vertical dimensions for DDT call strings
    pver = host_model.find_variable(standard_name=vert_layer_dim,
                                    any_scope=False)
    if pver is not None:
        prop_dict = {'standard_name' : vert_layer_dim,
                     'local_name' : pver.get_prop_value('local_name'),
                     'units' : 'count', 'type' : 'integer',
                     'protected' : 'True', 'dimensions' : '()'}
        if const_dict.find_variable(standard_name=vert_layer_dim,
                                    any_scope=False) is None:
            ind_var = Var(prop_dict, _API_SOURCE)
            const_dict.add_variable(ind_var)
        # end if
    # end if
    pver = host_model.find_variable(standard_name=vert_interface_dim,
                                    any_scope=False)
    if pver is not None:
        prop_dict = {'standard_name' : vert_interface_dim,
                     'local_name' : pver.get_prop_value('local_name'),
                     'units' : 'count', 'type' : 'integer',
                     'protected' : 'True', 'dimensions' : '()'}
        if const_dict.find_variable(standard_name=vert_interface_dim,
                                    any_scope=False) is None:
            ind_var = Var(prop_dict, _API_SOURCE)
            const_dict.add_variable(ind_var)
        # end if
    # end if

    return const_dict
示例#7
0
                          ParseContext(filename="host_cap.F90"))

_SUITE_NAME_VAR = Var({'local_name':'suite_name',
                       'standard_name':'suite_name',
                       'intent':'in', 'type':'character',
                       'kind':'len=*', 'units':'', 'protected':'True',
                       'dimensions':'()'}, _API_SOURCE)

_SUITE_PART_VAR = Var({'local_name':'suite_part',
                       'standard_name':'suite_part',
                       'intent':'in', 'type':'character',
                       'kind':'len=*', 'units':'', 'protected':'True',
                       'dimensions':'()'}, _API_SOURCE)

# Used to prevent loop substitution lookups
_BLANK_DICT = VarDictionary(_API_SRC_NAME)

###############################################################################
def suite_part_list(suite, stage):
###############################################################################
    """Return a list of all the suite parts for this stage"""
    run_stage = stage == 'run'
    if run_stage:
        spart_list = list()
        for spart in suite.groups:
            if suite.is_run_group(spart):
                spart_list.append(spart)
            # End if
        # End for
    else:
        spart_list = [suite.phase_group(stage)]
示例#8
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
示例#9
0
class HostModel(VarDictionary):
    """Class to hold the data from a host model"""
    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

    @property
    def name(self):
        """Return the host model name"""
        return self.__name

    @property
    def loop_vars(self):
        """Return this host model's loop variables"""
        return self.__loop_vars

    @property
    def ddt_lib(self):
        """Return this host model's DDT library"""
        return self.__ddt_lib

# XXgoldyXX: v needed?

    @property
    def constituent_module(self):
        """Return the name of host model constituent module"""
        return "{}_ccpp_constituents".format(self.name)
# XXgoldyXX: ^ needed?

    def argument_list(self, loop_vars=True):
        """Return a string representing the host model variable arg list"""
        args = [
            v.call_string(self)
            for v in self.variable_list(loop_vars=loop_vars, consts=False)
        ]
        return ', '.join(args)

    def metadata_tables(self):
        """Return a copy of this host models metadata tables"""
        return dict(self.__metadata_tables)

    def host_variable_module(self, local_name):
        """Return the module name for a host variable"""
        if local_name in self.__var_locations:
            return self.__var_locations[local_name]
        # End if
        return None

    def variable_locations(self):
        """Return a set of module-variable and module-type pairs.
        These represent the locations of all host model data with a listed
        source location (variables with no <module> source are omitted)."""
        varset = set()
        lnames = self.prop_list('local_name')
        # Attempt to realize deferred lookups
        if self.__deferred_finds is not None:
            for std_name in list(self.__deferred_finds):
                var = self.find_variable(standard_name=std_name)
                if var is not None:
                    self.__deferred_finds.remove(std_name)
                # End if
            # End for
        # End if
        # Now, find all the used module variables
        for name in lnames:
            module = self.host_variable_module(name)
            used = self.__used_variables and (name in self.__used_variables)
            if module and used:
                varset.add((module, name))
            # No else, either no module or a zero-length module name
            # End if
        # End for
        return varset

    def find_variable(self,
                      standard_name=None,
                      source_var=None,
                      any_scope=False,
                      clone=None,
                      search_call_list=False,
                      loop_subst=False):
        """Return the host model variable matching <standard_name> or None
        If <loop_subst> is True, substitute a begin:end range for an extent.
        """
        my_var = super(HostModel,
                       self).find_variable(standard_name=standard_name,
                                           source_var=source_var,
                                           any_scope=any_scope,
                                           clone=clone,
                                           search_call_list=search_call_list,
                                           loop_subst=loop_subst)
        if my_var is None:
            # Check our DDT library
            if standard_name is None:
                if source_var is None:
                    emsg = ("One of <standard_name> or <source_var> " +
                            "must be passed.")
                    raise ParseInternalError(emsg)
                # end if
                standard_name = source_var.get_prop_value('standard_name')
            # end if
            # Since we are the parent of the DDT library, only check that dict
            my_var = self.__ddt_dict.find_variable(standard_name=standard_name,
                                                   any_scope=False)
        # End if
        if loop_subst:
            if my_var is None:
                my_var = self.find_loop_subst(standard_name)
            # End if
            if my_var is not None:
                # If we get here, the host does not have the requested
                # variable but does have a replacement set. Create a new
                # variable to use to send to suites.
                ##XXgoldyXX: This cannot be working since find_loop_subst
                ##           returns a tuple
                new_name = self.new_internal_variable_name(prefix=self.name)
                ctx = ParseContext(filename='host_model.py')
                new_var = my_var.clone(new_name,
                                       source_name=self.name,
                                       source_type="HOST",
                                       context=ctx)
                self.add_variable(new_var)
                my_var = new_var
            # End if
        # End if
        if my_var is None:
            if self.__deferred_finds is not None:
                self.__deferred_finds.add(standard_name)
            # End if
        elif self.__used_variables is not None:
            lname = my_var.get_prop_value('local_name')
            # Try to add any index references (should be method?)
            imatch = FORTRAN_SCALAR_REF_RE.match(lname)
            if imatch is not None:
                vdims = [
                    x.strip() for x in imatch.group(2).split(',')
                    if ':' not in x
                ]
                for vname in vdims:
                    _ = self.find_variable(standard_name=vname)
                # End for
            # End if
            if isinstance(my_var, VarDDT):
                lname = my_var.get_parent_prop('local_name')
            # End if
            self.__used_variables.add(lname)
        # End if
        return my_var

    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)

    def add_host_variable_module(self, local_name, module, logger=None):
        """Add a module name location for a host variable"""
        if local_name not in self.__var_locations:
            if logger is not None:
                emsg = 'Adding variable, {}, from module, {}'
                logger.debug(emsg.format(local_name, module))
            # End if
            self.__var_locations[local_name] = module
        else:
            emsg = "Host variable, {}, already located in module"
            raise CCPPError(emsg.format(self.__var_locations[local_name]))
        # End if

    def call_list(self, phase):
        "Return the list of variables passed by the host model to the host cap"
        hdvars = list()
        loop_vars = phase == 'run'
        for hvar in self.variable_list(loop_vars=loop_vars, consts=False):
            lname = hvar.get_prop_value('local_name')
            if self.host_variable_module(lname) is None:
                hdvars.append(hvar)
            # End if
        # End for
        return hdvars
示例#10
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
    while insub and (statements is not None):
        while len(statements) > 0:
            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
            elif (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
            elif smatch is not None:
                scheme_name = smatch.group(1)
                inpreamble = scheme_name == table_name
                if inpreamble:
                    if smatch.group(2) is not None:
                        scheme_args = [
                            x.strip().lower()
                            for x in smatch.group(2).split(',')
                        ]
                    else:
                        scheme_args = list()
                    # End if
                    scheme_set = set(scheme_args)
                    var_dict = VarDictionary(scheme_name)
                    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, logger)) and
                      (not parse_use_statement({}, statement, pobj, logger))
                      and ('intent' in statement.lower())):
                    vars = parse_fortran_var_decl(statement,
                                                  psrc,
                                                  logger=logger)
                    for var in vars:
                        lname = var.get_prop_value('local_name').lower()
                        if lname in scheme_set:
                            scheme_set.remove(lname)
                        else:
                            raise ParseSyntaxError('dummy argument',
                                                   token=lname,
                                                   context=pobj)
                        # End if
                        var_dict.add_variable(var)
                    # End for
                # End if
            # End if
        # End while
        if insub and (len(statements) == 0):
            statements = read_statements(pobj)
        # End if
    # End while
    if (scheme_name is not None) and (var_dict is not None):
        mheader = MetadataHeader(title=scheme_name,
                                 type_in='SCHEME',
                                 module=spec_name,
                                 var_dict=var_dict,
                                 logger=logger)
    # End if
    return statements, mheader
示例#11
0
 def __init_from_file__(self, parse_object, logger):
     # Read the table preamble, assume the caller already figured out
     #  the first line of the header using the table_start method.
     curr_line, curr_line_num = self._pobj.next_line()
     self._table_title = None
     self._header_type = None
     self._module_name = None
     while (curr_line
            is not None) and (not self.variable_start(curr_line)) and (
                not MetadataHeader.table_start(curr_line)):
         for property in self.parse_config_line(curr_line):
             # Manually parse name, type, and module properties
             key = property[0].strip().lower()
             value = property[1].strip()
             if key == 'name':
                 self._table_title = value
             elif key == 'type':
                 if value not in ['module', 'scheme', 'ddt']:
                     raise ParseSyntaxError("metadata table type",
                                            token=value,
                                            context=self._pobj)
                 # End if
                 self._header_type = value
             elif key == 'module':
                 if value == "None":
                     raise ParseSyntaxError("metadata table, no module",
                                            context=self._pobj)
                 else:
                     self._module_name = value
                 # End if
             else:
                 raise ParseSyntaxError("metadata table start property",
                                        token=value,
                                        context=self._pobj)
             # End if
         # End for
         curr_line, curr_line_num = self._pobj.next_line()
     # End while
     if self.title is None:
         raise ParseSyntaxError("metadata header start, no table name",
                                token=curr_line,
                                context=self._pobj)
     elif self.header_type is None:
         raise ParseSyntaxError("metadata header start, no table type",
                                token=curr_line,
                                context=self._pobj)
     elif self.header_type == "ddt":
         register_fortran_ddt_name(self.title)
     # End if
     #  Initialize our ParseSource parent
     super(MetadataHeader, self).__init__(self.title, self.header_type,
                                          self._pobj)
     # Read the variables
     valid_lines = True
     self._variables = VarDictionary(self.title, logger=logger)
     while valid_lines:
         newvar, curr_line = self.parse_variable(curr_line)
         valid_lines = newvar is not None
         if valid_lines:
             self._variables.add_variable(newvar)
             # Check to see if we hit the end of the table
             valid_lines = not MetadataHeader.table_start(curr_line)
示例#12
0
class MetadataHeader(ParseSource):
    """Class to hold all information from a metadata header
    >>> MetadataHeader(ParseObject("foobar.txt",                              \
                      ["name = foobar", "type = scheme", "module = foo",      \
                       "[ im ]", "standard_name = horizontal_loop_extent",    \
                       "long_name = horizontal loop extent, start at 1",      \
                       "units = index | type = integer",                      \
                       "dimensions = () |  intent = in"])) #doctest: +ELLIPSIS
    <__main__.MetadataHeader foo / foobar at 0x...>
    >>> MetadataHeader(ParseObject("foobar.txt",                              \
                      ["name = foobar", "type = scheme", "module = foobar",   \
                       "[ im ]", "standard_name = horizontal_loop_extent",    \
                       "long_name = horizontal loop extent, start at 1",      \
                       "units = index | type = integer",                      \
                       "dimensions = () |  intent = in"])).get_var(standard_name='horizontal_loop_extent') #doctest: +ELLIPSIS
    <metavar.Var horizontal_loop_extent: im at 0x...>
    >>> MetadataHeader(ParseObject("foobar.txt",                              \
                      ["name = foobar", "module = foo",                       \
                       "[ im ]", "standard_name = horizontal_loop_extent",    \
                       "long_name = horizontal loop extent, start at 1",      \
                       "units = index | type = integer",                      \
                       "dimensions = () |  intent = in",                      \
                       "  subroutine foo()"])).get_var(standard_name='horizontal_loop_extent') #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    ParseSyntaxError: Missing metadata header type, at foobar.txt:7
    >>> MetadataHeader(ParseObject("foobar.txt",                              \
                      ["name = foobar", "type = scheme", "module=foobar",     \
                       "[ im ]", "standard_name = horizontal_loop_extent",    \
                       "long_name = horizontal loop extent, start at 1",      \
                       "units = index | type = integer",                      \
                       "dimensions = () |  intent = in",                      \
                       ""], line_start=0)).get_var(standard_name='horizontal_loop_extent').get_prop_value('local_name')
    'im'
    >>> MetadataHeader(ParseObject("foobar.txt",                              \
                      ["name = foobar", "type = scheme"                       \
                       "[ im ]", "standard_name = horizontal loop extent",    \
                       "long_name = horizontal loop extent, start at 1",      \
                       "units = index | type = integer",                      \
                       "dimensions = () |  intent = in",                      \
                       ""], line_start=0)).get_var(standard_name='horizontal_loop_extent') #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    ParseSyntaxError: Invalid variable property value, 'horizontal loop extent', at foobar.txt:2
    >>> MetadataHeader(ParseObject("foobar.txt",                              \
                      ["[ccpp-arg-table]", "name = foobar", "type = scheme"   \
                       "[ im ]", "standard_name = horizontal loop extent",    \
                       "long_name = horizontal loop extent, start at 1",      \
                       "units = index | type = integer",                      \
                       "dimensions = () |  intent = in",                      \
                       ""], line_start=0)).get_var(standard_name='horizontal_loop_extent') #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    ParseSyntaxError: Invalid property syntax, '[ccpp-arg-table]', at foobar.txt:1
    >>> MetadataHeader(ParseObject("foobar.txt",                              \
                      ["name = foobar", "module = foo"                        \
                       "[ im ]", "standard_name = horizontal loop extent",    \
                       "long_name = horizontal loop extent, start at 1",      \
                       "units = index | type = integer",                      \
                       "dimensions = () |  intent = in",                      \
                       ""], line_start=0)).get_var(standard_name='horizontal_loop_extent') #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    ParseSyntaxError: Invalid metadata header start, no table type, at foobar.txt:2
    >>> MetadataHeader.__var_start__.match('[ qval ]') #doctest: +ELLIPSIS
    <_sre.SRE_Match object at 0x...>
    >>> MetadataHeader.__var_start__.match('[ qval(hi_mom) ]') #doctest: +ELLIPSIS
    <_sre.SRE_Match object at 0x...>
"""

    __header_start__ = re.compile(r"(?i)\s*\[\s*ccpp-arg-table\s*\]")

    __var_start__ = re.compile(r"^\[\s*(" + FORTRAN_ID + r"|" + LITERAL_INT +
                               r"|" + FORTRAN_SCALAR_REF + r")\s*\]$")

    __blank_line__ = re.compile(r"\s*[#;]")

    __html_template__ = """
<html>
<head>
<title>{title}</title>
<meta charset="UTF-8">
</head>
<body>
<table border="1">
{header}{contents}</table>
</body>
</html>
"""

    def __init__(self,
                 parse_object=None,
                 title=None,
                 type_in=None,
                 module=None,
                 var_dict=None,
                 logger=None):
        self._pobj = parse_object
        """If <parse_object> is not None, initialize from the current file and
        location in <parse_object>.
        If <parse_object> is None, initialize from <title>, <type>, <module>,
        and <var_dict>. Note that if <parse_object> is not None, <title>,
        <type>, <module>, and <var_dict> are ignored.
        """
        if parse_object is None:
            if title is None:
                raise ParseInternalError('MetadataHeader requires a title')
            else:
                self._table_title = title
            # End if
            if type_in is None:
                raise ParseInternalError(
                    'MetadataHeader requires a header type')
            else:
                self._header_type = type
            # End if
            if module is None:
                raise ParseInternalError(
                    'MetadataHeader requires a module name')
            else:
                self._module_name = module
            # End if
            #  Initialize our ParseSource parent
            super(MetadataHeader, self).__init__(self.title, self.header_type,
                                                 self._pobj)
            self._variables = VarDictionary(self.title, logger=logger)
            for var in var_dict.variable_list():  # Let this crash if no dict
                self._variables.add_variable(var)
            # End for
        else:
            self.__init_from_file__(parse_object, logger)
        # End if
        # Categorize the variables
        self._var_intents = {'in': list(), 'out': list(), 'inout': list()}
        for var in self.variable_list():
            intent = var.get_prop_value('intent')
            if intent is not None:
                self._var_intents[intent].append(var)
            # End if
        # End for

    def __init_from_file__(self, parse_object, logger):
        # Read the table preamble, assume the caller already figured out
        #  the first line of the header using the table_start method.
        curr_line, curr_line_num = self._pobj.next_line()
        self._table_title = None
        self._header_type = None
        self._module_name = None
        while (curr_line
               is not None) and (not self.variable_start(curr_line)) and (
                   not MetadataHeader.table_start(curr_line)):
            for property in self.parse_config_line(curr_line):
                # Manually parse name, type, and module properties
                key = property[0].strip().lower()
                value = property[1].strip()
                if key == 'name':
                    self._table_title = value
                elif key == 'type':
                    if value not in ['module', 'scheme', 'ddt']:
                        raise ParseSyntaxError("metadata table type",
                                               token=value,
                                               context=self._pobj)
                    # End if
                    self._header_type = value
                elif key == 'module':
                    if value == "None":
                        raise ParseSyntaxError("metadata table, no module",
                                               context=self._pobj)
                    else:
                        self._module_name = value
                    # End if
                else:
                    raise ParseSyntaxError("metadata table start property",
                                           token=value,
                                           context=self._pobj)
                # End if
            # End for
            curr_line, curr_line_num = self._pobj.next_line()
        # End while
        if self.title is None:
            raise ParseSyntaxError("metadata header start, no table name",
                                   token=curr_line,
                                   context=self._pobj)
        elif self.header_type is None:
            raise ParseSyntaxError("metadata header start, no table type",
                                   token=curr_line,
                                   context=self._pobj)
        elif self.header_type == "ddt":
            register_fortran_ddt_name(self.title)
        # End if
        #  Initialize our ParseSource parent
        super(MetadataHeader, self).__init__(self.title, self.header_type,
                                             self._pobj)
        # Read the variables
        valid_lines = True
        self._variables = VarDictionary(self.title, logger=logger)
        while valid_lines:
            newvar, curr_line = self.parse_variable(curr_line)
            valid_lines = newvar is not None
            if valid_lines:
                self._variables.add_variable(newvar)
                # Check to see if we hit the end of the table
                valid_lines = not MetadataHeader.table_start(curr_line)
            # No else, we just run off the end of the table
            # End if
        # End while

    def parse_config_line(self, line):
        "Parse a config line and return a list of keyword value pairs."
        parse_items = list()
        if line is None:
            pass  # No properties on this line
        elif MetadataHeader.is_blank(line):
            pass  # No properties on this line
        else:
            properties = line.strip().split('|')
            for property in properties:
                pitems = property.split('=', 1)
                if len(pitems) < 2:
                    raise ParseSyntaxError("variable property syntax",
                                           token=property,
                                           context=self._pobj)
                else:
                    parse_items.append(pitems)
                # End if
            # End for
        # End if
        return parse_items

    def parse_variable(self, curr_line):
        # The header line has the format [ <valid_fortran_symbol> ]
        # Parse header
        valid_line = (curr_line is not None) and (
            not MetadataHeader.table_start(curr_line))
        if valid_line:
            local_name = self.variable_start(
                curr_line)  # caller handles exception
        else:
            local_name = None
        # End if
        if local_name is None:
            # This is not a valid variable line, punt (should be end of table)
            valid_line = False
        # End if
        # Parse lines until invalid line is found
        # NB: Header variables cannot have embedded blank lines
        if valid_line:
            var_props = {}
            var_props['local_name'] = local_name
        else:
            var_props = None
        # End if
        while valid_line:
            curr_line, curr_line_num = self._pobj.next_line()
            valid_line = ((curr_line is not None)
                          and (not MetadataHeader.is_blank(curr_line))
                          and (not MetadataHeader.table_start(curr_line))
                          and (self.variable_start(curr_line) is None))
            # A valid line may have multiple properties (separated by '|')
            if valid_line:
                properties = self.parse_config_line(curr_line)
                for property in properties:
                    try:
                        pname = property[0].strip()
                        pval_str = property[1].strip()
                        # Make sure this is a match
                        hp = Var.get_prop(pname)
                        if hp is not None:
                            pval = hp.valid_value(pval_str)
                        else:
                            raise ParseSyntaxError("variable property name",
                                                   token=pname,
                                                   context=self._pobj)
                        # End if
                        if pval is None:
                            raise ParseSyntaxError(
                                "'{}' property value".format(pname),
                                token=pval_str,
                                context=self._pobj)
                        # End if
                    except ParseSyntaxError as p:
                        raise p
                    # If we get this far, we have a valid property.
                    var_props[pname] = pval
                # End for
            # End if
        # End while
        if var_props is None:
            return None, curr_line
        else:
            try:
                newvar = Var(var_props, source=self)
            except CCPPError as ve:
                raise ParseSyntaxError(ve, context=self._pobj)
            return newvar, curr_line
        # End if

    def variable_list(self):
        "Return an ordered list of the header's variables"
        return self._variables.variable_list()

    def to_html(self, outdir, props):
        """Write html file for metadata table and return filename.
        Skip metadata headers without variables"""
        if not self._variables.variable_list():
            return None
        # Write table header
        header = "<tr>"
        for prop in props:
            header += "<th>{}</th>".format(prop)
        header += "</tr>\n"
        # Write table contents, one row per variable
        contents = ""
        for var in self._variables.variable_list():
            row = "<tr>"
            for prop in props:
                value = var.get_prop_value(prop)
                # Pretty-print for dimensions
                if prop == 'dimensions':
                    value = '(' + ', '.join(value) + ')'
                elif value is None:
                    value = "n/a"
                row += "<td>{}</td>".format(value)
            row += "</tr>\n"
            contents += row
        filename = os.path.join(outdir, self.title + '.html')
        with open(filename, "w") as f:
            f.writelines(
                self.__html_template__.format(title=self.title +
                                              ' argument table',
                                              header=header,
                                              contents=contents))
        return filename

    def get_var(self, standard_name=None, intent=None):
        if standard_name is not None:
            var = self._variables.find_variable(standard_name)
            return var
        elif intent is not None:
            if intent not in self._var_intents:
                raise ParseInternalError(
                    "Illegal intent type, '{}', in {}".format(
                        intent, self.title),
                    context=self._pobj)
            # End if
            return self._var_intents[intent]
        else:
            return None

    def prop_list(self, prop_name):
        "Return list of <prop_name> values for this scheme's arguments"
        return self._variables.prop_list(prop_name)

    def variable_start(self, line):
        """Return variable name if <line> is an interface metadata table header
        """
        if line is None:
            match = None
        else:
            match = MetadataHeader.__var_start__.match(line)
        # End if
        if match is not None:
            name = match.group(1)
            if not MetadataHeader.is_scalar_reference(name):
                raise ParseSyntaxError("local variable name",
                                       token=name,
                                       context=self._pobj)
            # End if
        else:
            name = None
        # End if
        return name

    def __repr__(self):
        base = super(MetadataHeader, self).__repr__()
        pind = base.find(' object ')
        if pind >= 0:
            pre = base[0:pind]
        else:
            pre = '<MetadataHeader'
        # End if
        bind = base.find('at 0x')
        if bind >= 0:
            post = base[bind:]
        else:
            post = '>'
        # End if
        return '{} {} / {} {}'.format(pre, self.module, self.title, post)

    def __del__(self):
        try:
            del self._variables
            super(MetadataHeader, self).__del__()
        except Exception as e:
            pass  # Python does not guarantee much about __del__ conditions
        # End try

    @property
    def title(self):
        'Return the name of the metadata arg_table'
        return self._table_title

    @property
    def module(self):
        'Return the module name for this header (if it exists)'
        return self._module_name

    @property
    def header_type(self):
        'Return the type of structure this header documents'
        return self._header_type

    @classmethod
    def is_blank(cls, line):
        "Return True iff <line> is a valid config format blank or comment line"
        return (len(line) == 0) or (cls.__blank_line__.match(line) is not None)

    @classmethod
    def table_start(cls, line):
        """Return variable name if <line> is an interface metadata table header
        """
        if (line is None) or cls.is_blank(line):
            match = None
        else:
            match = MetadataHeader.__header_start__.match(line)
        # End if
        return match is not None

    @classmethod
    def is_scalar_reference(cls, test_val):
        return check_fortran_ref(test_val) is not None

    @classmethod
    def parse_metadata_file(cls, filename):
        "Parse <filename> and return list of parsed metadata headers"
        # Read all lines of the file at once
        mheaders = list()
        with open(filename, 'r') as file:
            fin_lines = file.readlines()
            for index in range(len(fin_lines)):
                fin_lines[index] = fin_lines[index].rstrip('\n')
            # End for
        # End with
        # Look for a header start
        parse_obj = ParseObject(filename, fin_lines)
        curr_line, curr_line_num = parse_obj.curr_line()
        while curr_line is not None:
            if MetadataHeader.table_start(curr_line):
                mheaders.append(MetadataHeader(parse_obj))
                curr_line, curr_line_num = parse_obj.curr_line()
            else:
                curr_line, curr_line_num = parse_obj.next_line()
            # End if
        # End while
        return mheaders
示例#13
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
示例#14
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
示例#15
0
                       'dimensions':'()'}, _API_SOURCE, _API_DUMMY_RUN_ENV)

_SUITE_PART_VAR = Var({'local_name':'suite_part',
                       'standard_name':'suite_part',
                       'intent':'in', 'type':'character',
                       'kind':'len=*', 'units':'', 'protected':'True',
                       'dimensions':'()'}, _API_SOURCE, _API_DUMMY_RUN_ENV)

###############################################################################
# Used for creating blank dictionary
_MVAR_DUMMY_RUN_ENV = CCPPFrameworkEnv(None, ndict={'host_files':'',
                                                    'scheme_files':'',
                                                    'suites':''})

# Used to prevent loop substitution lookups
_BLANK_DICT = VarDictionary(_API_SRC_NAME, _MVAR_DUMMY_RUN_ENV)

###############################################################################
def suite_part_list(suite, stage):
###############################################################################
    """Return a list of all the suite parts for this stage"""
    run_stage = stage == 'run'
    if run_stage:
        spart_list = list()
        for spart in suite.groups:
            if suite.is_run_group(spart):
                spart_list.append(spart)
            # End if
        # End for
    else:
        spart_list = [suite.phase_group(stage)]
示例#16
0
 def __init_from_file__(self, parse_object, property_table, logger):
     # Read the table preamble, assume the caller already figured out
     #  the first line of the header using the table_start method.
     curr_line, curr_line_num = self._pobj.next_line()
     self._table_title = None
     self._header_type = None
     self._module_name = None
     self._dependencies = []
     relative_path_local = ''
     self._property_table = property_table
     while (curr_line
            is not None) and (not self.variable_start(curr_line)) and (
                not MetadataHeader.table_start(curr_line)):
         for property in self.parse_config_line(curr_line):
             # Manually parse name, type, and module properties
             key = property[0].strip().lower()
             value = property[1].strip()
             if key == 'name':
                 self._table_title = value
             elif key == 'type':
                 if value not in ['module', 'scheme', 'ddt']:
                     raise ParseSyntaxError("metadata table type",
                                            token=value,
                                            context=self._pobj)
                 # End if
                 self._header_type = value
             elif key == 'module':
                 if value == "None":
                     raise ParseSyntaxError("metadata table, no module",
                                            context=self._pobj)
                 else:
                     self._module_name = value
                 # End if
             elif key == 'dependencies':
                 if not (value == "None" or value == ""):
                     # Remove trailing comma, remove white spaces from each list element
                     self._dependencies += [
                         v.strip() for v in value.rstrip(",").split(",")
                     ]
             elif key == 'relative_path':
                 relative_path_local = value.strip()
             else:
                 raise ParseSyntaxError("metadata table start property",
                                        token=value,
                                        context=self._pobj)
             # End if
         # End for
         curr_line, curr_line_num = self._pobj.next_line()
     # End while
     if self.title is None:
         raise ParseSyntaxError("metadata header start, no table name",
                                token=curr_line,
                                context=self._pobj)
     elif self.header_type is None:
         raise ParseSyntaxError("metadata header start, no table type",
                                token=curr_line,
                                context=self._pobj)
     elif self.header_type == "ddt":
         register_fortran_ddt_name(self.title)
     # End if
     # Add relative path to dependencies
     if self.dependencies and relative_path_local:
         self._dependencies = [
             os.path.join(relative_path_local, v) for v in self.dependencies
         ]
     #  Initialize our ParseSource parent
     super(MetadataHeader, self).__init__(self.title, self.header_type,
                                          self._pobj)
     # Read the variables
     valid_lines = True
     self._variables = VarDictionary(self.title, logger=logger)
     while valid_lines:
         newvar, curr_line = self.parse_variable(curr_line)
         valid_lines = newvar is not None
         if valid_lines:
             self._variables.add_variable(newvar)
             # Check to see if we hit the end of the table
             valid_lines = not MetadataHeader.table_start(curr_line)