def test_if_content(): ''' Check that the content of an if gets created successfully. ''' module = ModuleGen(name="testmodule") clause = "a < b" if_statement = IfThenGen(module, clause) if_statement.add(CommentGen(if_statement, "HELLO")) module.add(if_statement) lines = str(module.root).splitlines() assert "IF (" + clause + ") THEN" in lines[3] assert "!HELLO" in lines[4] assert "END IF" in lines[5]
def test_basegen_previous_loop_no_loop(): '''Check that we raise an error when requesting the position of the previous loop if we don't have a loop ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) # Request the position of the last loop # even though we haven't got one with pytest.raises(RuntimeError) as err: sub.previous_loop() assert "no loop found - there is no previous loop" in str(err)
def test_basegen_last_declaration_no_vars(): '''Check that we raise an error when requesting the position of the last variable declaration if we don't have any variables''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) # Request the position of the last variable declaration # even though we haven't got any with pytest.raises(RuntimeError) as err: sub.last_declaration() assert "no variable declarations found" in str(err)
def test_basegen_append_default(): ''' Check if no position argument is supplied to BaseGen.add() then it defaults to appending ''' from psyclone.f2pygen import BaseGen module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) BaseGen.add(sub, DeclGen(sub, datatype="integer", entity_decls=["var1"])) BaseGen.add(sub, CommentGen(sub, " hello")) cindex = line_number(sub.root, "hello") assert cindex == 3
def test_imp_none_in_module(): ''' test that implicit none can be added to a module in the correct location''' module = ModuleGen(name="testmodule", implicitnone=False) module.add(ImplicitNoneGen(module)) in_idx = line_number(module.root, "IMPLICIT NONE") cont_idx = line_number(module.root, "CONTAINS") assert in_idx > -1, "IMPLICIT NONE not found" assert cont_idx > -1, "CONTAINS not found" assert cont_idx - in_idx == 1, "CONTAINS is not on the line after" +\ " IMPLICIT NONE"
def test_imp_none_in_subroutine_with_decs(): ''' test that implicit none is added before any declaration statements in a subroutine when auto (the default) is used for insertion ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sub.add(DeclGen(sub, datatype="integer", entity_decls=["var1"])) sub.add(TypeDeclGen(sub, datatype="my_type", entity_decls=["type1"])) sub.add(ImplicitNoneGen(module)) in_idx = line_number(sub.root, "IMPLICIT NONE") assert in_idx == 1
def test_progunitgen_multiple_use2(): '''Check that we correctly handle the case where the same module appears in two use statements but, because the first use is specific, the second, generic use is included. ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sub.add(UseGen(sub, name="fred", only=True, funcnames=["astaire"])) sub.add(UseGen(sub, name="fred")) assert count_lines(sub.root, "USE fred") == 2
def test_adduse_empty_only(): ''' Test that the adduse module method works correctly when we specify that we want it to be specific but then don't provide a list of entities for the only qualifier ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) from psyclone.f2pygen import adduse # Add a use statement with only=True but an empty list of entities adduse("fred", sub.root, only=True, funcnames=[]) assert count_lines(sub.root, "USE fred") == 1 assert count_lines(sub.root, "USE fred, only") == 0
def test_basegen_after_index(): '''Check that we can insert an object using "after_index"''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sub.add(DeclGen(sub, datatype="integer", entity_decls=["var1"])) sub.add(DeclGen(sub, datatype="integer", entity_decls=["var2"])) sub.add(CommentGen(sub, " hello"), position=["after_index", 1]) # The code checked by line_number() *includes* the SUBROUTINE # statement (which is obviously not a child of the SubroutineGen # object) and therefore the index it returns is 1 greater than we # might expect. assert line_number(sub.root, "hello") == 3
def test_basegen_start_parent_loop_no_loop_dbg(): '''Check the debug option to the start_parent_loop method when we have no loop''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) dgen = DirectiveGen(sub, "omp", "end", "do", "") sub.add(dgen) call = CallGen(sub, name="testcall", args=["a", "b"]) sub.add(call) with pytest.raises(RuntimeError) as err: call.start_parent_loop(debug=True) assert "This node has no enclosing Do loop" in str(err)
def test_adduse_default_funcnames(): ''' Test that the adduse module method works correctly when we do not specify a list of funcnames ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) call = CallGen(sub, name="testcall", args=["a", "b"]) sub.add(call) from psyclone.f2pygen import adduse adduse("fred", call.root) gen = str(sub.root) expected = (" SUBROUTINE testsubroutine()\n" " USE fred\n") assert expected in gen
def test_deallocate_arg_list(): '''check that a deallocate gets created succesfully with content being a list.''' module = ModuleGen(name="testmodule") content = ["and", "now", "the", "end", "is", "near"] content_str = "" for idx, name in enumerate(content): content_str += name if idx + 1 < len(content): content_str += ", " deallocate = DeallocateGen(module, content) module.add(deallocate) lines = str(module.root).splitlines() assert "DEALLOCATE (" + content_str + ")" in lines[3]
def test_allocate_arg_list(): '''check that an allocate gets created succesfully with content being a list.''' module = ModuleGen(name="testmodule") content = ["hello", "how", "are", "you"] content_str = "" for idx, name in enumerate(content): content_str += name if idx + 1 < len(content): content_str += ", " allocate = AllocateGen(module, content) module.add(allocate) lines = str(module.root).splitlines() assert "ALLOCATE (" + content_str + ")" in lines[3]
def test_if_add_use(): ''' Check that IfThenGen.add() correctly handles the case when it is passed a UseGen object ''' module = ModuleGen(name="testmodule") clause = "a < b" if_statement = IfThenGen(module, clause) if_statement.add(CommentGen(if_statement, "GOODBYE")) if_statement.add(UseGen(if_statement, name="dibna")) module.add(if_statement) print str(module.root) use_line = line_number(module.root, "USE dibna") if_line = line_number(module.root, "IF (" + clause + ") THEN") # The use statement must come before the if..then block assert use_line < if_line
def test_imp_none_in_module_with_use_and_decs_and_comments(): ''' test that implicit none is added after any use statements and before any declarations in a module in the presence of comments when auto (the default) is used for insertion''' module = ModuleGen(name="testmodule", implicitnone=False) module.add(DeclGen(module, datatype="integer", entity_decls=["var1"])) module.add(TypeDeclGen(module, datatype="my_type", entity_decls=["type1"])) module.add(UseGen(module, "fred")) for idx in [0, 1, 2, 3]: module.add(CommentGen(module, " hello " + str(idx)), position=["before_index", 2 * idx]) module.add(ImplicitNoneGen(module)) in_idx = line_number(module.root, "IMPLICIT NONE") assert in_idx == 3
def test_adduse(): ''' Test that the adduse module method works correctly when we use a call object as our starting point ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) call = CallGen(sub, name="testcall", args=["a", "b"]) sub.add(call) from psyclone.f2pygen import adduse adduse("fred", call.root, only=True, funcnames=["astaire"]) gen = str(sub.root) expected = (" SUBROUTINE testsubroutine()\n" " USE fred, ONLY: astaire\n") assert expected in gen
def test_basegen_before_error(): '''Check that we raise an error when attempting to insert an object before another object that is not present in the tree''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sub.add(DeclGen(sub, datatype="integer", entity_decls=["var1"])) sub.add(DeclGen(sub, datatype="integer", entity_decls=["var2"])) # Create an object but do not add it as a child of sub dgen = DeclGen(sub, datatype="real", entity_decls=["rvar1"]) # Try to add an object before the orphan dgen with pytest.raises(RuntimeError) as err: sub.add(CommentGen(sub, " hello"), position=["before", dgen]) assert "Failed to find supplied object" in str(err)
def test_typeselectiongen(): ''' Check that SelectionGen works as expected for a type ''' from psyclone.f2pygen import SelectionGen module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sgen = SelectionGen(sub, expr="my_var=>another_var", typeselect=True) sub.add(sgen) agen = AssignGen(sgen, lhs="happy", rhs=".TRUE.") sgen.addcase("fspace", [agen]) sgen.adddefault() gen = str(sub.root) print gen assert "SELECT TYPE ( my_var=>another_var )" in gen assert "TYPE IS ( fspace )" in gen
def test_do_loop_add_after(): ''' Test that we correctly generate code for a do loop when adding a child to it with position *after* ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsub") module.add(sub) dogen = DoGen(sub, "it", "1", "10", step="2") sub.add(dogen) assign1 = AssignGen(dogen, lhs="happy", rhs=".TRUE.") dogen.add(assign1) assign2 = AssignGen(dogen, lhs="sad", rhs=".FALSE.") dogen.add(assign2, position=["before", assign1.root]) a1_line = line_number(sub.root, "happy = ") a2_line = line_number(sub.root, "sad = ") assert a1_line > a2_line
def test_subroutine_var_with_implicit_none(): ''' test that a variable is added after an implicit none statement in a subroutine''' module = ModuleGen(name="testmodule") subroutine = SubroutineGen(module, name="testsubroutine", implicitnone=True) module.add(subroutine) subroutine.add( DeclGen(subroutine, datatype="integer", entity_decls=["var1"])) idx_var = line_number(subroutine.root, "INTEGER var1") idx_imp_none = line_number(subroutine.root, "IMPLICIT NONE") print str(module.root) assert idx_var - idx_imp_none == 1, \ "variable declation must be after implicit none"
def test_add_before(): ''' add the new code before a particular object ''' module = ModuleGen(name="testmodule") subroutine = SubroutineGen(module, name="testsubroutine") module.add(subroutine) loop = DoGen(subroutine, "it", "1", "10") subroutine.add(loop) call = CallGen(subroutine, "testcall") subroutine.add(call, position=["before", loop.root]) lines = str(module.root).splitlines() # the call should be inserted before the loop print lines assert "SUBROUTINE testsubroutine" in lines[3] assert "CALL testcall" in lines[4] assert "DO it=1,10" in lines[5]
def test_selectiongen_addcase(): ''' Check that SelectionGen.addcase() works as expected when no content is supplied''' from psyclone.f2pygen import SelectionGen module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) sgen = SelectionGen(sub, expr="my_var") sub.add(sgen) sgen.addcase("1") gen = str(sub.root) print gen expected = (" SELECT CASE ( my_var )\n" " CASE ( 1 )\n" " END SELECT") assert expected in gen
def test_if_with_position_append(): ''' Check that IfThenGen.add() correctly uses the position argument when *append* is specified. ''' module = ModuleGen(name="testmodule") clause = "a < b" if_statement = IfThenGen(module, clause) com1 = CommentGen(if_statement, "HELLO") if_statement.add(com1) if_statement.add(CommentGen(if_statement, "GOODBYE"), position=["append"]) module.add(if_statement) print str(module.root) lines = str(module.root).splitlines() assert "IF (" + clause + ") THEN" in lines[3] assert "!HELLO" in lines[4] assert "!GOODBYE" in lines[5] assert "END IF" in lines[6]
def gen(self): ''' Generate PSy code for the Dynamo0.1 api. :rtype: ast ''' from psyclone.f2pygen import ModuleGen, UseGen # create an empty PSy layer module psy_module = ModuleGen(self.name) # include the lfric module lfric_use = UseGen(psy_module, name="lfric") psy_module.add(lfric_use) # add all invoke specific information self.invokes.gen_code(psy_module) return psy_module.root
def test_imp_none_in_module_with_use_and_decs(): ''' test that implicit none is added after any use statements and before any declarations in a module when auto (the default) is used for insertion''' module = ModuleGen(name="testmodule", implicitnone=False) module.add(DeclGen(module, datatype="integer", entity_decls=["var1"])) module.add(TypeDeclGen(module, datatype="my_type", entity_decls=["type1"])) module.add(UseGen(module, "fred")) module.add(ImplicitNoneGen(module)) in_idx = line_number(module.root, "IMPLICIT NONE") assert in_idx == 2
def test_progunit_multiple_use3(): '''Check that we correctly handle the case where the same module is specified in two UseGen objects statements both of which are specific and they have overlapping variable names. ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) funcnames = ["a", "b", "c"] sub.add(UseGen(sub, name="fred", only=True, funcnames=funcnames)) funcnames = ["c", "d"] sub.add(UseGen(sub, name="fred", only=True, funcnames=funcnames)) gen = str(sub.root) expected = (" USE fred, ONLY: d\n" " USE fred, ONLY: a, b, c") assert expected in gen assert count_lines(sub.root, "USE fred") == 2 # ensure that the input list does not get modified assert funcnames == ["c", "d"]
def test_subroutine_var_intent_in_with_directive(): ''' test that a variable declared as intent in is added before a directive in a subroutine''' module = ModuleGen(name="testmodule") subroutine = SubroutineGen(module, name="testsubroutine", implicitnone=False) module.add(subroutine) subroutine.add(DirectiveGen(subroutine, "omp", "begin", "parallel", "")) subroutine.add( DeclGen(subroutine, datatype="integer", intent="in", entity_decls=["var1"])) idx_par = line_number(subroutine.root, "!$omp parallel") idx_var = line_number(subroutine.root, "INTEGER, intent(in) :: var1") print str(module.root) assert idx_par - idx_var == 1, \ "variable declaration must be before directive"
def test_declgen_multiple_use2(): '''Check that we don't correctly handle the case where data of a different type has already been delared. ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) # first declaration datanames = ["data1"] sub.add(DeclGen(sub, datatype="real", entity_decls=datanames)) gen = str(sub.root) # second declaration datanames = ["data1", "data2"] sub.add(DeclGen(sub, datatype="integer", entity_decls=datanames)) gen = str(sub.root) print gen expected = (" INTEGER data1, data2\n" " REAL data1") assert expected in gen # check input data is not modified assert datanames == ["data1", "data2"]
def test_typedeclgen_multiple_use(): '''Check that we correctly handle the case where data of the same type has already been declared. ''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) # first declaration datanames = ["type1"] sub.add(TypeDeclGen(sub, datatype="my_type", entity_decls=datanames)) gen = str(sub.root) # second declaration datanames = ["type1", "type2"] sub.add(TypeDeclGen(sub, datatype="my_type", entity_decls=datanames)) gen = str(sub.root) print gen expected = (" TYPE(my_type) type2\n" " TYPE(my_type) type1") assert expected in gen # check input data is not modified assert datanames == ["type1", "type2"]
def test_basegen_start_parent_loop_dbg(capsys): '''Check the debug option to the start_parent_loop method''' module = ModuleGen(name="testmodule") sub = SubroutineGen(module, name="testsubroutine") module.add(sub) loop = DoGen(sub, "it", "1", "10") sub.add(loop) call = CallGen(loop, "testcall") loop.add(call) call.start_parent_loop(debug=True) out, _ = capsys.readouterr() print out expected = ("Parent is a do loop so moving to the parent\n" "The type of the current node is now <class " "'fparser.one.block_statements.Do'>\n" "The type of parent is <class " "'fparser.one.block_statements.Subroutine'>\n" "Finding the loops position in its parent ...\n" "The loop's index is 0\n") assert expected in out