def get_integer_variable(self, name): ''' Parse the kernel meta-data and find the value of the integer variable with the supplied name. Return None if no matching variable is found. :param str name: the name of the integer variable to find. :returns: value of the specified integer variable or None. :rtype: str :raises ParseError: if the RHS of the assignment is not a Name. ''' # Ensure the Fortran2003 parser is initialised _ = ParserFactory().create() for statement, _ in fpapi.walk(self._ktype, -1): if isinstance(statement, fparser1.typedecl_statements.Integer): # fparser only goes down to the statement level. We use # fparser2 to parse the statement itself (eventually we'll # use fparser2 to parse the whole thing). assign = Fortran2003.Assignment_Stmt(statement.entity_decls[0]) if str(assign.items[0]) == name: if not isinstance(assign.items[2], Fortran2003.Name): raise ParseError( "get_integer_variable: RHS of assignment is not " "a variable name: '{0}'".format(str(assign))) return str(assign.items[2]) return None
def test_parser_caseinsensitive2(monkeypatch): '''Check that the test for the existance of a kernel call in a use statement is case insensitive. ''' def dummy_func(arg1, arg2, arg3, arg4): '''A dummy function used by monkeypatch to override the get_kernel_ast function. We don't care about the arguments as we just want to raise an exception. ''' # pylint: disable=unused-argument raise NotImplementedError("test_parser_caseinsensitive2") monkeypatch.setattr("psyclone.parse.kernel.get_kernel_ast", dummy_func) from fparser.two import Fortran2003 as f2003 from fparser.two.parser import ParserFactory ParserFactory().create(std="f2003") parser = Parser() use = f2003.Use_Stmt("use my_mod, only : MY_KERN") parser.update_arg_to_module_map(use) with pytest.raises(NotImplementedError) as excinfo: # We have monkeypatched the function 'get_kernel_ast' to # return 'NotImplementedError' with a string associated with # this test so we know that we have got to this function if # this exception is raised. The case insensitive test we # really care about is before this function is called (and it # raises a ParseError) so we know that if we don't get a # ParseError then all is well. parser.create_coded_kernel_call("My_Kern", None) # Sanity check that the exception is the monkeypatched one. assert str(excinfo.value) == "test_parser_caseinsensitive2"
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)
def create_schedule(code, routine_name, ast_processor=Fparser2Reader): '''Utility function that returns a PSyIR tree from Fortran code using fparser2 and (by default) Fparser2Reader. :param str code: Fortran code. :param str routine_name: the name of the Fortran routine for which to \ create the PSyIR tree. :param ast_processor: the particular front-end to use. Defaults \ to Fparser2Reader. :type ast_processor: :py:class:`psyclone.psyGen.Fparser2Reader` :returns: PSyIR tree representing the Fortran code. :rtype: Subclass of :py:class:`psyclone.psyGen.Node` ''' reader = FortranStringReader(code) f2003_parser = ParserFactory().create(std="f2003") parse_tree = f2003_parser(reader) # Generate PSyIR schedule from fparser2 parse tree processor = ast_processor() schedule = processor.generate_schedule(routine_name, parse_tree) return schedule
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
def parser(): ''' Creates and returns an fparser object. Since this is expensive we only do this once per test session (scope="session" above). ''' from fparser.two.parser import ParserFactory return ParserFactory().create()
def test_fw_codeblock(): '''Check the FortranWriter class codeblock method correctly prints out the Fortran code contained within it. ''' # Generate fparser2 parse tree from Fortran code. code = ( "module test\n" "contains\n" "subroutine tmp()\n" " integer :: a\n" " a=1\n" "end subroutine tmp\n" "end module test") schedule = create_schedule(code) code1 = ( "print *, 'I am a code block'\n" "print *, 'with more than one line'\n") _ = ParserFactory().create(std="f2003") reader = get_reader(code1) statements = Fortran2003.Execution_Part(reader) code_block = CodeBlock([statements], parent=schedule) schedule.addchild(code_block) # Generate Fortran from the PSyIR schedule fvisitor = FortranWriter() result = fvisitor(schedule) assert ( " a=1\n" "PRINT *, 'I am a code block'\n" " PRINT *, 'with more than one line'\n" in result)
def f2003_parser(): '''Create a Fortran 2003 parser class hierarchy and return the parser for usage in tests. :return: a Program class (not object) for use with the Fortran reader. :rtype: :py:class:`fparser.two.Fortran2003.Program` ''' return ParserFactory().create(std='f2003')
def clear_fparser(): ''' The next test assumes that fparser has not been initialised. This is achieved by calling `_setup([])` with an empty list, which will remove all currently existing parser classes and functions. At the end of the tests re-initialse parser. This must be done in a fixture, since in case of a failure we still have to make sure that fparser gets properly re-initialised. ''' # Remove all fparser classes and functions ParserFactory()._setup([]) # Now execute all tests yield # We need to properly initialise fparser, # otherwise followup tests will fail (if this test should fail) ParserFactory().create(std="f2008")
def parser(): ''' Creates and returns an fparser object. Since this is expensive we only do this once per test session (scope="session" above). Note: If this fixture is not used to get the fparser parse tree but is used as just a step in getting the PSyIR, use the fortran_reader fixture below. ''' return ParserFactory().create(std="f2008")
def test_parser_caseinsensitive1(): '''Check that the test for the existance of a builtin call in a use statement is case insensitive. ''' ParserFactory().create(std="f2003") parser = Parser() use = Use_Stmt("use my_mod, only : SETVAL_X") parser.update_arg_to_module_map(use) with pytest.raises(ParseError) as excinfo: parser.create_builtin_kernel_call("SetVal_X", None) assert "A built-in cannot be named in a use statement" \ in str(excinfo.value)
def test_parserfactory_std(): '''Test ParserFactory std argument options [none, f2003, f2008 and invalid]. Also test that previous calls to the create method in the ParserFactory class do not affect current calls. ''' fstring = ( "submodule (x) y\n" "end\n") parser = ParserFactory().create() reader = FortranStringReader(fstring) with pytest.raises(NoMatchError) as excinfo: _ = parser(reader) assert "at line 1\n>>>submodule (x) y\n" in str(excinfo.value) parser = ParserFactory().create(std="f2003") reader = FortranStringReader(fstring) with pytest.raises(NoMatchError) as excinfo: _ = parser(reader) assert "at line 1\n>>>submodule (x) y\n" in str(excinfo.value) parser = ParserFactory().create(std="f2008") reader = FortranStringReader(fstring) ast = parser(reader) code = str(ast) assert "SUBMODULE (x) y\nEND SUBMODULE y" in code # Repeat f2003 example to make sure that a previously valid (f2008) # match does not affect the current (f2003) invalid match. parser = ParserFactory().create(std="f2003") reader = FortranStringReader(fstring) with pytest.raises(NoMatchError) as excinfo: _ = parser(reader) assert "at line 1\n>>>submodule (x) y\n" in str(excinfo.value) # TODO: raise exception here, see issue #52 with pytest.raises(SystemExit): parser = ParserFactory().create(std="invalid")
def get_tree(self) -> fortran2003.Program_Unit: if not self._tree: # We don't use the tree directly. Instead we let all the decorators # have a go first. reader = readfortran.FortranStringReader(self._text.get_text(), ignore_comments=False) fortran_parser = ParserFactory().create(std='f2008') try: self._tree: fortran2003.Program_Unit = fortran_parser(reader) self._tree_error = None except FparserException as ex: self._tree = None self._tree_error = str(ex) return self._tree
def get_integer_array(self, name): ''' Parse the kernel meta-data and find the values of the integer array variable with the supplied name. Returns an empty list if no matching variable is found. :param str name: the name of the integer array to find. :returns: list of values. :rtype: list of str. :raises InternalError: if we fail to parse the LHS of the array \ declaration or the array constructor. :raises ParseError: if the RHS of the declaration is not an array \ constructor. ''' # Ensure the classes are setup for the Fortran2003 parser _ = ParserFactory().create() for statement, _ in fpapi.walk(self._ktype, -1): if not isinstance(statement, fparser1.typedecl_statements.Integer): # This isn't an integer declaration so skip it continue # fparser only goes down to the statement level. We use fparser2 to # parse the statement itself. assign = Fortran2003.Assignment_Stmt(statement.entity_decls[0]) names = walk_ast(assign.items, [Fortran2003.Name]) if not names: raise InternalError( "Unsupported assignment statement: '{0}'".format( str(assign))) if str(names[0]) == name: # This is the variable declaration we're looking for if not isinstance(assign.items[2], Fortran2003.Array_Constructor): raise ParseError( "get_integer_array: RHS of assignment is not " "an array constructor: '{0}'".format(str(assign))) # fparser2 AST for Array_Constructor is: # Array_Constructor('[', Ac_Value_List(',', (Name('w0'), # Name('w1'))), ']') # Construct a list of the names in the array constructor names = walk_ast(assign.items[2].items, [Fortran2003.Name]) if not names: raise InternalError("Failed to parse array constructor: " "'{0}'".format(str(assign.items[2]))) return [str(name) for name in names] return []
def get_tree(self) -> Optional[Fortran2003.Program]: if not self._tree: # We don't use the tree directly. Instead we let all the decorators # have a go first. reader = readfortran.FortranStringReader(self._text.get_text(), ignore_comments=False) # Pycharm complains about a type mismatch at this point but MyPy # doesn't. # fortran_parser: Type[Fortran2003.Program] \ = ParserFactory().create(std='f2008') try: self._tree: Fortran2003.Program = fortran_parser(reader) self._tree_error = None except FparserException as ex: self._tree = None self._tree_error = str(ex) return self._tree
def create_schedule(code): '''Utility function that returns a PSyIR tree from Fortran code using fparser2 and Fparser2ASTProcessor. :param str code: Fortran code. :returns: PSyIR tree representing the Fortran code. :rtype: Subclass of :py:class:`psyclone.psyGen.Node` ''' reader = FortranStringReader(code) f2003_parser = ParserFactory().create(std="f2003") parse_tree = f2003_parser(reader) # Generate PSyIR schedule from fparser2 parse tree processor = Fparser2ASTProcessor() schedule = processor.generate_schedule("tmp", parse_tree) return schedule
def extend(self, snippet): from fparser.two.parser import ParserFactory from fparser.common.readfortran import FortranStringReader source = """ PROGRAM main contains ! NOTE: I'm exploiting a bug here. ! :( https://github.com/stfc/fparser/issues/136 {} END PROGRAM main """.format(snippet).strip() parser = ParserFactory().create(std="f2008") try: reader = FortranStringReader(source) program = parser(reader) except Exception: # FortranSyntaxError reader = FortranStringReader(snippet) program = parser(reader) cell_prog = Program.process(program) self.programs.append(cell_prog)
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)
from psyclone.parse import parse from psyclone.psyGen import PSyFactory, InternalError, GenerationError, \ CodeBlock from psyclone import nemo from fparser.common.readfortran import FortranStringReader from fparser.two import Fortran2003 from fparser.two.parser import ParserFactory from fparser.two.utils import walk_ast # Constants API = "nemo" # Location of the Fortran files associated with these tests BASE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_files") # Fortran parser _PARSER = ParserFactory().create() def test_unamed_unit(): ''' Test that we raise the expected internal error if we fail to find a name for the PSy object. ''' code = ("program simple\n" " ztmp(:,:,:) = 0.0\n" "end program\n") reader = FortranStringReader(code) prog = Fortran2003.Program_Unit(reader) psy = PSyFactory(API, distributed_memory=False).create(prog) assert psy._name == "simple_psy" # We have to work quite hard to trigger the internal error that is # raised when no names are found. # Delete most of the AST
def get_integer_array(self, name): ''' Parse the kernel meta-data and find the values of the integer array variable with the supplied name. Returns an empty list if no matching variable is found. The search is not case sensitive. :param str name: the name of the integer array to find. :return: list of values (lower-case). :rtype: list of str. :raises InternalError: if we fail to parse the LHS of the array \ declaration or the array constructor. :raises ParseError: if the array is not of rank 1. :raises ParseError: if the array extent is not specified using an \ integer literal. :raises ParseError: if the RHS of the declaration is not an array \ constructor. :raises InternalError: if the parse tree for the array constructor \ does not have the expected structure. :raises ParseError: if the number of items in the array constructor \ does not match the extent of the array. ''' # Ensure the classes are setup for the Fortran2008 parser _ = ParserFactory().create(std="f2008") # Fortran is not case sensitive so nor is our matching lower_name = name.lower() for statement, _ in fpapi.walk(self._ktype): if not isinstance(statement, fparser1.typedecl_statements.Integer): # This isn't an integer declaration so skip it continue # fparser only goes down to the statement level. We use fparser2 to # parse the statement itself. assign = Fortran2003.Assignment_Stmt(statement.entity_decls[0]) names = walk(assign.children, Fortran2003.Name) if not names: raise InternalError("Unsupported assignment statement: '{0}'". format(str(assign))) if str(names[0]).lower() != lower_name: # This is not the variable declaration we're looking for continue if not isinstance(assign.children[0], Fortran2003.Part_Ref): # Not an array declaration return [] if not isinstance(assign.children[0].children[1], Fortran2003.Section_Subscript_List): raise InternalError( "get_integer_array: expected array declaration to have a " "Section_Subscript_List but found '{0}' for: '{1}'".format( type(assign.children[0].children[1]).__name__, str(assign))) dim_stmt = assign.children[0].children[1] if len(dim_stmt.children) != 1: raise ParseError( "get_integer_array: array must be 1D but found an array " "with {0} dimensions for name '{1}'".format( len(dim_stmt.children), name)) if not isinstance(dim_stmt.children[0], Fortran2003.Int_Literal_Constant): raise ParseError( "get_integer_array: array extent must be specified using " "an integer literal but found '{0}' for array '{1}'". format(str(dim_stmt.children[0]), name)) # Get the declared size of the array array_extent = int(str(dim_stmt.children[0])) if not isinstance(assign.children[2], Fortran2003.Array_Constructor): raise ParseError( "get_integer_array: RHS of assignment is not " "an array constructor: '{0}'".format(str(assign))) # fparser2 AST for Array_Constructor is: # Array_Constructor('[', Ac_Value_List(',', (Name('w0'), # Name('w1'))), ']') # Construct a list of the names in the array constructor names = walk(assign.children[2].children, Fortran2003.Name) if not names: raise InternalError("Failed to parse array constructor: " "'{0}'".format(str(assign.items[2]))) if len(names) != array_extent: # Ideally fparser would catch this but it isn't yet mature # enough. raise ParseError( "get_integer_array: declared length of array '{0}' is {1} " "but constructor only contains {2} names: '{3}'".format( name, array_extent, len(names), str(assign))) return [str(name).lower() for name in names] # No matching declaration for the provided name was found return []
def __init__(self): if not self._parser: self._parser = ParserFactory().create(std="f2008") self._processor = Fparser2Reader()
def f2003_create(): '''Create a fortran 2003 parser class hierarchy''' _ = ParserFactory().create(std="f2003")
def perform(self, targs): astlist = {} srcprog = {} if len(targs.src) == 0 and "srclist" not in self.env: print("ERROR: no input source file.") else: srclist = {} if "srclist" in self.env: srclist.update(self.env["srclist"]) aliases = {} if targs.alias: for alias in targs.alias: for varg in alias.vargs: adef = varg.split("=", 1) if len(adef) == 2: aliases[adef[1].strip()] = adef[0].strip() else: raise pyloco.UsageError("Wrong alias syntax: %s" % c) macros = {} if targs.macro: for m in targs.macro: for v in m.vargs: macros[v] = None for k, v in m.kwargs.items(): macros[k] = v includes = [] if targs.include: for i in targs.include: paths = i.split(":") apaths = self.gen_aliases(paths, aliases) includes.extend([s.strip() for s in paths]) includes.extend([s.strip() for s in apaths]) if targs.src: for path in targs.src: srclist[path] = (macros, includes) for path, (macros, includes) in srclist.items(): print("parsing '{}'...".format(path), end=" ") sys.stdout.flush() try: pp = "cpp" flags = "-w -traditional -P" pack_macros = [] for k, v in macros.items(): if v is None: pack_macros.append("-D{}".format(k)) else: pack_macros.append("-D{0}={1}".format(k, v)) pack_includes = [] aincludes = self.gen_aliases(includes, aliases) for p in includes + aincludes: pack_includes.append("-I{}".format(p)) if not os.path.isfile(path): apaths = self.gen_aliases([path], aliases) if apaths and os.path.isfile(apaths[0]): path = apaths[0] else: print("'%s' does not exist.".format(path)) continue with open(path) as fr: code = fr.read() if type(code) == type(u'A'): code = code.encode('utf-8') output, err, retcode = run_shcmd( '%s %s %s %s' % (pp, flags, " ".join(pack_includes), " ".join(pack_macros)), input=code) if targs.save: root, ext = os.path.splitext( os.path.basename(path)) savepath = root + ".pre" with open(savepath, 'w') as fw: fw.write(output) if type(output) != type(u'A'): output = output.decode('utf-8') srcprog[path] = output reader = FortranStringReader(output, ignore_comments=False) reader.id = path f2008_parser = ParserFactory().create(std="f2008") ast = f2008_parser(reader) astlist[path] = ast print("DONE.") except FortranSyntaxError as err: print("FAILED Syntax with '{}'.".format(str(err))) except NameError as err: print("FAILED Name with '{}'.".format(str(err))) except IOError as err: print("FAILED I/O with '{}'.".format(str(err))) except Exception as err: print("FAILED {0} with '{1}'.".format( err.__class__.__name__, str(err))) return 0, {"astlist": astlist, "srcprog": srcprog}, {}
from fparser.two.Fortran2003 import Part_Ref, Structure_Constructor, \ Data_Ref, Proc_Component_Ref, Name, Call_Stmt, Use_Stmt, \ Actual_Arg_Spec, Program from fparser.two.parser import ParserFactory from psyclone.parse.algorithm import Parser, get_invoke_label, \ get_kernel, create_var_name, KernelCall, BuiltInCall, Arg, \ FileInfo from psyclone.parse.utils import ParseError, parse_fp2 from psyclone.errors import InternalError LFRIC_TEST_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.path.pardir, "test_files", "dynamo0p3") # This ParserFactory call needs to happen at the top-level in order for the # fparser.two.Fortran2003 import to work as expected. ParserFactory().create(std="f2008") # class Parser() tests # Parser.parse() method tests def test_parser_parse_linelength(): '''Check that the parse() method in the Parser() class raises an exception if one or more of the lines is too long (>132 characters) in the supplied input file when _line_length is set to True and does not raise an exception by default. ''' parser = Parser() parser.parse(os.path.join(LFRIC_TEST_PATH, "13_alg_long_line.f90"))
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. '''A simple fparser2 Fortran2008 example demonstrating support for submodules''' from fparser.two.parser import ParserFactory from fparser.common.readfortran import FortranStringReader MYFILE = ''' program hello integer a end program hello submodule (hello2) world end submodule world subroutine world2 end subroutine world2 ''' READER = FortranStringReader(MYFILE) F2008_PARSER = ParserFactory().create(std="f2008") PROGRAM = F2008_PARSER(READER) print(PROGRAM)
def __init__(self, std="f2008", ignore_mod_deps=None): self.f2008_parser = ParserFactory().create(std=std) self.ignore_mod_deps = ignore_mod_deps or [] # Warn the user if the code still includes this deprecated dependency mechanism self.depends_on_comment_found = False
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. '''File containing unit tests for the BinaryOpBase baseclass in utils.py ''' import pytest from fparser.two.utils import BinaryOpBase, NoMatchError from fparser.two.Fortran2003 import Name, Real_Literal_Constant, \ Int_Literal_Constant, Complex_Literal_Constant, Level_4_Expr import fparser.two.pattern_tools as fparser_patterns from fparser.two.parser import ParserFactory # This is required to setup the fortran2003 classes (when matching # with Complex_Literal_Constant) _ = ParserFactory().create(std="f2003") @pytest.mark.parametrize('pattern', ["%", fparser_patterns.percent_op]) @pytest.mark.parametrize('right', [True, False]) def test_binaryopbase_pattern_nomatch(pattern, right): '''Test the BinaryOpBase match method returns None if the pattern is of type 'str' or 'Pattern' and is not found in the string. Check with the optional 'right' argument set to True and False. ''' string = "ab" result = BinaryOpBase.match(None, pattern, None, string, right=right) assert result is None
def fixture_f2008_parser(): ''' Initialise fparser2 with Fortran2008 standard. ''' return ParserFactory().create(std="f2008")
from __future__ import absolute_import import six import pytest from fparser.two.Fortran2003 import Part_Ref, Structure_Constructor, \ Data_Ref, Proc_Component_Ref, Name, Call_Stmt, Use_Stmt, \ Actual_Arg_Spec from fparser.two.parser import ParserFactory from psyclone.parse.algorithm import Parser, get_invoke_label, \ get_kernel, create_var_name, KernelCall, BuiltInCall, Arg from psyclone.parse.utils import ParseError from psyclone.errors import InternalError ParserFactory().create() # class parser() tests def test_parser_parse(tmpdir): '''Test that if no relevant code is found in the algorithm file then the appropriate exception is raised. ''' tmp = Parser() filename = str(tmpdir.join("empty.f90")) ffile = open(filename, "w") ffile.write("") ffile.close() with pytest.raises(ParseError) as excinfo: