예제 #1
0
def test_utf_char_in_code(log):
    ''' Check that we cope with Fortran code that contains UTF characters. This
    is not valid Fortran but most compilers cope with it. '''
    log.reset()
    fort_file = os.path.join(os.path.dirname(__file__), "utf_in_code.f90")
    reader = FortranFileReader(fort_file, ignore_comments=True)
    out_line = reader.get_item()
    while out_line:
        out_line = reader.get_item()
    assert log.messages['critical'] == []
예제 #2
0
파일: fortran.py 프로젝트: metomi/fab
 def _parse_file(self, fpath):
     """Get a node tree from a fortran file."""
     reader = FortranFileReader(str(fpath), ignore_comments=False)
     reader.exit_on_error = False  # don't call sys.exit, it messes up the multi-processing
     try:
         tree = self.f2008_parser(reader)
         return tree
     except FortranSyntaxError as err:
         # we can't return the FortranSyntaxError, it breaks multiprocessing!
         logger.error(f"\nsyntax error in {fpath}\n{err}")
         raise Exception(f"syntax error in {fpath}\n{err}")
     except Exception as err:
         logger.error(f"\nunhandled error '{type(err)}' in {fpath}\n{err}")
         raise Exception(f"unhandled error '{type(err)}' in {fpath}\n{err}")
예제 #3
0
def runner(_, options, args):
    ''' Function to read, parse and output fortran source code '''
    from fparser.two.parser import ParserFactory
    from fparser.two.Fortran2003 import FortranSyntaxError, InternalError
    from fparser.common.readfortran import FortranFileReader
    if not args:
        print("Error: No fortran files specified")
        raise SystemExit(1)
    for filename in args:
        try:
            reader = FortranFileReader(filename)
        except IOError as error:
            print(error)
            return
        if options.mode != 'auto':
            reader.format.from_mode(options.mode)
        try:
            f2003_parser = ParserFactory().create()
            program = f2003_parser(reader)
            print(program)
        except FortranSyntaxError as msg:
            print("Syntax error: {0}".format(str(msg)))
            try:
                # protect the access to fifo_item[-1] in case the fifo
                # buffer is empty
                print('parsing %r failed at %s' %
                      (filename, reader.fifo_item[-1]))
                print('started at %s' % (reader.fifo_item[0]))
            except IndexError:
                pass
            raise SystemExit(1)
        except InternalError as msg:
            print("Internal error in fparser: {0}".format(str(msg)))
            raise SystemExit(1)
예제 #4
0
def runner(_, options, args):
    '''Call the Fortran File reader for each filename in args and print
    out its content.

    :param options: command line argument information from the options \
    parser
    :type options: :py:class:`optparse.Values`
    :param args: a list of Fortran filepaths
    :type args: list of str

    :raises NotImplementedError: if the task option is not set to \
    "show".

    '''
    from fparser.common.readfortran import FortranFileReader
    for filename in args:
        reader = FortranFileReader(filename)
        if options.task == 'show':
            for item in reader:
                print(item)
                sys.stdout.flush()
        else:
            raise NotImplementedError(
                "The task option '{0}' is invalid. Currently only "
                "'show' is supported.".format(repr(options.task)))
예제 #5
0
def parse_fp2(filename):
    '''Parse a Fortran source file contained in the file 'filename' using
    fparser2.

    :param str filename: source file (including path) to read.
    :returns: fparser2 AST for the source file.
    :rtype: :py:class:`fparser.two.Fortran2003.Program`
    :raises ParseError: if the file could not be parsed.

    '''
    parser = ParserFactory().create(std="f2008")
    # We get the directories to search for any Fortran include files from
    # our configuration object.
    config = Config.get()
    try:
        reader = FortranFileReader(filename, include_dirs=config.include_paths)
    except IOError as error:
        raise ParseError(
            "algorithm.py:parse_fp2: Failed to parse file '{0}'. Error "
            "returned was ' {1} '.".format(filename, error))
    try:
        parse_tree = parser(reader)
    except FortranSyntaxError as msg:
        raise ParseError(
            "algorithm.py:parse_fp2: Syntax error in file '{0}':\n"
            "{1}".format(filename, str(msg)))
    return parse_tree
예제 #6
0
def test_bad_file_reader():
    '''
    Tests that the file reader can spot when it is given something to read
    which is neither file nor filename.
    '''
    with pytest.raises(ValueError) as ex:
        unit_under_test = FortranFileReader(42)
    expected = 'FortranFileReader is used with a filename or file-like object.'
    assert expected in str(ex)
예제 #7
0
def check_include_works(fortran_filename,
                        fortran_code,
                        include_info,
                        expected,
                        tmpdir,
                        ignore_comments=True):
    '''Utility function used by a number of tests to check that include
    files work as expected.

    :param str fortran_filename: the name of the fortran file that is \
    going to be created in the 'tmpdir' directory.
    :param str fortran_code: the fortran code to put in the fortran \
    file specified by 'fortran_filename'.
    :param include_info: a list of 2-tuples each with an include \
    filename as a string followed by include code as a string.
    :type include_info: list of (str, str)
    :param str expected: the expected output after parsing the code.
    :param str tmpdir: the temporary directory in which to create and \
    process the Fortran files.
    :param bool ignore_comments: whether to ignore (skip) comments in \
    the Fortran code or not. Defaults to ignore them.

    '''

    try:
        oldpwd = tmpdir.chdir()
        cwd = str(tmpdir)

        # Create the program
        with open(os.path.join(cwd, fortran_filename), "w") as cfile:
            cfile.write(fortran_code)
        for include_filename in include_info.keys():
            with open(os.path.join(cwd, include_filename), "w") as cfile:
                cfile.write(include_info[include_filename])
        reader = FortranFileReader(fortran_filename,
                                   ignore_comments=ignore_comments)
        for orig_line in expected.split("\n"):
            new_line = reader.next().line
            assert new_line == orig_line
        with pytest.raises(StopIteration):
            reader.next()
    finally:
        oldpwd.chdir()
예제 #8
0
def test_filename_reader():
    '''
    Tests that a Fortran source file can be read given its filename.
    '''
    handle, filename = tempfile.mkstemp(suffix='.f90', text=True)
    os.close(handle)
    try:
        with io.open(filename, mode='w', encoding='UTF-8') as source_file:
            source_file.write(FULL_FREE_SOURCE)

        unit_under_test = FortranFileReader(filename)
        expected = fparser.common.sourceinfo.FortranFormat(True, False)
        assert unit_under_test.format == expected
        for expected in FULL_FREE_EXPECTED:
            found = unit_under_test.get_single_line(ignore_empty=True)
            assert found == expected
    except Exception:
        os.unlink(filename)
        raise
예제 #9
0
def test_file_reader():
    '''
    Tests that a Fortran source file can be read given a file object of it.
    '''
    handle, filename = tempfile.mkstemp(suffix='.f90', text=True)
    os.close(handle)
    try:
        with open(filename, mode='w') as source_file:
            print(FULL_FREE_SOURCE, file=source_file)

        with open(filename, mode='r') as source_file:
            unit_under_test = FortranFileReader(source_file)

            expected = fparser.common.sourceinfo.FortranFormat(True, False)
            assert unit_under_test.format == expected
            for expected in FULL_FREE_EXPECTED:
                assert unit_under_test.get_single_line(ignore_empty=True) \
                       == expected
    except Exception:
        os.unlink(filename)
        raise
예제 #10
0
def test_none_in_fifo(log):
    ''' Check that a None entry in the reader FIFO buffer is handled
    correctly. '''
    log.reset()
    handle, filename = tempfile.mkstemp(suffix='.f90', text=True)
    os.close(handle)

    with io.open(filename, mode='w', encoding='UTF-8') as source_file:
        source_file.write(FULL_FREE_SOURCE)

    with io.open(filename, mode='r', encoding='UTF-8') as source_file:
        unit_under_test = FortranFileReader(source_file)
        while True:
            try:
                _ = unit_under_test.next(ignore_comments=False)
            except StopIteration:
                break
        # Erroneously push a None to the FIFO buffer
        unit_under_test.put_item(None)
        # Attempt to read the next item
        with pytest.raises(StopIteration):
            _ = unit_under_test.next(ignore_comments=False)
        # Check that nothing has been logged
        for log_level in ["debug", "info", "warning", "error", "critical"]:
            assert log.messages[log_level] == []
예제 #11
0
def test_new_kernel_file(tmpdir, monkeypatch):
    ''' Check that we write out the transformed kernel to the CWD. '''
    from fparser.two import Fortran2003, parser
    from fparser.common.readfortran import FortranFileReader
    # Ensure kernel-output directory is uninitialised
    config = Config.get()
    monkeypatch.setattr(config, "_kernel_output_dir", "")
    monkeypatch.setattr(config, "_kernel_naming", "multiple")
    # Change to temp dir (so kernel written there)
    old_cwd = tmpdir.chdir()
    psy, invoke = get_invoke("nemolite2d_alg_mod.f90", api="gocean1.0", idx=0)
    sched = invoke.schedule
    kern = sched.children[0].loop_body[0].loop_body[0]
    rtrans = ACCRoutineTrans()
    _, _ = rtrans.apply(kern)
    # Generate the code (this triggers the generation of a new kernel)
    code = str(psy.gen).lower()
    # Work out the value of the tag used to re-name the kernel
    tag = re.search('use continuity(.+?)_mod', code).group(1)
    assert ("use continuity{0}_mod, only: continuity{0}_code".format(tag)
            in code)
    assert "call continuity{0}_code(".format(tag) in code
    # The kernel and module name should have gained the tag just identified
    # and be written to the CWD
    filename = os.path.join(str(tmpdir), "continuity{0}_mod.f90".format(tag))
    assert os.path.isfile(filename)
    # Parse the new kernel file
    f2003_parser = parser.ParserFactory().create()
    reader = FortranFileReader(filename)
    prog = f2003_parser(reader)
    # Check that the module has the right name
    modules = walk_ast(prog.content, [Fortran2003.Module_Stmt])
    assert str(modules[0].items[1]) == "continuity{0}_mod".format(tag)
    # Check that the subroutine has the right name
    subs = walk_ast(prog.content, [Fortran2003.Subroutine_Stmt])
    found = False
    for sub in subs:
        if str(sub.items[1]) == "continuity{0}_code".format(tag):
            found = True
            break
    assert found
    # Check that the kernel type has been re-named
    dtypes = walk_ast(prog.content, [Fortran2003.Derived_Type_Def])
    names = walk_ast(dtypes[0].content, [Fortran2003.Type_Name])
    assert str(names[0]) == "continuity{0}_type".format(tag)

    from gocean1p0_build import GOcean1p0Build
    # If compilation fails this will raise an exception
    GOcean1p0Build(tmpdir).compile_file(filename)

    old_cwd.chdir()
def test_nemo_find_container_symbol(parser):
    ''' Check that find_or_create_symbol() works for the NEMO API when the
    searched-for symbol is declared in the parent module. '''
    reader = FortranFileReader(
        os.path.join(
            os.path.dirname(
                os.path.dirname(os.path.dirname(os.path.abspath(__file__)))),
            "test_files", "gocean1p0", "kernel_with_global_mod.f90"))
    prog = parser(reader)
    psy = PSyFactory("nemo", distributed_memory=False).create(prog)
    # Get a node from the schedule
    bops = psy._invokes.invoke_list[0].schedule.walk(BinaryOperation)
    # Use it as the starting point for the search
    symbol = _find_or_create_imported_symbol(bops[0], "alpha")
    assert symbol.datatype.intrinsic == ScalarType.Intrinsic.REAL
예제 #13
0
파일: f2003.py 프로젝트: kdeyev/fparser
def runner(parser, options, args):
    from fparser.two import Fortran2003
    from fparser.common.readfortran import FortranFileReader
    for filename in args:
        reader = FortranFileReader(filename)
        if options.mode != 'auto':
            mode = fparser.common.sourceinfo\
                   .FortranFormat.from_mode(options.mode)
            reader.format.set_mode(mode)
        try:
            program = Fortran2003.Program(reader)
            print(program)
        except Fortran2003.NoMatchError as msg:
            print('parsing %r failed at %s' % (filename, reader.fifo_item[-1]))
            print('started at %s' % (reader.fifo_item[0]))
            print('quiting')
            return
예제 #14
0
파일: parse.py 프로젝트: kdeyev/fparser
def runner(parser, options, args):
    from fparser.common.readfortran import FortranFileReader
    from fparser.one.parsefortran import FortranParser
    for filename in args:
        reader = FortranFileReader(filename)
        if options.mode != 'auto':
            mode = fparser.common.sourceinfo\
                   .FortranFormat.from_mode(options.mode)
            reader.format.set_mode(mode)
        parser = FortranParser(reader)
        parser.parse()
        parser.analyze()
        if options.task == 'show':
            print(parser.block.torepr(4))
        elif options.task == 'none':
            pass
        else:
            raise NotImplementedError(repr(options.task))
예제 #15
0
def test_inherited_f77():
    '''
    A grab bag of functional tests inherited from readfortran.py.
    '''
    string_f77 = """c -*- f77 -*-
c12346 comment
      subroutine foo
      call foo
     'bar
a    'g
      abc=2
cf2py call me ! hey
      call you ! hi
      end
     '"""
    expected = ["Comment('c -*- f77 -*-',(1, 1))",
                "Comment('c12346 comment',(2, 2))",
                "line #3'subroutine foo'",
                "line #4'call foobar'",
                'Comment("a    \'g",(6, 6))',
                "line #7'abc=2'",
                "line #9'call you ! hi'",
                "line #10'end'"]

    # Reading from buffer
    reader = FortranStringReader(
        string_f77, ignore_comments=False)
    assert reader.format.mode == 'f77', repr(reader.format.mode)
    stack = expected[:]
    for item in reader:
        assert str(item) == stack.pop(0)

    # Reading from file
    handle, filename = tempfile.mkstemp(suffix='.f', text=True)
    os.close(handle)
    with open(filename, 'w') as fortran_file:
        print(string_f77, file=fortran_file)

    reader = FortranFileReader(
        filename, ignore_comments=False)
    stack = expected[:]
    for item in reader:
        assert str(item) == stack.pop(0)
예제 #16
0
def runner(_, options, args):
    '''
    Function to read, parse and output Fortran source code.

    :param options: object constructed by OptionParser with cmd-line flags.
    :param args: list of Fortran files to parse.
    :type args: list of str

    '''
    import six
    from fparser.two.parser import ParserFactory
    from fparser.two.Fortran2003 import FortranSyntaxError, InternalError
    from fparser.common.readfortran import FortranFileReader
    if not args:
        print("Error: No fortran files specified", file=sys.stderr)
        raise SystemExit(1)
    for filename in args:
        print("File: '{0}'".format(filename), file=sys.stderr)
        try:
            reader = FortranFileReader(filename, ignore_comments=False)
        except IOError as error:
            print(error, file=sys.stderr)
            continue
        try:
            fparser = ParserFactory().create(std=options.std)
            program = fparser(reader)
            if options.task == "show":
                print(six.text_type(program))
            if options.task == "repr":
                print(repr(program))
        except FortranSyntaxError as msg:
            print("Syntax error: {0}".format(six.text_type(msg)),
                  file=sys.stderr)
        except InternalError as msg:
            print("Internal error in fparser: {0}".format(six.text_type(msg)),
                  file=sys.stderr)
예제 #17
0
파일: api.py 프로젝트: vamironov/fparser
def get_reader(source,
               isfree=None,
               isstrict=None,
               include_dirs=None,
               source_only=None,
               ignore_comments=True):
    '''
    Returns Fortran reader instance.

    If ``source`` is a C filename then the functions searches for comment
    lines starting with ``/*f2py`` and reads following lines as PYF file
    content until a line ``*/`` is found.

    :param str source: Specify a string or filename containing Fortran code.
    :param bool isfree: True if Fortran is free format
    :param bool isstrict: True if we are to strictly enforce free/fixed format
    :param list include_dirs: Specify a list of include directories. The
                              default list (when include_dirs=None) contains
                              the current working directory and the directory
                              of ``source``.
    :param list source_only: Specify a list of Fortran file names that are
                             searched when the ``USE`` statement is
                             encountered.
    :param bool ignore_comments: Whether or not to ignore (and discard)
                                 comments when parsing the source.

    :returns: a reader instance
    :rtype: :py:class:`fparser.common.readfortran.FortranReader`
    '''
    import os
    import re
    from fparser.common.readfortran import FortranFileReader, \
        FortranStringReader
    from fparser.common.sourceinfo import FortranFormat

    if os.path.isfile(source):
        _name, ext = os.path.splitext(source)
        if ext.lower() in ['.c']:
            # get signatures from C file comments starting with
            # `/*f2py` and ending with `*/`.
            # TODO: improve parser to take line number offset making line
            #       numbers in parser messages correct.
            f2py_c_comments = re.compile(r'/[*]\s*f2py\s.*[*]/', re.I | re.M)
            handle = open(source, 'r')
            c_input = ''
            for line in f2py_c_comments.findall(handle.read()):
                c_input += line[2:-2].lstrip()[4:] + '\n'
            handle.close()
            if isfree is None:
                isfree = True
            if isstrict is None:
                isstrict = True
            return parse(c_input, isfree, isstrict, include_dirs)
        reader = FortranFileReader(source,
                                   include_dirs=include_dirs,
                                   source_only=source_only,
                                   ignore_comments=ignore_comments)
    elif isinstance(source, string_types):
        reader = FortranStringReader(source,
                                     include_dirs=include_dirs,
                                     source_only=source_only,
                                     ignore_comments=ignore_comments)
    else:
        raise TypeError('Expected string or filename input but got %s' %
                        (type(input)))
    if isfree is None:
        isfree = reader.format.is_free
    if isstrict is None:
        isstrict = reader.format.is_strict
    reader.set_format(FortranFormat(isfree, isstrict))
    return reader
예제 #18
0
if __name__ == "__main__":
    if len(sys.argv) < 2:
        usage()

    # Apparently pylint thinks that `all_files` is a constant, and complains
    # that it should be capitalised.
    # pylint: disable=invalid-name
    all_files = sys.argv[1:]

    # Sort the input file names, so that they are output alphabetically
    all_files.sort()
    for filename in all_files:

        # Parse the current source file:
        try:
            reader = FortranFileReader(filename)
        except IOError:
            print("Could not open file '{0}'.".format(filename),
                  file=sys.stderr)
            sys.exit(-1)

        parser = ParserFactory().create(std="f2003")
        parse_tree = parser(reader)

        # Collect all used modules in a list
        all_use = []
        for node in walk(parse_tree, Use_Stmt):
            use_name = str(node.items[2])
            # Nothing else to do if the name is already in the list:
            if use_name + ".o" in all_use:
                continue