diff --git a/scripts/fortran_tools/fortran_write.py b/scripts/fortran_tools/fortran_write.py index e147b48c..49057e1a 100644 --- a/scripts/fortran_tools/fortran_write.py +++ b/scripts/fortran_tools/fortran_write.py @@ -19,14 +19,16 @@ class FortranWriter: ########################################################################### # Class variables ########################################################################### - __INDENT = 3 # Spaces per indent level + __INDENT = 2 # Spaces per indent level - __CONTINUE_INDENT = 5 # Extra spaces on continuation line + __CONTINUE_INDENT = 4 # Extra spaces on continuation line __LINE_FILL = 97 # Target line length __LINE_MAX = 130 # Max line length + __BREAK_CHARS = [',', '+', '*', '/', '(', ')'] + # CCPP copyright statement to be included in all generated Fortran files __COPYRIGHT = '''! ! This work (Common Community Physics Package Framework), identified by @@ -52,7 +54,7 @@ class FortranWriter: __MOD_PREAMBLE = ["implicit none", "private"] __CONTAINS = ''' -CONTAINS''' +contains''' __MOD_FOOTER = ''' end module {module}''' @@ -150,8 +152,8 @@ def write(self, statement, indent_level, continue_line=False): line_len = len(outstr) if line_len > self.__line_fill: # Collect pretty break points - spaces = list() - commas = list() + spaces = [] + break_chars = [] sptr = len(istr) in_single_char = False in_double_char = False @@ -180,12 +182,12 @@ def write(self, statement, indent_level, continue_line=False): elif outstr[sptr] == ' ': # Non-quote spaces are where we can break spaces.append(sptr) - elif outstr[sptr] == ',': - # Non-quote commas are where we can break - commas.append(sptr) elif outstr[sptr:sptr+2] == '//': - # Non-quote commas are where we can break - commas.append(sptr + 1) + # Non-quote syntax are where we can break + break_chars.append(sptr + 1) + elif outstr[sptr] in FortranWriter.__BREAK_CHARS: + # Non-quote syntax are where we can break + break_chars.append(sptr) # End if (no else, other characters will be ignored) sptr = sptr + 1 # End while @@ -203,7 +205,7 @@ def write(self, statement, indent_level, continue_line=False): # end if best = self.find_best_break(spaces) if best >= self.__line_fill: - best = min(best, self.find_best_break(commas)) + best = min(best, self.find_best_break(break_chars)) # End if line_continue = False if best >= self.__line_max: @@ -218,8 +220,8 @@ def write(self, statement, indent_level, continue_line=False): if self._in_quote(outstr[0:best+1]): line_continue = '&' elif not outstr[best+1:].lstrip(): - # If the next line is empty, the current line is done - # and is equal to the max line length. Do not use + # If the next line is empty, the current line is done + # and is equal to the max line length. Do not use # continue and set best to line_max (best+1) line_continue = False best = best+1 @@ -233,12 +235,14 @@ def write(self, statement, indent_level, continue_line=False): if in_comment or is_comment_stmt: line_continue = False # end if - if line_continue: - fill = "{}&".format((self.__line_fill - best)*' ') + if line_continue == '&': + fill = '&' + elif line_continue: + fill = ' &' else: fill = "" # End if - outline = f"{outstr[0:best+1]}{fill}".rstrip() + outline = f"{outstr[0:best+1].rstrip()}{fill}" self.__file.write(f"{outline}\n") if best <= 0: imsg = "Internal ERROR: Unable to break line" @@ -250,7 +254,7 @@ def write(self, statement, indent_level, continue_line=False): # end if self.write(statement, indent_level, continue_line=line_continue) else: - self.__file.write("{}\n".format(outstr)) + self.__file.write(f"{outstr}\n") # End if # End if diff --git a/scripts/host_cap.py b/scripts/host_cap.py index b06906fe..fb2e7012 100644 --- a/scripts/host_cap.py +++ b/scripts/host_cap.py @@ -732,12 +732,12 @@ def write_host_cap(host_model, api, module_name, output_dir, run_env): cap.write("return", 4) cap.write("end if", 3) # Allocate the suite's dynamic constituents array - size_string = "0+" + size_string = "0 +" for var in host_local_vars.variable_list(): vtype = var.get_prop_value('type') if vtype == 'ccpp_constituent_properties_t': local_name = var.get_prop_value('local_name') - size_string += f"size({local_name})+" + size_string += f"size({local_name}) +" # end if # end for if not has_dyn_consts: diff --git a/test/unit_tests/sample_files/fortran_files/comments_test.F90 b/test/unit_tests/sample_files/fortran_files/comments_test.F90 index d4820a36..a3aa6072 100644 --- a/test/unit_tests/sample_files/fortran_files/comments_test.F90 +++ b/test/unit_tests/sample_files/fortran_files/comments_test.F90 @@ -18,16 +18,16 @@ module comments_test ! We can write comments in the module header - ! We can write indented comments in the header - integer :: foo ! Comment at end of line works - integer :: bar ! - ! xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - ! - integer :: baz ! - ! yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy - ! yyyyy + ! We can write indented comments in the header + integer :: foo ! Comment at end of line works + integer :: bar ! + ! xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + ! + integer :: baz ! + ! yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy + ! yyyy -CONTAINS - ! We can write comments in the module body +contains + ! We can write comments in the module body end module comments_test diff --git a/test/unit_tests/sample_files/fortran_files/linebreak_test.F90 b/test/unit_tests/sample_files/fortran_files/linebreak_test.F90 index 4f89441f..e2f5a3bc 100644 --- a/test/unit_tests/sample_files/fortran_files/linebreak_test.F90 +++ b/test/unit_tests/sample_files/fortran_files/linebreak_test.F90 @@ -17,23 +17,37 @@ ! module linebreak_test - character(len=7) :: data = (/ name000, name001, name002, name003, name004, name005, name006, & - name007, name008, name009, name010, name011, name012, name013, name014, name015, & - name016, name017, name018, name019, name020, name021, name022, name023, name024, & - name025, name026, name027, name028, name029, name030, name031, name032, name033, & - name034, name035, name036, name037, name038, name039, name040, name041, name042, & - name043, name044, name045, name046, name047, name048, name049, name050, name051, & - name052, name053, name054, name055, name056, name057, name058, name059, name060, & - name061, name062, name063, name064, name065, name066, name067, name068, name069, & - name070, name071, name072, name073, name074, name075, name076, name077, name078, & - name079, name080, name081, name082, name083, name084, name085, name086, name087, & - name088, name089, name090, name091, name092, name093, name094, name095, name096, & - name097, name098, name099 /) + character(len=7) :: data(100) = (/ 'name000', 'name001', 'name002', 'name003', 'name004', & + 'name005', 'name006', 'name007', 'name008', 'name009', 'name010', 'name011', 'name012', & + 'name013', 'name014', 'name015', 'name016', 'name017', 'name018', 'name019', 'name020', & + 'name021', 'name022', 'name023', 'name024', 'name025', 'name026', 'name027', 'name028', & + 'name029', 'name030', 'name031', 'name032', 'name033', 'name034', 'name035', 'name036', & + 'name037', 'name038', 'name039', 'name040', 'name041', 'name042', 'name043', 'name044', & + 'name045', 'name046', 'name047', 'name048', 'name049', 'name050', 'name051', 'name052', & + 'name053', 'name054', 'name055', 'name056', 'name057', 'name058', 'name059', 'name060', & + 'name061', 'name062', 'name063', 'name064', 'name065', 'name066', 'name067', 'name068', & + 'name069', 'name070', 'name071', 'name072', 'name073', 'name074', 'name075', 'name076', & + 'name077', 'name078', 'name079', 'name080', 'name081', 'name082', 'name083', 'name084', & + 'name085', 'name086', 'name087', 'name088', 'name089', 'name090', 'name091', 'name092', & + 'name093', 'name094', 'name095', 'name096', 'name097', 'name098', 'name099' /) -CONTAINS - call & - endrun('Cannot read columns_on_task from file'// & - ', columns_on_task has no horizontal dimension; columns_on_task is a protected variable') +contains + subroutine foo(ozone_constituents, aerosol_constituents, volcaero_constituents, & + other_constituents) + integer, intent(in) :: ozone_constituents(:) + integer, intent(in) :: aerosol_constituents(:) + integer, intent(in) :: volcaero_constituents(:) + integer, intent(in) :: other_constituents(:) + real, allocatable :: tracer_data_test_dynamic_constituents(:) +! codee format off + allocate(tracer_data_test_dynamic_constituents(0+size(ozone_constituents)+size( & + aerosol_constituents)+size(volcaero_constituents)+size(other_constituents))) + + write(6, '(a)') & + 'Cannot read columns_on_task from file'// & + ', columns_on_task has no horizontal dimension; columns_on_task is a protected variable' +! codee format on + end subroutine foo end module linebreak_test diff --git a/test/unit_tests/sample_files/fortran_files/long_string_test.F90 b/test/unit_tests/sample_files/fortran_files/long_string_test.F90 index 2910fe53..46e0c350 100644 --- a/test/unit_tests/sample_files/fortran_files/long_string_test.F90 +++ b/test/unit_tests/sample_files/fortran_files/long_string_test.F90 @@ -17,95 +17,95 @@ ! module long_string_test - foo100 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789' + foo100 = & + '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789' - foo101 = & - '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' + foo101 = & + '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' - foo102 = & - '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901' + foo102 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901' - foo103 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012' + foo103 = & + '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012' - foo104 = & - '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123' + foo104 = & + '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123' - foo105 = & - '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234' + foo105 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234' - foo106 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345' + foo106 = & + '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345' - foo107 = & - '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456' + foo107 = & + '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456' - foo108 = & - '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567' + foo108 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567' - foo109 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678' + foo109 = & + '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678' - foo110 = & - '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789' + foo110 = & + '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789' - foo111 = & - '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' + foo111 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' - foo112 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901' + foo112 = & + '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901' - foo113 = & - '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012' + foo113 = & + '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012' - foo114 = & - '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123' + foo114 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123' - foo115 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234' + foo115 = & + '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234' - foo116 = & - '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345' + foo116 = & + '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345' - foo117 = & - '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456' + foo117 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456' - foo118 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567' + foo118 = & + '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567' - foo119 = & - '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678' + foo119 = & + '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678' - foo120 = & - '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789' + foo120 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789' - foo121 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890& + foo121 = & + '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' + + foo122 = & + '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901' + + foo123 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012& &' - foo122 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890& -&1' - foo123 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890& -&12' - foo124 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890& -&123' - foo125 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890& -&1234' - foo126 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890& -&12345' - foo127 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890& -&123456' - foo128 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890& -&1234567' - foo129 = & - '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890& -&12345678' + foo124 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012& +&3' + foo125 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012& +&34' + foo126 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012& +&345' + foo127 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012& +&3456' + foo128 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012& +&34567' + foo129 = & + '012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012& +&345678' end module long_string_test diff --git a/test/unit_tests/test_fortran_write.py b/test/unit_tests/test_fortran_write.py index c2248896..8466e2ec 100644 --- a/test/unit_tests/test_fortran_write.py +++ b/test/unit_tests/test_fortran_write.py @@ -78,15 +78,32 @@ def test_line_breaking(self): header = "Test of line breaking for FortranWriter" with FortranWriter(generate, 'w', header, f"{testname}") as gen: # Test long declaration - data_items = ', '.join([f"name{x:03}" for x in range(100)]) - gen.write(f"character(len=7) :: data = (/ {data_items} /)", 1) + qchr = "'" + nditems = 100 + data_items = ', '.join([f"{qchr}name{x:03}{qchr}" for x in range(nditems)]) + gen.write(f"character(len=7) :: data({nditems}) = (/ {data_items} /)", 1) gen.end_module_header() # Test long code lines - line_items = ["call endrun('Cannot read columns_on_task from ", + gen.blank_line() + gen.write("subroutine foo(ozone_constituents, aerosol_constituents, " + "volcaero_constituents, other_constituents)", 1) + gen.write("integer, intent(in) :: ozone_constituents(:)", 2) + gen.write("integer, intent(in) :: aerosol_constituents(:)", 2) + gen.write("integer, intent(in) :: volcaero_constituents(:)", 2) + gen.write("integer, intent(in) :: other_constituents(:)", 2) + gen.write("real, allocatable :: tracer_data_test_dynamic_constituents(:)", 2) + gen.comment("codee format off", 0) + gen.write("allocate(tracer_data_test_dynamic_constituents(0+" + "size(ozone_constituents)+size(aerosol_constituents)" + "+size(volcaero_constituents)+size(other_constituents)))", 2) + gen.blank_line() + line_items = ["write(6, '(a)') 'Cannot read columns_on_task from ", "file'//', columns_on_task has no horizontal ", "dimension; columns_on_task is a ", - "protected variable')"] + "protected variable'"] gen.write(f"{''.join(line_items)}", 2) + gen.comment("codee format on", 0) + gen.write("end subroutine foo", 1) # end with # Check that file was generated