def test_blockbase_match_names(f2003_create): '''Test the blockbase name matching option in its match method. We use the Derived_Type_Def class (which subclasses BlockBase) for this as it sets match_names to True. ''' from fparser.two.Fortran2003 import Derived_Type_Def, Case_Construct # working named example reader = get_reader("type abc\nend type abc") ast = Derived_Type_Def(reader) assert "TYPE :: abc\nEND TYPE abc" in str(ast) # case insensitive reader = get_reader("type abc\nend type ABC") ast = Derived_Type_Def(reader) assert "TYPE :: abc\nEND TYPE ABC" in str(ast) # incorrect name exception reader = get_reader("type abc\nend type cde") with pytest.raises(FortranSyntaxError) as excinfo: ast = Derived_Type_Def(reader) assert "at line 2\n>>>end type cde\nExpecting name 'abc'" \ in str(excinfo.value) # first name required if second name supplied # switch to using select case as it can trip the exception reader = get_reader("select case (i)\nend select label") with pytest.raises(FortranSyntaxError) as excinfo: ast = Case_Construct(reader) assert ("at line 2\n>>>end select label\nName 'label' has no " "corresponding starting name") in str(excinfo.value)
def test_where_construct(): ''' Tests for the WHERE construct, R744. ''' tcls = Where_Construct obj = tcls( get_reader('''\ where (pressure <= 1.0) pressure = pressure + inc_pressure temp = temp - 5.0 elsewhere raining = .true. end where ''')) assert isinstance(obj, tcls), repr(obj) assert (str(obj) == "WHERE (pressure <= 1.0)\n " "pressure = pressure + inc_pressure\n " "temp = temp - 5.0\n" "ELSEWHERE\n raining = .TRUE.\nEND WHERE") obj = tcls( get_reader('''\ where (cond1) else where (cond2) end where ''')) assert isinstance(obj, tcls), repr(obj) assert str(obj) == 'WHERE (cond1)\nELSEWHERE(cond2)\nEND WHERE' obj = tcls( get_reader('''\ n:where (cond1) elsewhere (cond2) n else where n end where n ''')) assert isinstance(obj, tcls), repr(obj) assert (str(obj) == "n:WHERE (cond1)\nELSEWHERE(cond2) n\n" "ELSEWHERE n\nEND WHERE n") obj = tcls( get_reader('''\ n:where (cond1) else where (cond2) n else where n end where n ''')) assert isinstance(obj, tcls), repr(obj) assert (str(obj) == 'n:WHERE (cond1)\nELSEWHERE(cond2) n\nELSEWHERE n\n' 'END WHERE n') obj = tcls( get_reader('''\ n:where (me(:)=="hello") else where (me(:)=="goodbye") n else where n end where n ''')) assert (str(obj) == 'n:WHERE (me(:) == "hello")\nELSEWHERE(me(:) == "goodbye") n\n' 'ELSEWHERE n\n' 'END WHERE n')
def test_nonblock_do_construct(): ''' Tests that nonblock DO construct is parsed correctly (R835). ''' tcls = Nonblock_Do_Construct obj = tcls( get_reader('''\ do 20, i = 1, 3 20 rotm(i,j) = r2(j,i) ''')) assert isinstance(obj, Action_Term_Do_Construct), repr(obj) assert str(obj) == 'DO 20 , i = 1, 3\n20 rotm(i, j) = r2(j, i)' # Without the comma after the label obj = tcls( get_reader('''\ do 20 i = 1, 3 20 rotm(i,j) = r2(j,i) ''')) assert isinstance(obj, Action_Term_Do_Construct), repr(obj) assert str(obj) == 'DO 20 i = 1, 3\n20 rotm(i, j) = r2(j, i)' obj = tcls( get_reader('''\ do 50, i = n, m, -1 50 call foo(a) ''')) assert isinstance(obj, Action_Term_Do_Construct), repr(obj) assert str(obj) == 'DO 50 , i = n, m, - 1\n50 CALL foo(a)'
def test_blockbase_match_name_classes(f2003_create): '''Test the blockbase name matching option in its match method. We use the If_Construct class (which subclasses BlockBase) for this as it sets match_names to True and provides match_name_classes. This is used when names can appear in multiple places. ''' from fparser.two.Fortran2003 import If_Construct # working named example reader = get_reader("label:if (.true.) then\nendif label") ast = If_Construct(reader) assert "label:IF (.TRUE.) THEN\nEND IF label" in str(ast) # case insensitive reader = get_reader("label:if (.true.) then\nendif LABEL") ast = If_Construct(reader) assert "label:IF (.TRUE.) THEN\nEND IF LABEL" in str(ast) # incorrect name exception reader = get_reader("label:if (.true.) then\nendif bella") with pytest.raises(FortranSyntaxError) as excinfo: ast = If_Construct(reader) assert "at line 2\n>>>endif bella\nExpecting name 'label'" \ in str(excinfo.value) # first name required if subsequent name supplied reader = get_reader("if (.true.) then\nendif label") with pytest.raises(FortranSyntaxError) as excinfo: ast = If_Construct(reader) assert ("at line 2\n>>>endif label\nName 'label' has no corresponding " "starting name") in str(excinfo.value)
def test_fixed_fmt(): ''' Test that we handle comments in fixed-format mode ''' reader = get_reader('''\ subroutine foo c this is a subroutine end subroutine foo''', isfree=False, ignore_comments=True) cls = Subroutine_Subprogram obj = cls(reader) assert isinstance(obj, cls), repr(obj) assert str(obj) == 'SUBROUTINE foo\nEND SUBROUTINE foo' assert (repr(obj) == "Subroutine_Subprogram(Subroutine_Stmt(None, " "Name('foo'), None, None), End_Subroutine_Stmt('SUBROUTINE', " "Name('foo')))") reader = get_reader('''\ subroutine foo c this is a subroutine end subroutine foo''', isfree=False, ignore_comments=False) cls = Subroutine_Subprogram obj = cls(reader) fort = obj.tofortran(isfix=True) assert isinstance(obj, cls), repr(obj) assert (fort == ' SUBROUTINE foo\nc this is a subroutine\n' ' END SUBROUTINE foo') assert (repr(obj) == "Subroutine_Subprogram(Subroutine_Stmt(None, " "Name('foo'), None, None), End_Subroutine_Stmt('SUBROUTINE', " "Name('foo')))")
def test_ignore_comments(): ''' Check that the parser does throw away comments when requested ''' tree = Program( get_reader('''\ PROGRAM a_prog ! A full line comment PRINT *, "Hello" ! This block gets executed END PROGRAM a_prog ''', ignore_comments=True)) gen = str(tree) assert ("PROGRAM a_prog\n" " PRINT *, \"Hello\"\n" "END PROGRAM a_prog" in gen) assert "full line comment" not in gen assert "block gets executed" not in gen # Check that the default behaviour is to ignore comments tree = Program( get_reader('''\ PROGRAM a_prog ! A full line comment PRINT *, "Hello" ! This block gets executed END PROGRAM a_prog ''')) gen = str(tree) assert "full line comment" not in gen assert "block gets executed" not in gen
def test_valid(f2003_create): ''' Test that valid code is parsed correctly. ''' # basic obj = Main_Program(get_reader("program a\nend")) assert isinstance(obj, Main_Program) assert str(obj) == 'PROGRAM a\nEND' assert repr(obj) == ("Main_Program(Program_Stmt('PROGRAM', Name('a')), " "End_Program_Stmt(None, None))") # name matching obj = Main_Program(get_reader("program a\nend program a")) assert isinstance(obj, Main_Program) assert str(obj) == 'PROGRAM a\nEND PROGRAM a' assert repr(obj) == ("Main_Program(Program_Stmt('PROGRAM', Name('a')), " "End_Program_Stmt('PROGRAM', Name('a')))") # mixed case name matching obj = Main_Program(get_reader("program a\nend program A")) assert isinstance(obj, Main_Program) assert str(obj) == 'PROGRAM a\nEND PROGRAM A' # specification-part obj = Main_Program(get_reader("program a\ninteger i\nend program a")) assert str(obj) == 'PROGRAM a\n INTEGER :: i\nEND PROGRAM a' # execution-part obj = Main_Program(get_reader("program a\ni=10\nend program a")) assert str(obj) == 'PROGRAM a\n i = 10\nEND PROGRAM a' # internal-subprogram-part obj = Main_Program( get_reader("program a\ncontains\nsubroutine foo\n" "end\nend program a")) assert str(obj) == ("PROGRAM a\n CONTAINS\n SUBROUTINE foo\n" " END\nEND PROGRAM a") # specification-part + execution-part obj = Main_Program(get_reader("program a\ninteger i\ni=10\nend program a")) assert str(obj) == 'PROGRAM a\n INTEGER :: i\n i = 10\nEND PROGRAM a' # execution-part + internal-subprogram-part obj = Main_Program( get_reader("program a\ni=10\ncontains\nsubroutine foo\n" "end\nend program a")) assert str(obj) == ("PROGRAM a\n i = 10\n CONTAINS\n SUBROUTINE foo\n" " END\nEND PROGRAM a") # specification-part + execution-part + internal-subprogram-part obj = Main_Program( get_reader("program a\ninteger i\ni=10\ncontains\n" "subroutine foo\nend\nend program a")) assert str(obj) == ("PROGRAM a\n INTEGER :: i\n i = 10\n CONTAINS\n " "SUBROUTINE foo\n END\nEND PROGRAM a")
def test_reproduce_issue_fix90(): source_str = '''\ subroutine foo() real a c 1 c 2 end ''' tree = api.get_reader(source_str, isfree=False, isstrict=False) tree = list(tree) foo, a, comment, end = tree[:3] + tree[-1:] assert foo.span == (1, 1) assert a.span == (2, 2), repr(a.span) assert end.span == (5, 5), repr(end.span) source_str = '''\ subroutine foo() real a c- c end ''' tree = api.get_reader(source_str, isfree=False, isstrict=False, ignore_comments=False) tree = list(tree) foo, a, comment, end = tree[:3] + tree[-1:] assert foo.span == (1, 1) assert a.span == (2, 2), repr(a.span) assert end.span == (5, 5), repr(end.span) source_str = '''\ subroutine foo() real a c c end ''' tree = api.get_reader(source_str, isfree=False, isstrict=False, ignore_comments=False) tree = list(tree) foo, a, comment, end = tree[:3] + tree[-1:] assert foo.span == (1, 1) assert a.span == (2, 2), repr(a.span) assert comment.span == (3, 3) assert end.span == (5, 5), repr(end.span)
def test_subroutine_comments(): ''' Tests for comments in subroutines ''' source = '''\ subroutine my_mod() ! First comment implicit none integer my_mod ! Body comment my_mod = 1 ! Inline comment ! Ending comment end subroutine my_mod ''' from fparser.two.Fortran2003 import Subroutine_Subprogram reader = get_reader(source, isfree=True, ignore_comments=False) fn_unit = Subroutine_Subprogram(reader) assert isinstance(fn_unit, Subroutine_Subprogram) walk_ast(fn_unit.content, [Comment], debug=True) spec_part = fn_unit.content[1] comment = spec_part.content[0].content[0] assert isinstance(comment, Comment) assert "! First comment" in str(comment) comment = spec_part.content[2].content[0] assert isinstance(comment, Comment) assert "! Body comment" in str(comment) exec_part = fn_unit.content[2] comment = exec_part.content[1] assert isinstance(comment, Comment) assert "! Inline comment" in str(comment)
def test_proc_component_part(interface, attributes): ''' Test that various procedure component declarations are recognised. R445. ''' code = "procedure({0}), {1} :: my_proc".format(interface, attributes) reader = get_reader(code) obj = Component_Part(reader) assert obj is not None
def test_proc_component_pointer(attributes): ''' R445, C449: POINTER shall appear in each proc-component-attr-spec-list. ''' code = "procedure(), {0} :: my_proc".format(attributes) reader = get_reader(code) with pytest.raises(NoMatchError): _ = Component_Part(reader)
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 test_data_component_part(var_type): ''' Test that various data component declarations are recognised. R440. ''' code = var_type + " :: iflag" reader = get_reader(code, isfree=True, isstrict=True) obj = Component_Part(reader) assert "iflag" in str(obj)
def test_mix(f2003_create): '''Test that multiple program_units can be parsed successfully with a mix of includes and comments. ''' reader = get_reader(("include '1'\n" "! comment1\n" "include '2'\n" "subroutine test()\n" "end subroutine\n" "include '3'\n" "include '4'\n" "! comment2\n" "! comment3\n" "module example\n" "end module\n" "! comment4\n" "include '5'\n" "! comment5\n"), ignore_comments=False) ast = Program(reader) assert ("INCLUDE '1'\n" "! comment1\n" "INCLUDE '2'\n" "SUBROUTINE test\n" "END SUBROUTINE\n" "INCLUDE '3'\n" "INCLUDE '4'\n" "! comment2\n" "! comment3\n" "MODULE example\n" "END MODULE\n" "! comment4\n" "INCLUDE '5'\n" "! comment5") in str(ast)
def test_strict_order_invalid_code(f2003_create, strict_order): '''Check that the strict_order flag toggles the parse behaviour as expected. ''' subclasses = [F2003.Specification_Part, F2003.Execution_Part] reader = get_reader(""" program main i = 2 integer :: i end program main """) expected = remove_indentation("""([ Program_Stmt('PROGRAM', Name('main')), Execution_Part( Assignment_Stmt(Name('i'), '=', Int_Literal_Constant('2', None))), Specification_Part( Type_Declaration_Stmt( Intrinsic_Type_Spec('INTEGER', None), None, Entity_Decl(Name('i'), None, None, None))), End_Program_Stmt('PROGRAM', Name('main')) ],) """) result = BlockBase.match(F2003.Program_Stmt, subclasses, F2003.End_Program_Stmt, reader, strict_order=strict_order) if strict_order: assert result is None else: assert str(result) == expected
def test_walk_debug(capsys): ''' Test the debug output of the walk() utility. ''' import six reader = get_reader("program just_a_test\n" "if(.true.)then\n" " b = 1\n" "end if\n" "end program just_a_test\n") main = Fortran2003.Program(reader) _ = walk(main, debug=True) stdout, _ = capsys.readouterr() if six.PY2: # Output of capsys under Python 2 is not the same as under 3 assert stdout.startswith("('child type = ") else: assert stdout.startswith("child type = ") assert "Main_Program" in stdout assert "If_Construct" in stdout assert "Assignment" in stdout assert "Int_Literal_Constant" in stdout assert "End_If_Stmt" in stdout # Walk only part of the tree and specify an indent if_constructs = walk(main, Fortran2003.If_Construct) _ = walk(if_constructs[0], indent=4, debug=True) stdout, _ = capsys.readouterr() if six.PY2: # Output of capsys under Python 2 is not the same as under 3 assert stdout.startswith("('" + 8 * " " + "child type =") else: assert stdout.startswith(8 * " " + "child type =") assert "Program" not in stdout
def test_get_child(): ''' Test the get_child() utility. ''' from fparser.two import Fortran2003 from fparser.two.utils import walk, get_child reader = get_reader("program hello\n" "write(*,*) 'hello'\n" "write(*,*) 'goodbye'\n" "end program hello\n") main = Fortran2003.Program(reader) prog = get_child(main, Fortran2003.Main_Program) exe = get_child(prog, Fortran2003.Execution_Part) assert isinstance(exe, Fortran2003.Execution_Part) write_stmt = get_child(exe, Fortran2003.Write_Stmt) # Check that we got the first write and not the second assert "goodbye" not in str(write_stmt) # The top level has no Io_Control_Spec children assert not get_child(main, Fortran2003.Io_Control_Spec) # Check functionality when node has children in `items` and # not in `content` io_nodes = walk(main.content, Fortran2003.Io_Control_Spec) assert not hasattr(io_nodes[0], "content") io_unit = get_child(io_nodes[0], Fortran2003.Io_Unit) assert isinstance(io_unit, Fortran2003.Io_Unit) missing = get_child(io_nodes[0], Fortran2003.Execution_Part) assert missing is None
def test_kind_spaces(f2003_create): '''Test that a kind selector with 'kind=' present and spaces can be parsed successfully. ''' reader = get_reader(" ( kind = some_kind ) ") ast = Kind_Selector(reader) assert "(KIND = some_kind)" in str(ast)
def test_directive_at_different_places(f2003_parser, lines): '''Test that directives are parsed correctly irrespective of where they appear in the code.''' code = '\n'.join(line.strip() for line in lines) ref = '\n'.join(lines) reader = get_reader(code) result = f2003_parser(reader) assert str(result) == ref
def test_invalid1(f2003_create): ''' Test that exceptions are raised for invalid code ''' # no end with pytest.raises(NoMatchError) as excinfo: _ = Main_Program(get_reader("program a\n")) assert "at line 1\n>>>program a" in str(excinfo.value) # no start with pytest.raises(NoMatchError) as excinfo: _ = Main_Program(get_reader("end program a\n")) assert "at line 1\n>>>end program a" in str(excinfo.value) # name mismatch with pytest.raises(FortranSyntaxError) as excinfo: _ = Main_Program(get_reader("program a\nend program b")) assert "at line 2\n>>>end program b\nExpecting name 'a'" \ in str(excinfo.value)
def test_empty_input(f2003_create): '''Test that empty input or input only containing white space can be parsed succesfully ''' for code in ["", " ", " \n \n\n"]: reader = get_reader(code) ast = Program(reader) assert str(ast) == ""
def test_single_error2(f2003_create): '''Test that a single program_unit with an error in the final statement raises an appropriate exception ''' reader = get_reader("subroutine test()\n\n" "end subroutin\n\n\n") with pytest.raises(FortranSyntaxError) as excinfo: dummy = Program(reader) assert ("at line 3\n>>>end subroutin\n" in str(excinfo.value))
def test_do_construct(f2003_create): '''Test a do construct is supported by the executable construct class. ''' code = ("do i = 1, n\n" "end do") reader = get_reader(code) result = Executable_Construct(reader) assert str(result).lower() == code
def test_submodule(f2008_create): '''Test the parsing of a minimal submodule.''' reader = get_reader('''\ submodule (foobar) bar end ''') ast = Submodule(reader) assert "SUBMODULE (foobar) bar\n" \ "END SUBMODULE bar" in str(ast)
def test_single(f2003_create): '''Test that a single program_unit can be parsed successfully.''' reader = get_reader('''\ subroutine test() end subroutine ''') ast = Program(reader) assert "SUBROUTINE test\n" \ "END SUBROUTINE" in str(ast)
def test_nokind_spaces(f2003_create): '''Test that a kind selector with 'kind=' not present and spaces can be parsed successfully. Note, the parser automatically adds-in kind for the output. ''' reader = get_reader(" ( some_kind ) ") ast = Kind_Selector(reader) assert "(KIND = some_kind)" in str(ast)
def test_submodule_nomatch(f2008_create): '''Test an exception is raised if there is a syntax error.''' reader = get_reader('''\ submod (foobar) bar end ''') with pytest.raises(NoMatchError) as excinfo: dummy_ = Program_Unit(reader) assert ("at line 1\n>>> submod (foobar) bar\n" in str(excinfo.value))
def check_forall(reader): '''Internal helper function to avoid code replication.''' ast = Forall_Stmt(reader) assert "FORALL (i = b(k) : 2, j = 1 : c(k)) a(i, j) = 0.0" in str(ast) line = "forall (i=b(k):2,j=1:c(k)) a(i,j)=0.0" check_forall(line) reader = get_reader(line) check_forall(reader)
def test_submodule(f2008_create): '''Test that submodule as a top-level program unit can be parsed.''' reader = get_reader('''\ submodule (foobar) bar end ''') ast = Program_Unit(reader) assert "SUBMODULE (foobar) bar\n" \ "END" in str(ast)
def test_reproduce_issue_fix90(): source_str = '''\ subroutine foo() real a c 1 c 2 end ''' tree = api.get_reader(source_str, isfree=False, isstrict=False) tree = list(tree) foo, a, comment,end = tree[:3]+tree[-1:] assert foo.span==(1,1) assert a.span==(2,2),`a.span` assert end.span==(5,5),`end.span` source_str = '''\ subroutine foo() real a c- c end ''' tree = api.get_reader(source_str, isfree=False, isstrict=False) tree = list(tree) foo, a, comment,end = tree[:3]+tree[-1:] assert foo.span==(1,1) assert a.span==(2,2),`a.span` assert end.span==(5,5),`end.span` source_str = '''\ subroutine foo() real a c c end ''' tree = api.get_reader(source_str, isfree=False, isstrict=False) tree = list(tree) foo, a, comment, end = tree[:3]+tree[-1:] assert foo.span==(1,1) assert a.span==(2,2),`a.span` assert comment.span == (3,3) assert end.span==(5,5),`end.span`
def test_invalid3(f2003_create): '''Test that execution-part after internal-subprogram-part produces an error. ''' with pytest.raises(NoMatchError) as excinfo: _ = Main_Program( get_reader("program a\ncontains\nsubroutine foo\n" "end\ni=10\nend program a")) assert "at line 5\n>>>i=10\n" in str(excinfo.value)
def test_reproduce_issue_fix77(): source_str = '''\ subroutine foo() real a c c end ''' tree = api.get_reader(source_str, isfree=False, isstrict=True) tree = list(tree) foo, a, comment, end = tree[:3]+tree[-1:] assert foo.span==(1,1) assert a.span==(2,4),repr(a.span) assert comment.span==(5,5),repr(comment.span) assert end.span==(5,5),repr(end.span)
def test_reproduce_issue(): source_str = '''\ subroutine bndfp() use m_struc_def C- C C C C C end ''' tree = api.get_reader(source_str, isfree=False, isstrict=False) tree = list(tree) s, u, c, e = tree[:3]+tree[-1:] assert s.span==(1,1),`s.span` assert u.span==(2,2),`u.span` assert c.span==(3,3),`c.span` assert e.span==(9,9),`e.span`
def __parse(self): reader = api.get_reader(self.infile, True, False, None, None) parser = parsefortran.FortranParser(reader, False) parser.parse() return parser.block
def test_comment_cont_fix90(): source_str = '''\ subroutine foo() real c 1 & a c 2 end ''' tree = api.get_reader(source_str, isfree=False, isstrict=False) tree = list(tree) foo, a, comment, end = tree[:3]+tree[-1:] assert foo.span==(1,1) assert a.span==(2,4),`a.span` assert comment.span==(3,3),`comment.span` assert end.span==(6,6) source_str = '''\ subroutine foo() real c & a c 2 end ''' tree = api.get_reader(source_str, isfree=False, isstrict=False) tree = list(tree) foo, a, comment, end = tree[:3]+tree[-1:] assert foo.span==(1,1) assert a.span==(2,4),`a.span` assert comment.span==(3,3),`comment.span` assert end.span==(6,6) source_str = '''\ subroutine foo() real c 1 & a c end ''' tree = api.get_reader(source_str, isfree=False, isstrict=False) tree = list(tree) foo, a, comment, end = tree[:3]+tree[-1:] assert foo.span==(1,1) assert a.span==(2,4),`a.span` assert comment.span==(3,3),`comment.span` assert end.span==(6,6) source_str = '''\ subroutine foo() real c 1 & a c 2 &,b end ''' tree = api.get_reader(source_str, isfree=False, isstrict=False) tree = list(tree) foo, ab, comment, end = tree[:3]+tree[-1:] assert foo.span==(1,1) assert ab.span==(2,6),`a.span` assert comment.span==(3,3),`comment.span` assert end.span==(7,7)