def parse_len_select(self, lenselect, context, len_optional=True):
     """Parse a character type length_selector"""
     largs = [x.strip() for x in lenselect.split('=')]
     if len(largs) > 2:
         raise ParseSyntaxError("length_selector",
                                token=lenselect,
                                context=context)
     # end if
     if (not len_optional) and ((len(largs) != 2) or
                                (largs[0].lower() != 'len')):
         raise ParseSyntaxError("length_selector when len= is required",
                                token=lenselect,
                                context=context)
     # end if
     if len(largs) == 2:
         if largs[0].lower() != 'len':
             raise ParseSyntaxError("length_selector",
                                    token=lenselect,
                                    context=context)
         # end if
         return self.parse_len_token(largs[1], context)
     elif len_optional:
         return self.parse_len_token(largs[0], context)
     else:
         raise ParseSyntaxError("length_selector when len= is required",
                                token=lenselect,
                                context=context)
 def __init__(self,
              typestr_in=None,
              kind_in=None,
              line_in=None,
              context=None):
     if context is None:
         self._context = ParseContext()
     else:
         self._context = ParseContext(context=context)
     # We have to distinguish which type of initialization we have
     if typestr_in is not None:
         if line_in is not None:
             raise ParseInternalError(
                 "typestr_in and line_in cannot both be used in a single call",
                 self._context)
         # End if
         self._typestr = typestr_in
         self.default_kind = kind_in is None
         if kind_in is None:
             self._kind = None
         elif kind_in[0] == '(':
             # Parse an explicit kind declaration
             self._kind = self.parse_kind_selector(kind_in)
         else:
             # The kind has already been parsed for us (e.g., by character)
             self._kind = kind_in
     elif kind_in is not None:
         raise ParseInternalError(
             "kind_in cannot be passed without typestr_in", self._context)
     elif line_in is not None:
         match = Ftype.type_match(line_in)
         self._match_len = len(match.group(0))
         if match is None:
             raise ParseSyntaxError("type declaration",
                                    token=line_in,
                                    context=self._context)
         elif check_fortran_intrinsic(match.group(1)):
             self._typestr = match.group(1)
             if match.group(2) is not None:
                 # Parse kind section
                 self._kind = self.parse_kind_selector(
                     match.group(2).strip())
             else:
                 self._kind = None
             # End if
             self.default_kind = self._kind is None
         else:
             raise ParseSyntaxError("type declaration",
                                    token=line_in,
                                    context=self._context)
     else:
         raise ParseInternalError(
             "At least one of typestr_in or line must be passed",
             self._context)
Exemple #3
0
def parse_program(pobj, statements, logger=None):
    # 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)
    # After the program name is the specification part
    statements, mheaders = 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(statements)
            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, mheaders
 def reassemble_parens(cls, propstr, errstr, context, splitstr=','):
     """Return list of <propstr> split by top-level instances of <splitstr>.
     Occurrences of <splitstr> in character contexts or in parentheses are
     ignored.
     >>> Ftype.reassemble_parens("a(b, c),d,e()", 'spec', ParseContext())
     ['a(b, c)', 'd', 'e()']
     >>> Ftype.reassemble_parens("dimension(size(Grid%xlon,1),NSPC1),  intent(in)", 'spec', ParseContext())
     ['dimension(size(Grid%xlon,1),NSPC1)', 'intent(in)']
     """
     var_list = list()
     proplist = propstr.split(splitstr)
     while len(proplist) > 0:
         var = proplist.pop(0)
         while var.count('(') != var.count(')'):
             if len(proplist) == 0:
                 raise ParseSyntaxError(errstr,
                                        token=propstr,
                                        context=context)
             # end if
             var = var + ',' + proplist.pop(0)
         # end while
         var = var.strip()
         if len(var) > 0:
             var_list.append(var)
         # end if
     # end while
     return var_list
 def parse_attr_specs(cls, propstring, context):
     """Return a list of variable properties"""
     properties = list()
     # Remove leading comma
     propstring = propstring.strip()
     if propstring and (propstring[0] == ','):
         propstring = propstring[1:].lstrip()
     # end if
     proplist = cls.reassemble_parens(propstring, 'attr_spec', context)
     for prop in proplist:
         prop = prop.strip().lower()
         if '(' in prop:
             # Strip out value from dimensions, bind, or intent
             pval = prop[0:prop.index('(')].strip()
         else:
             pval = prop
         # end if
         if pval not in cls.__attr_spec:
             raise ParseSyntaxError('attr_spec',
                                    token=prop,
                                    context=context)
         # end if
         properties.append(prop)
     # end for
     return properties
Exemple #6
0
 def parse_len_token(self, token, context):
     """Check to make sure token is a valid length identifier"""
     match = Ftype_character.len_token_re.match(token)
     if match is not None:
         return match.group(1)
     else:
         raise ParseSyntaxError("length type-param-value", token=token, context=context)
Exemple #7
0
 def __init__(self, line, context):
     """Initialize an extended type from a declaration line"""
     match = Ftype_type_decl.type_match(line)
     if match is None:
         raise ParseSyntaxError("type declaration", token=line, context=context)
     else:
         self._match_len = len(match.group(0))
         self._class = match.group(1)
         self._typestr = match.group(2)
         self._kind = self.typestr
 def parse_kind_selector(self, kind_selector, context=None):
     """Find and return the 'kind' value from <kind_selector>
     '(foo)' and '(kind=foo)' both return 'foo'"""
     if context is None:
         if hasattr(self, 'context'):
             context = self.__context
         else:
             context = ParseContext()
         # end if
     kind = None
     if (kind_selector[0] == '(') and (kind_selector[-1] == ')'):
         args = kind_selector[1:-1].split('=')
     else:
         args = kind_selector.split('=')
     # end if
     if (len(args) > 2) or (len(args) < 1):
         raise ParseSyntaxError("kind_selector",
                                token=kind_selector,
                                context=context)
     # end if
     if len(args) == 1:
         kind = args[0].strip()
     elif args[0].strip().lower() != 'kind':
         # We have two args, the first better be kind
         raise ParseSyntaxError("kind_selector",
                                token=kind_selector,
                                context=context)
     # end if
     if kind is None:
         # We have two args and the second is our kind string
         kind = args[1].strip()
     # end if
     # One last check for missing right paren
     match = Ftype.__kind_re.search(kind)
     if match is not None:
         if match.group(2) is not None:
             if match.group(2) != match.group(4):
                 raise ParseSyntaxError("kind_selector",
                                        token=kind_selector,
                                        context=context)
             # end if
             if (match.group(1) is None) and (match.group(5) is not None):
                 raise ParseSyntaxError("kind_selector",
                                        token=kind_selector,
                                        context=context)
             # end if
             if (match.group(1) is not None) and (match.group(5) is None):
                 raise ParseSyntaxError("kind_selector",
                                        token=kind_selector,
                                        context=context)
             # end if
         else:
             pass
     elif kind[0:4].lower() == "kind":
         # Got 'something' == 'kind'??
         raise ParseSyntaxError("kind_selector",
                                token=kind_selector,
                                context=context)
     # end if
     return kind
 def __init__(self, line, context):
     """Initialize an extended type from a declaration line"""
     match = FtypeTypeDecl.type_match(line)
     if match is None:
         raise ParseSyntaxError("type declaration",
                                token=line,
                                context=context)
     # end if
     super(FtypeTypeDecl, self).__init__(typestr_in=match.group(2),
                                         kind_in=match.group(2),
                                         match_len_in=len(match.group(0)),
                                         context=context)
     self.__class = match.group(1)
Exemple #10
0
 def add_variable(self, newvar, exists_ok=False):
     """Add a variable if it does not conflict with existing entries"""
     standard_name = newvar.get_prop_value('standard_name')
     if (standard_name in self) and (not exists_ok):
         # We already have a matching variable, error!
         if self._logger is not None:
             self._logger.error("Attempt to add duplicate variable, {} from {}".format(standard_name, newvar.source.name))
         # End if
         raise ParseSyntaxError("Duplicate standard name in {}".format(self.name),
                                token=standard_name, context=newvar._context)
     # End if
     cvar = self.find_variable(standard_name)
     if (cvar is not None) and (not cvar.compatible(newvar, self._logger)):
         if self._logger is not None:
             self._logger.error("Attempt to add incompatible variable, {} from {}".format(standard_name, newvar.source.name))
         # End if
         errstr = "standard name, incompatible with {}"
         raise ParseSyntaxError(errstr.format(cvar.context),
                                token=standard_name,
                                context=newvar.source.context)
     # End if
     # If we make it to here without an exception, add the variable
     self[standard_name] = newvar
Exemple #11
0
def parse_module(pobj, statements, logger=None):
    # 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)
    # After the module name is the specification part
    statements, mheaders = 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 len(statements) > 0:
            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:
                    mheaders.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, mheaders
Exemple #12
0
    def __init__(self, line, context):
        """Initialize a character type from a declaration line"""

        clen = None
        kind = None # This will be interpreted as default kind
        match = Ftype_character.type_match(line)
        if match is None:
            raise ParseSyntaxError("character declaration", token=line, context=context)
        elif len(match.groups()) == 3:
            self._match_len = len(match.group(0))
            # We have an old style character declaration
            if match.group(2) != '*':
                raise ParseSyntaxError("character declaration", token=line, context=context)
            elif Ftype_character.oldchartrail_re.match(line.strip()[len(match.group(0)):]) is None:
                raise ParseSyntaxError("character declaration", token=line, context=context)
            else:
                clen = match.group(3)
            # End if
        elif match.group(2) is not None:
            self._match_len = len(match.group(0))
            # Parse attributes (strip off parentheses)
            attrs = [ x.strip() for x in match.group(2)[1:-1].split(',') ]
            if len(attrs) == 0:
                # Empty parentheses is not allowed
                raise ParseSyntaxError("char_selector", token=match.group(2), context=context)
            if len(attrs) > 2:
                # Too many attributes!
                raise ParseSyntaxError("char_selector", token=match.group(2), context=context)
            elif attrs[0][0:4].lower() == "kind":
                # The first arg is kind, try to parse it
                kind = self.parse_kind_selector(attrs[0], context=context)
                # If there is a second arg, it must be of form len=<length_selector>
                if len(attrs) == 2:
                    clen = self.parse_len_select(attrs[1], context, len_optional=False)
            elif len(attrs) == 2:
                # We have both a len and a kind, len first
                clen = self.parse_len_select(attrs[0], context, len_optional=True)
                kind = self.parse_kind_selector(attrs[1], context)
            else:
                # We just a len argument
                clen = self.parse_len_select(attrs[0], context, len_optional=True)
            # End if
        else:
            self._match_len = len(match.group(0))
            # We had better check the training characters
            if Ftype_character.chartrail_re.match(line.strip()[len(match.group(0)):]) is None:
                raise ParseSyntaxError("character declaration", token=line, context=context)
        # End if
        if clen is None:
            clen = 1
        # End if
        self.lenstr = "{}".format(clen)
        super(Ftype_character, self).__init__(typestr_in=match.group(1), kind_in=kind, context=context)
 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 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
Exemple #15
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
 def __init__(self,
              typestr_in=None,
              kind_in=None,
              match_len_in=None,
              line_in=None,
              context=None):
     """Initialize  this FType object, either using <typestr_in> and
     <kind_in>, OR using line_in."""
     if context is None:
         self.__context = ParseContext()
     else:
         self.__context = ParseContext(context=context)
     # end if
     # We have to distinguish which type of initialization we have
     self.__typestr = typestr_in
     if typestr_in is not None:
         if line_in is not None:
             emsg = "Cannot pass both typestr_in and line_in as arguments"
             raise ParseInternalError(emsg, self.__context)
         # end if
         self.__default_kind = kind_in is None
         if kind_in is None:
             self.__kind = None
         elif kind_in[0] == '(':
             # Parse an explicit kind declaration
             self.__kind = self.parse_kind_selector(kind_in)
         else:
             # The kind has already been parsed for us (e.g., by character)
             self.__kind = kind_in
         # end if
         if match_len_in is not None:
             self.__match_len = match_len_in
         else:
             self.__match_len = len(self.typestr)
             if kind_in is not None:
                 self.__match_len += len(self.__kind) + 2
             # end if
         # end if
     elif kind_in is not None:
         emsg = "kind_in cannot be passed without typestr_in"
         raise ParseInternalError(emsg, self.__context)
     elif line_in is not None:
         match = Ftype.type_match(line_in)
         if match is None:
             emsg = "type declaration"
             raise ParseSyntaxError(emsg,
                                    token=line_in,
                                    context=self.__context)
         # end if
         if match_len_in is not None:
             self.__match_len = match_len_in
         else:
             self.__match_len = len(match.group(0))
         # end if
         if check_fortran_intrinsic(match.group(1)):
             self.__typestr = match.group(1)
             if match.group(2) is not None:
                 # Parse kind section
                 kmatch = match.group(2).strip()
                 self.__kind = self.parse_kind_selector(kmatch)
             else:
                 self.__kind = None
             # end if
             self.__default_kind = self.__kind is None
         else:
             raise ParseSyntaxError("type declaration",
                                    token=line_in,
                                    context=self.__context)
         # end if
     else:
         emsg = "At least one of typestr_in or line_in must be passed"
         raise ParseInternalError(emsg, self.__context)
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
Exemple #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
Exemple #19
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
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
 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)
 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
Exemple #23
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
Exemple #24
0
def scan_free_line(line, in_continue, in_single_char, in_double_char, context):
    """Scan a Fortran line for continue indicators, continued quotes, and
    comments
    Return continue_in_col, continue_out_col, in_single_char, in_double_char,
           comment_col
    >>> scan_free_line("! Comment line", False, False, False, ParseContext())
    (-1, -1, False, False, 0)
    >>> scan_free_line("!! ", False, False, False, ParseContext())
    (-1, -1, False, False, 0)
    >>> scan_free_line("int :: index", False, False, False, ParseContext())
    (-1, -1, False, False, -1)
    >>> scan_free_line("int :: inde& ! oops", False, False, False, ParseContext())
    (-1, 11, False, False, 13)
    >>> scan_free_line("int :: inde&", False, False, False, ParseContext())
    (-1, 11, False, False, -1)
    >>> scan_free_line("character(len=*), parameter :: foo = 'This line & not continued'", False, False, False, ParseContext())
    (-1, -1, False, False, -1)
    >>> scan_free_line("character(len=*), parameter :: foo = 'This is continue line& ", False, False, False, ParseContext())
    (-1, 59, True, False, -1)
    >>> scan_free_line('character(len=*), parameter :: foo = "This line & not continued"', False, False, False, ParseContext())
    (-1, -1, False, False, -1)
    >>> scan_free_line('character(len=*), parameter :: foo = "This is continue line& ', False, False, False, ParseContext())
    (-1, 59, False, True, -1)
    >>> scan_free_line('  & line continued"', True, False, True, ParseContext())
    (2, -1, False, False, -1)
    >>> scan_free_line('  & line continued"', True, True, False, ParseContext()) #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    ParseSyntaxError: Cannot end non-continued line in a character context, in <standard input>
    >>> scan_free_line("  & line continued'", True, False, True, ParseContext()) #doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    ParseSyntaxError: Cannot end non-continued line in a character context, in <standard input>
    >>> scan_free_line("int :: inde&", False, True, False, ParseContext())
    Traceback (most recent call last):
    ParseSyntaxError: Cannot start line in character context if not a continued line, in <standard input>
    >>> scan_free_line("int :: inde&", True, True, True, ParseContext())
    Traceback (most recent call last):
    ParseSyntaxError: Cannot be both in an apostrophe character context and a quote character context, in <standard input>
    """

    # A few sanity checks
    if (in_single_char or in_double_char) and (not in_continue):
        raise ParseSyntaxError(
            "Cannot start line in character context if not a continued line",
            context=context)
    # Endif
    if in_single_char and in_double_char:
        raise ParseSyntaxError(
            "Cannot be both in an apostrophe character context and a quote character context",
            context=context)

    continue_in_col = -1
    continue_out_col = -1
    comment_col = -1

    index = 0
    last_ind = len(line.rstrip()) - 1
    # Is first non-blank character a continue character?
    if line.lstrip()[0] == '&':
        if not in_continue:
            raise ParseSyntaxError(
                "Cannot begin line with continue character (&), not on continued line",
                context=context)
        else:
            continue_in_col = line.find('&')
            index = continue_in_col + 1
        # End if
    # Process rest of line
    while index <= last_ind:
        blank = blank_re.match(line[index:])
        if blank is not None:
            index = index + len(blank.group(0)) - 1  # +1 at end of loop
        elif in_single_char:
            if line[index:min(index + 1, last_ind)] == "''":
                # Embedded single quote
                index = index + 1  # +1 and end of loop
            elif line[index] == "'":
                in_single_char = False
            elif (line[index] == '&'):
                if index == last_ind:
                    continue_out_col = index
                # End if
            # End if (just ignore any other character)
        elif in_double_char:
            if line[index:min(index + 1, last_ind)] == '""':
                # Embedded double quote
                index = index + 1  # +1 and end of loop
            elif line[index] == '"':
                in_double_char = False
            elif line[index] == '&':
                if index == last_ind:
                    continue_out_col = index
                # End if
            # End if (just ignore any other character)
        elif line[index] == "'":
            # If we got here, we are not in a character context, start single
            in_single_char = True
        elif line[index] == '"':
            # If we got here, we are not in a character context, start double
            in_double_char = True
        elif line[index] == '!':
            # If we got here, we are not in a character context, done with line
            comment_col = index
            index = last_ind
        elif line[index] == '&':
            # If we got here, we are not in a character context, note continue
            # First make sure this is a valid continue
            match = continue_re.match(line[index:])
            if match is not None:
                continue_out_col = index
            else:
                raise ParseSyntaxError(
                    "Invalid continue, ampersand not followed by comment character",
                    context=context)
            # End if
        # End if
        index = index + 1
    # End while
    # A final check
    if (in_single_char or in_double_char) and (continue_out_col < 0):
        raise ParseSyntaxError(
            "Cannot end non-continued line in a character context",
            context=context)

    return continue_in_col, continue_out_col, in_single_char, in_double_char, comment_col
Exemple #25
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)
Exemple #26
0
def scan_fixed_line(line, in_single_char, in_double_char, context):
    """Scan a fixed-format FORTRAN line for continue indicators, continued
    quotes, and comments
    Return continue_in_col, in_single_char, in_double_char,
           comment_col
    >>> scan_fixed_line('     & line continued', False, False, ParseContext())
    (5, False, False, -1)
    >>> scan_fixed_line('     & line continued"', False, True, ParseContext())
    (5, False, False, -1)
    >>> scan_fixed_line('     * line continued', False, False, ParseContext())
    (5, False, False, -1)
    >>> scan_fixed_line('     1 line continued', False, False, ParseContext())
    (5, False, False, -1)
    >>> scan_fixed_line('C     comment line', False, False, ParseContext())
    (-1, False, False, 0)
    >>> scan_fixed_line('*     comment line', False, False, ParseContext())
    (-1, False, False, 0)
    >>> scan_fixed_line('!     comment line', False, False, ParseContext())
    (-1, False, False, 0)
    >>> scan_fixed_line(' !    comment line', False, False, ParseContext())
    (-1, False, False, 1)
    >>> scan_fixed_line('    ! comment line', False, False, ParseContext())
    (-1, False, False, 4)
    >>> scan_fixed_line('     ! not comment line', False, False, ParseContext())
    (5, False, False, -1)
    >>> scan_fixed_line('!...................................', False, False, ParseContext())
    (-1, False, False, 0)
    >>> scan_fixed_line('123   x = x + 1', False, False, ParseContext())
    (-1, False, False, -1)
    """

    # Check if comment or continue statement
    cmatch = fixed_comment_re.match(line)
    is_comment = cmatch is not None
    is_continue = fixed_continue_re.match(line) is not None
    # A few sanity checks
    if (in_single_char or in_double_char) and (not is_continue):
        raise ParseSyntaxError(
            "Cannot start line in character context if not a continued line",
            context=context)
    # Endif
    if in_single_char and in_double_char:
        raise ParseSyntaxError(
            "Cannot be both in an apostrophe character context and a quote character context",
            context=context)

    if is_continue:
        continue_in_col = 5
        comment_col = -1
        index = 6
    elif is_comment:
        comment_col = len(cmatch.group(1)) - 1
        continue_in_col = -1
        index = len(line.rstrip())
    else:
        continue_in_col = -1
        comment_col = -1
        index = 0
    # End if

    last_ind = len(line.rstrip()) - 1
    # Process the line
    while index <= last_ind:
        blank = blank_re.match(line[index:])
        if blank is not None:
            index = index + len(blank.group(0)) - 1  # +1 at end of loop
        elif in_single_char:
            if line[index:min(index + 1, last_ind)] == "''":
                # Embedded single quote
                index = index + 1  # +1 and end of loop
            elif line[index] == "'":
                in_single_char = False
                # End if
            # End if (just ignore any other character)
        elif in_double_char:
            if line[index:min(index + 1, last_ind)] == '""':
                # Embedded double quote
                index = index + 1  # +1 and end of loop
            elif line[index] == '"':
                in_double_char = False
                # End if
            # End if (just ignore any other character)
        elif line[index] == "'":
            # If we got here, we are not in a character context, start single
            in_single_char = True
        elif line[index] == '"':
            # If we got here, we are not in a character context, start double
            in_double_char = True
        elif line[index] == '!':
            # If we got here, we are not in a character context, done with line
            comment_col = index
            index = last_ind
        # End if
        index = index + 1
    # End while

    return continue_in_col, in_single_char, in_double_char, comment_col
 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)