def test_use_mixed_case(f2003_create): '''Check that a use statement with mixed case keywords ('use' and 'only') works as expected. ''' line = "UsE my_model, OnLy: name" ast = Use_Stmt(line) assert "USE my_model, ONLY: name" in str(ast) assert repr(ast) == ("Use_Stmt(None, None, Name('my_model'), ', ONLY:', " "Name('name'))")
def test_use_spaces_2(f2003_create): '''Check that a use statement with spaces works correctly with an only clause. ''' line = " use , intrinsic :: my_model , only : name " ast = Use_Stmt(line) assert "USE, INTRINSIC :: my_model, ONLY: name" in str(ast) assert repr(ast) == ("Use_Stmt(Module_Nature('INTRINSIC'), '::', " "Name('my_model'), ', ONLY:', Name('name'))")
def test_use_only_empty(f2003_create): '''Check that a use statement is parsed correctly when there is an only clause without any content. ''' line = "use my_model, only:" ast = Use_Stmt(line) assert "USE my_model, ONLY:" in str(ast) assert repr(ast) == ( "Use_Stmt(None, None, Name('my_model'), ', ONLY:', None)")
def test_use_spaces_1(f2003_create): '''Check that a use statement with spaces works correctly with renaming. ''' line = " Use , intrinsic :: my_model , name=>new_name " ast = Use_Stmt(line) assert "USE, INTRINSIC :: my_model, name => new_name" in str(ast) assert repr(ast) == ( "Use_Stmt(Module_Nature('INTRINSIC'), '::', Name('my_model'), ',', " "Rename(None, Name('name'), Name('new_name')))")
def test_use_only(f2003_create): '''Check that a use statement is parsed correctly when there is an only clause. ''' line = "use my_model, only: name" ast = Use_Stmt(line) assert "USE my_model, ONLY: name" in str(ast) assert repr(ast) == ( "Use_Stmt(None, None, Name('my_model'), ', ONLY:', Only_List(',', " "(Name('name'),)))")
def test_syntaxerror(f2003_create): '''Test that NoMatchError is raised for various syntax errors.''' for line in [ "us", "ust", "use", "usemy_model", "use, ", "use, ::", "use, intrinsic", "use, intrinsic::", "use, intrinsic my_module", "use,", "use my_model,", "use my_model, only", "use my_model, only ;", "use my_model, only name" ]: with pytest.raises(NoMatchError) as excinfo: _ = Use_Stmt(line) assert "Use_Stmt: '{0}'".format(line) in str(excinfo.value)
def test_parser_caseinsensitive1(): '''Check that the test for the existance of a builtin call in a use statement is case insensitive. ''' 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 adduse(parse_tree, location, name, only=None, funcnames=None): '''Add a Fortran 'use' statement to an existing fparser2 parse tree. This will be added at the first valid location before the current location. This function should be part of the fparser2 replacement for f2pygen (which uses fparser1) but is kept here until this is developed, see issue #240. The 'parse_tree' argument is only required as fparser2 currently does not connect a child to a parent. This will be addressed in issue fparser:#102. :param parse_tree: The full parse tree of the associated code :type parse_tree: :py:class:`fparser.two.utils.Base` :param location: The current location (node) in the parse tree \ provided in the parse_tree argument :type location: :py:class:`fparser.two.utils.Base` :param str name: The name of the use statement :param bool only: Whether to include the 'only' clause in the use \ statement or not. Defaults to None which will result in only being \ added if funcnames has content and not being added otherwise. :param funcnames: A list of names to include in the use statement's \ only list. If the list is empty or None then nothing is \ added. Defaults to None. :type funcnames: list of str :raises GenerationError: if the location is not part of the parse \ tree. :raises GenerationError: if the location is not a valid location \ to add a use statement. :raises NotImplementedError: if the type of parent node is not \ supported. :raises InternalError: if the type of parent node does not have \ the expected structure. ''' # pylint: disable=too-many-locals # pylint: disable=too-many-branches from fparser.two.utils import walk_ast from fparser.two.Fortran2003 import Main_Program, Module, \ Subroutine_Subprogram, Function_Subprogram, Use_Stmt, \ Specification_Part from psyclone.psyGen import GenerationError, InternalError if location is None: raise GenerationError("alg_gen.py:adduse: Location argument must " "not be None.") if funcnames: # funcnames have been provided for the only clause. if only is False: # However, the only clause has been explicitly set to False. raise GenerationError( "alg_gen.py:adduse: If the 'funcnames' argument is provided " "and has content, then the 'only' argument must not be set " "to 'False'.") if only is None: # only has not been specified so set it to True as it is # required when funcnames has content. only = True if only is None: # only has not been specified and we can therefore infer that # funcnames is empty or is not provided (as earlier code would # have set only to True otherwise) so only is not required. only = False # Create the specified use statement only_str = "" if only: only_str = ", only :" my_funcnames = funcnames if funcnames is None: my_funcnames = [] use = Use_Stmt("use {0}{1} {2}".format(name, only_str, ", ".join(my_funcnames))) # find the parent program statement containing the specified location parent_prog_statement = None found = False for child in walk_ast(parse_tree.content): if child == location: found = True break if isinstance(child, (Main_Program, Module, Subroutine_Subprogram, Function_Subprogram)): parent_prog_statement = child if not found: raise GenerationError("alg_gen.py:adduse: The specified location is " "not in the parse tree.") if not parent_prog_statement: raise GenerationError( "alg_gen.py:adduse: The specified location is invalid as it has " "no parent in the parse tree that is a program, module, " "subroutine or function.") if not isinstance( parent_prog_statement, (Main_Program, Subroutine_Subprogram, Function_Subprogram)): # We currently only support program, subroutine and function # as ancestors raise NotImplementedError( "alg_gen.py:adduse: Unsupported parent code found '{0}'. " "Currently support is limited to program, subroutine and " "function.".format(str(type(parent_prog_statement)))) if not isinstance(parent_prog_statement.content[1], Specification_Part): raise InternalError( "alg_gen.py:adduse: The second child of the parent code " "(content[1]) is expected to be a specification part but " "found '{0}'.".format(repr(parent_prog_statement.content[1]))) # add the use statement as the first child of the specification # part of the program spec_part = parent_prog_statement.content[1] spec_part.content.insert(0, use) return parse_tree
def test_use_colons(f2003_create): '''Check that a basic use with '::' is parsed correctly.''' line = "use :: my_model" ast = Use_Stmt(line) assert "USE :: my_model" in str(ast) assert repr(ast) == "Use_Stmt(None, '::', Name('my_model'), '', None)"
def check_use(reader): '''Internal helper function to avoid code replication.''' ast = Use_Stmt(reader) assert "USE my_model" in str(ast) assert repr(ast) == "Use_Stmt(None, None, Name('my_model'), '', None)"