diff --git a/tools/prettify/prettify_cp2k/normalizeFortranFile.py b/tools/prettify/prettify_cp2k/normalizeFortranFile.py index 8f9002a285..2e6a69e724 100644 --- a/tools/prettify/prettify_cp2k/normalizeFortranFile.py +++ b/tools/prettify/prettify_cp2k/normalizeFortranFile.py @@ -8,22 +8,81 @@ try: except ImportError: from io import StringIO +# Declare various RE snippets for building larger REs + +# Valid fortran argument/variable name +VALID_NAME = r"[a-zA-Z][a-zA-Z_0-9]*" + +# Set up valid type declaration +DECL_KIND_KW = rf"\( (?:kind = )? (?:{VALID_NAME}|[0-9]+) \)".replace(" ", r"\s*") +DECL_KIND_STAR = r"\s*\*\s*[0-9]+" +CHAR_KIND_SPEC = rf"(?:(?:len|kind) = )? (?:{VALID_NAME}|[0-9]+|\*|:)" +CHAR_KIND_SPEC = rf"\( {CHAR_KIND_SPEC}(?: , {CHAR_KIND_SPEC}) \)".replace(" ", r"\s*") +DECL_KIND_SPEC = rf"\s*(?:{DECL_KIND_STAR}|{DECL_KIND_KW})" +DECL_TYPE_DEF = rf"""(?: +(?:integer|real|complex)(?:{DECL_KIND_SPEC})?| +character(?:{DECL_KIND_STAR}|{CHAR_KIND_SPEC})?| +logical(?:{DECL_KIND_KW})?|type|class)""" + +# String styles +DQUOTED = r'"[^"]*"' +SQUOTED = r"'[^']*'" +QUOTED = rf"(?:{DQUOTED}|{SQUOTED})" + +# Stop at punctuation +NOT_PUNC = r"[^()\"'\[\]]" +NOT_PUNC_COMMA = r"[^()\"',\[\]]" +NOT_BRAC = r"[^()]" + +# Enable new-style fortran arrays (square brackets) +BRAC_OPEN = r"[(\[]" +BRAC_CLOSE = r"[)\]]" +NOT_PAREN = r"[^()]" + +# Nested parens for up to 3-level nesting (1st level's parens are outside this variable) +# Should more than 3 levels be necessary, need to reduplicate this deeper. +NESTED_PAREN_1TO3_CONTENTS = ( + rf"(?:{NOT_PAREN}+|\((?:{NOT_PAREN}+|\({NOT_PAREN}*\))*\))*" +) + +# Variable statement VAR_RE = re.compile( - r" *(?P[a-zA-Z_0-9]+) *(?P(?:\((?P(?:[^()]+|\((?:[^()]+|\([^()]*\))*\))*)\))? *(?:= *(?P(?:[^\"',()\[\]]+|\[(?:[^()\"'\[\]]+|\([^()\"']*\)|\"[^\"]*\"|'[^']*')*\]|\((?:[^()\"'\[\]]+|\([^()\"']*\)|\"[^\"]*\"|'[^']*')*\)|\"[^\"]*\"|'[^']*')+))?)? *(?:(?P,)|\n?) *", - re.IGNORECASE, + rf""" +\s*(?P{VALID_NAME}) +\s*(?P(:?\((?P{NESTED_PAREN_1TO3_CONTENTS})\))? +\s*(?:=\s*(?P(?: +{NOT_PUNC_COMMA}+| +{BRAC_OPEN}(?:{NOT_PUNC}|{BRAC_OPEN}{NOT_PUNC}*{BRAC_CLOSE}|{QUOTED})*{BRAC_CLOSE}| +{QUOTED})+))?)? +\s*(?:(?P,)|\n?) +\s*""", + re.IGNORECASE | re.VERBOSE, ) + +# Use statement USE_PARSE_RE = re.compile( - r" *use +(?P[a-zA-Z_][a-zA-Z_0-9]*)(?P *, *only *:)? *(?P.*)$", - flags=re.IGNORECASE, + rf"""\s* +use(\s+|(?P\s*,\s*Intrinsic\s+::\s*)) +(?P{VALID_NAME}) +(?P\s*,\s*only\s*:)?\s* +(?P.*)$""", + flags=re.IGNORECASE | re.VERBOSE, ) -COMMON_USES_RE = re.compile('^#include *"([^"]*(cp_common_uses.f90|base_uses.f90))"') + +COMMON_USES_RE = re.compile('^#include\s*"([^"]*(cp_common_uses.f90|base_uses.f90))"') LOCAL_NAME_RE = re.compile( - " *(?P[a-zA-Z_0-9]+)(?: *= *> *[a-zA-Z_0-9]+)? *$" + rf"\s*(?P{VALID_NAME})(?:\s*=>\s*{VALID_NAME})?\s*$", re.VERBOSE ) VAR_DECL_RE = re.compile( - r" *(?Pinteger(?: *\* *[0-9]+)?|logical|character(?: *\* *[0-9]+)?|real(?: *\* *[0-9]+)?|complex(?: *\* *[0-9]+)?|type) *(?P\((?:[^()]+|\((?:[^()]+|\([^()]*\))*\))*\))? *(?P(?: *, *[a-zA-Z_0-9]+(?: *\((?:[^()]+|\((?:[^()]+|\([^()]*\))*\))*\))?)+)? *(?P::)?(?P[^\n]+)\n?", - re.IGNORECASE, -) # $ + rf""" +\s*(?P{DECL_TYPE_DEF}) +\s*(?P\({NESTED_PAREN_1TO3_CONTENTS}\))? +\s*(?P(?:\s*,\s*[a-zA-Z_0-9]+(?:\s*\({NESTED_PAREN_1TO3_CONTENTS}\))?)+)?\s* +(?P::)? +(?P[^\n]+)\n? +""", + re.IGNORECASE | re.VERBOSE, +) INDENT_SIZE = 2 DECL_LINELENGTH = 100 DECL_OFFSET = 50