Skip to content

Commit f86801d

Browse files
committed
Fixes bug with fortan line cont and preproc
Fixes Preprocessor statements in declarations break parsing #203 Fixes Preprocessor statements in declarations break parsing #4
1 parent 052f24d commit f86801d

File tree

7 files changed

+32
-8
lines changed

7 files changed

+32
-8
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
([gnikit/fortls#16](https://github.com/gnikit/fortls/issues/16))
3939
- Fixes `END FORALL` end of scope error
4040
([gnikit/fortls#18](https://github.com/gnikit/fortls/issues/18))
41+
- Fixes Fortran line continuation definitions intermingled with preprocessor directives
42+
([#203](https://github.com/hansec/fortran-language-server/issues/203))
43+
([gnikit/fortls#4](https://github.com/gnikit/fortls/issues/4))
4144

4245
## 1.16.0
4346

fortls/parse_fortran.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
NAT_VAR_REGEX,
105105
NON_DEF_REGEX,
106106
PARAMETER_VAL_REGEX,
107+
PP_ANY_REGEX,
107108
PP_DEF_REGEX,
108109
PP_INCLUDE_REGEX,
109110
PP_REGEX,
@@ -978,7 +979,7 @@ def get_code_line(
978979
line_ind -= 1
979980
else: # Free format file
980981
opt_cont_match = FREE_CONT_REGEX.match(curr_line)
981-
if opt_cont_match is not None:
982+
if opt_cont_match:
982983
curr_line = (
983984
" " * opt_cont_match.end(0) + curr_line[opt_cont_match.end(0) :]
984985
)
@@ -989,7 +990,7 @@ def get_code_line(
989990
tmp_no_comm = tmp_line.split("!")[0]
990991
cont_ind = tmp_no_comm.rfind("&")
991992
opt_cont_match = FREE_CONT_REGEX.match(tmp_no_comm)
992-
if opt_cont_match is not None:
993+
if opt_cont_match:
993994
if cont_ind == opt_cont_match.end(0) - 1:
994995
break
995996
tmp_no_comm = (
@@ -1022,21 +1023,27 @@ def get_code_line(
10221023
if iComm < 0:
10231024
iComm = iAmper + 1
10241025
next_line = ""
1026+
# Read the next line if needed
10251027
while (iAmper >= 0) and (iAmper < iComm):
10261028
if line_ind == line_number + 1:
10271029
curr_line = curr_line[:iAmper]
10281030
elif next_line != "":
10291031
post_lines[-1] = next_line[:iAmper]
10301032
next_line = self.get_line(line_ind, pp_content)
10311033
line_ind += 1
1034+
# Skip any preprocessor statements when seeking the next line
1035+
if PP_ANY_REGEX.match(next_line):
1036+
next_line = ""
1037+
post_lines.append("")
1038+
continue
10321039
# Skip empty or comment lines
10331040
match = FREE_COMMENT_LINE_MATCH.match(next_line)
1034-
if (next_line.rstrip() == "") or (match is not None):
1041+
if next_line.rstrip() == "" or match:
10351042
next_line = ""
10361043
post_lines.append("")
10371044
continue
10381045
opt_cont_match = FREE_CONT_REGEX.match(next_line)
1039-
if opt_cont_match is not None:
1046+
if opt_cont_match:
10401047
next_line = (
10411048
" " * opt_cont_match.end(0)
10421049
+ next_line[opt_cont_match.end(0) :]
@@ -1056,9 +1063,7 @@ def get_code_line(
10561063
def strip_comment(self, line: str) -> str:
10571064
"""Strip comment from line"""
10581065
if self.fixed:
1059-
if (FIXED_COMMENT_LINE_MATCH.match(line) is not None) and (
1060-
FIXED_OPENMP_MATCH.match(line) is not None
1061-
):
1066+
if FIXED_COMMENT_LINE_MATCH.match(line) and FIXED_OPENMP_MATCH.match(line):
10621067
return ""
10631068
else:
10641069
if FREE_OPENMP_MATCH.match(line) is None:

fortls/regex_patterns.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
PP_DEF_REGEX = re.compile(r"#(define|undef)[ ]*([\w]+)(\((\w+(,[ ]*)?)+\))?", re.I)
112112
PP_DEF_TEST_REGEX = re.compile(r"(![ ]*)?defined[ ]*\([ ]*([a-z0-9_]*)[ ]*\)$", re.I)
113113
PP_INCLUDE_REGEX = re.compile(r"#include[ ]*([\"a-z0-9_\.]*)", re.I)
114+
PP_ANY_REGEX = re.compile(r"(^#:?\w+)")
114115
# Context matching rules
115116
CALL_REGEX = re.compile(r"[ ]*CALL[ ]+[a-z0-9_%]*$", re.I)
116117
INT_STMNT_REGEX = re.compile(r"^[ ]*[a-z]*$", re.I)

test/test_preproc.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ def check_return(result_array, checks):
3434
string += hover_req(file_path, 7, 40) # multi-lin variable
3535
string += hover_req(file_path, 8, 7) # function with if conditional
3636
string += hover_req(file_path, 9, 7) # multiline function with if conditional
37+
file_path = os.path.join(test_dir, "pp", "preproc_keywords.F90")
38+
string += hover_req(file_path, 6, 2) # ignores PP across Fortran line continuations
3739
errcode, results = run_request(string, f" --config={root_dir}/.pp_conf.json")
3840
assert errcode == 0
3941

@@ -44,6 +46,7 @@ def check_return(result_array, checks):
4446
"#define varVar 55",
4547
"#define ewrite if (priority <= 3) write((priority), format)",
4648
"#define ewrite2 if (priority <= 3) write((priority), format)",
49+
"REAL, CONTIGUOUS, POINTER, DIMENSION(:)",
4750
)
4851
assert len(ref_results) == len(results) - 1
4952
check_return(results[1:], ref_results)

test/test_server.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ def check_return(result_array):
186186
["test_int", 2, 0],
187187
["test_mod", 2, 0],
188188
["test_nonint_mod", 2, 0],
189+
["test_preproc_keywords", 2, 0],
189190
["test_program", 2, 0],
190191
["test_rename_sub", 6, 9],
191192
["test_select", 2, 0],

test/test_source/pp/.pp_conf.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
"enable_code_actions": true,
77
"pp_suffixes": [".h", ".F90"],
88
"incl_suffixes": [".h"],
9-
"include_dirs": ["include"]
9+
"include_dirs": ["include"],
10+
"pp_defs": { "HAVE_CONTIGUOUS": "" }
1011
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
program test_preproc_keywords
2+
REAL &
3+
#ifdef HAVE_CONTIGUOUS
4+
, CONTIGUOUS &
5+
#endif
6+
, POINTER :: &
7+
var1(:), &
8+
var2(:)
9+
10+
end program test_preproc_keywords

0 commit comments

Comments
 (0)