107107SELCASE_RE = re .compile (
108108 SOL_STR + r"SELECT\s*(CASE|TYPE)\s*\(.+\)" + EOL_STR , RE_FLAGS )
109109CASE_RE = re .compile (
110- SOL_STR + r"(CASE|TYPE\s+IS|CLASS\s+IS)\s*(\(.+\)|DEFAULT)" + EOL_STR , RE_FLAGS )
110+ SOL_STR + r"(( CASE|TYPE\s+IS|CLASS\s+IS)\s*(\(.+\)|DEFAULT)|CLASS\s+ DEFAULT)" + EOL_STR , RE_FLAGS )
111111ENDSEL_RE = re .compile (SOL_STR + r"END\s*SELECT" + EOL_STR , RE_FLAGS )
112112
113113ASSOCIATE_RE = re .compile (SOL_STR + r"ASSOCIATE\s*\(.+\)" + EOL_STR , RE_FLAGS )
114114ENDASSOCIATE_RE = re .compile (SOL_STR + r"END\s*ASSOCIATE" + EOL_STR , RE_FLAGS )
115115
116+ BLK_RE = re .compile (SOL_STR + r"(\w+\s*:)?\s*BLOCK" + EOL_STR , RE_FLAGS )
117+ ENDBLK_RE = re .compile (SOL_STR + r"END\s*BLOCK(\s+\w+)?" + EOL_STR , RE_FLAGS )
118+
116119SUBR_RE = re .compile (
117120 r"^([^\"'!]* )?SUBROUTINE\s+\w+\s*(\(.*\))?" + EOL_STR , RE_FLAGS )
118121ENDSUBR_RE = re .compile (
151154
152155ENDANY_RE = re .compile (SOL_STR + r"END" + EOL_STR , RE_FLAGS )
153156
157+ PRIVATE_RE = re .compile (SOL_STR + r"PRIVATE\s*::" , RE_FLAGS )
154158PUBLIC_RE = re .compile (SOL_STR + r"PUBLIC\s*::" , RE_FLAGS )
155159
156160# intrinsic statements with parenthesis notation that are not functions
165169# Note: +/- in real literals and sign operator is ignored
166170PLUSMINUS_RE = re .compile (
167171 r"(?<=[\w\)\]])(?<![\d\.]\w)\s*(\+|-)\s*" , RE_FLAGS )
172+ # Note: ** or // (or any multiples of * or /) are ignored
173+ MULTDIV_RE = re .compile (
174+ r"(?<=[\w\)\]])\s*((?<!\*)\*(?!\*)|(?<!/)/(?!/))(?=[\s\w\(])" , RE_FLAGS )
168175REL_OP_RE = re .compile (
169176 r"(?<!\()\s*(\.(?:EQ|NE|LT|LE|GT|GE)\.|(?:==|\/=|<(?!=)|<=|(?<!=)>(?!=)|>=))\s*(?!\))" ,
170177 RE_FLAGS )
181188EMPTY_RE = re .compile (SOL_STR + r"([!#].*)?$" , RE_FLAGS )
182189
183190# two-sided operators
184- LR_OPS_RE = [REL_OP_RE , LOG_OP_RE , PLUSMINUS_RE , PRINT_RE ]
191+ LR_OPS_RE = [REL_OP_RE , LOG_OP_RE , PLUSMINUS_RE , MULTDIV_RE , PRINT_RE ]
185192
186193USE_RE = re .compile (
187194 SOL_STR + "USE(\s+|(,.+?)?::\s*)\w+?((,.+?=>.+?)+|,\s*only\s*:.+?)?$" + EOL_STR , RE_FLAGS )
191198
192199# combine regex that define subunits
193200NEW_SCOPE_RE = [IF_RE , DO_RE , SELCASE_RE , SUBR_RE ,
194- FCT_RE , MOD_RE , PROG_RE , INTERFACE_RE , TYPE_RE , ENUM_RE , ASSOCIATE_RE , None ]
201+ FCT_RE , MOD_RE , PROG_RE , INTERFACE_RE , TYPE_RE , ENUM_RE , ASSOCIATE_RE , None , BLK_RE ]
195202CONTINUE_SCOPE_RE = [ELSE_RE , None , CASE_RE , CONTAINS_RE ,
196- CONTAINS_RE , CONTAINS_RE , CONTAINS_RE , None , CONTAINS_RE , None , None , None ]
203+ CONTAINS_RE , CONTAINS_RE , CONTAINS_RE , None , CONTAINS_RE , None , None , None , None ]
197204END_SCOPE_RE = [ENDIF_RE , ENDDO_RE , ENDSEL_RE , ENDSUBR_RE ,
198- ENDFCT_RE , ENDMOD_RE , ENDPROG_RE , ENDINTERFACE_RE , ENDTYPE_RE , ENDENUM_RE , ENDASSOCIATE_RE , ENDANY_RE ]
205+ ENDFCT_RE , ENDMOD_RE , ENDPROG_RE , ENDINTERFACE_RE , ENDTYPE_RE , ENDENUM_RE , ENDASSOCIATE_RE , ENDANY_RE , ENDBLK_RE ]
199206
207+ # match namelist names
208+ NML_RE = re .compile (r"(/\w+/)" , RE_FLAGS )
209+ # find namelists and data statements
210+ NML_STMT_RE = re .compile (SOL_STR + r"NAMELIST.*/.*/" , RE_FLAGS )
211+ DATA_STMT_RE = re .compile (SOL_STR + r"DATA\s+\w" , RE_FLAGS )
200212
201213class F90Indenter (object ):
202214 """
@@ -394,7 +406,7 @@ def process_lines_of_fline(self, f_line, lines, rel_ind, line_nr):
394406
395407 self .__init_line (line_nr )
396408
397- is_decl = VAR_DECL_RE .search (f_line ) or PUBLIC_RE .search (f_line )
409+ is_decl = VAR_DECL_RE .search (f_line ) or PUBLIC_RE .search (f_line ) or PRIVATE_RE . match ( f_line )
398410 for pos , line in enumerate (lines ):
399411 self .__align_line_continuations (
400412 line , is_decl , rel_ind , self ._line_nr + pos )
@@ -566,7 +578,7 @@ def format_single_fline(f_line, whitespace, linebreak_pos, ampersand_sep,
566578 separating whitespace characters before ampersand (`ampersand_sep`).
567579 `filename` and `line_nr` just for error messages.
568580 The higher `whitespace`, the more white space characters inserted -
569- whitespace = 0, 1, 2 are currently supported.
581+ whitespace = 0, 1, 2, 3 are currently supported.
570582 auto formatting can be turned off by setting `auto_format` to False.
571583 """
572584
@@ -576,14 +588,17 @@ def format_single_fline(f_line, whitespace, linebreak_pos, ampersand_sep,
576588 # 2: relational operators
577589 # 3: logical operators
578590 # 4: arithm. operators plus and minus
579- # 5: print / read statements
591+ # 5: arithm. operators multiply and divide
592+ # 6: print / read statements
580593
581594 if whitespace == 0 :
582- spacey = [0 , 0 , 0 , 0 , 0 , 0 ]
595+ spacey = [0 , 0 , 0 , 0 , 0 , 0 , 0 ]
583596 elif whitespace == 1 :
584- spacey = [1 , 1 , 1 , 1 , 0 , 1 ]
597+ spacey = [1 , 1 , 1 , 1 , 0 , 0 , 1 ]
585598 elif whitespace == 2 :
586- spacey = [1 , 1 , 1 , 1 , 1 , 1 ]
599+ spacey = [1 , 1 , 1 , 1 , 1 , 0 , 1 ]
600+ elif whitespace == 3 :
601+ spacey = [1 , 1 , 1 , 1 , 1 , 1 , 1 ]
587602 else :
588603 raise NotImplementedError ("unknown value for whitespace" )
589604
@@ -668,6 +683,8 @@ def add_whitespace_charwise(line, spacey, filename, line_nr):
668683 line [:pos ], RE_FLAGS ) or
669684 re .search (SOL_STR + r"SELECT\s*TYPE\s*" ,
670685 line [:pos ], RE_FLAGS ) or
686+ re .search (SOL_STR + r"CLASS\s*DEFAULT\s*" ,
687+ line [:pos ], RE_FLAGS ) or
671688 re .search (SOL_STR + r"(TYPE|CLASS)\s+IS\s*" ,
672689 line [:pos ], RE_FLAGS ) or
673690 re .search (r"\b" + INTR_STMTS_PAR + r"\s*$" ,
@@ -764,13 +781,23 @@ def add_whitespace_context(line, spacey):
764781 if pos == len (line ) - 1 :
765782 line_parts .append (line [str_end + 1 :])
766783
784+ # format namelists with spaces around /
785+ if NML_STMT_RE .match (line ):
786+ for pos , part in enumerate (line_parts ):
787+ # exclude comments, strings:
788+ if not re .match (r"['\"!]" , part , RE_FLAGS ):
789+ partsplit = NML_RE .split (part )
790+ line_parts [pos ] = (' ' .join (partsplit ))
791+
767792 # Two-sided operators
768793 for n_op , lr_re in enumerate (LR_OPS_RE ):
769794 for pos , part in enumerate (line_parts ):
770795 # exclude comments, strings:
771796 if not re .search (r"^['\"!]" , part , RE_FLAGS ):
772- partsplit = lr_re .split (part )
773- line_parts [pos ] = (' ' * spacey [n_op + 2 ]).join (partsplit )
797+ # also exclude / if we see a namelist and data statement
798+ if not ( NML_STMT_RE .match (line ) or DATA_STMT_RE .match (line ) ):
799+ partsplit = lr_re .split (part )
800+ line_parts [pos ] = (' ' * spacey [n_op + 2 ]).join (partsplit )
774801
775802 line = '' .join (line_parts )
776803
@@ -1216,7 +1243,7 @@ def run(argv=sys.argv): # pragma: no cover
12161243 parser .add_argument ("-i" , "--indent" , type = int , default = 3 ,
12171244 help = "relative indentation width" )
12181245 parser .add_argument ("-w" , "--whitespace" , type = int ,
1219- choices = range (0 , 3 ), default = 2 , help = "Amount of whitespace" )
1246+ choices = range (0 , 4 ), default = 2 , help = "Amount of whitespace" )
12201247 parser .add_argument ("-s" , "--stdout" , action = 'store_true' , default = False ,
12211248 help = "Write to stdout instead of formatting inplace" )
12221249
0 commit comments