Skip to content

Commit

Permalink
Merge pull request #324 from fortran-lang/refactor/objetcs
Browse files Browse the repository at this point in the history
Refactoring Fortran Objects
  • Loading branch information
gnikit committed Oct 21, 2023
2 parents a096d8e + 5b6acfc commit 27b9d49
Show file tree
Hide file tree
Showing 4 changed files with 361 additions and 349 deletions.
121 changes: 76 additions & 45 deletions fortls/helper_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,9 @@ def strip_line_label(line: str) -> tuple[str, str | None]:
match = FRegex.LINE_LABEL.match(line)
if match is None:
return line, None
else:
line_label = match.group(1)
out_str = line[: match.start(1)] + " " * len(line_label) + line[match.end(1) :]
return out_str, line_label
line_label = match.group(1)
out_str = line[: match.start(1)] + " " * len(line_label) + line[match.end(1) :]
return out_str, line_label


def strip_strings(in_line: str, maintain_len: bool = False) -> str:
Expand Down Expand Up @@ -172,7 +171,7 @@ def separate_def_list(test_str: str) -> list[str] | None:
if curr_str != "":
def_list.append(curr_str)
curr_str = ""
elif (curr_str == "") and (len(def_list) == 0):
elif not def_list:
return None
continue
curr_str += char
Expand All @@ -198,17 +197,20 @@ def find_word_in_line(line: str, word: str) -> Range:
start and end positions (indices) of the word if not found it returns
-1, len(word) -1
"""
i = -1
for poss_name in FRegex.WORD.finditer(line):
if poss_name.group() == word:
i = poss_name.start()
break
i = next(
(
poss_name.start()
for poss_name in FRegex.WORD.finditer(line)
if poss_name.group() == word
),
-1,
)
# TODO: if i == -1: return None makes more sense
return Range(i, i + len(word))


def find_paren_match(string: str) -> int:
"""Find matching closing parenthesis **from an already open parenthesis scope**
"""Find matching closing parenthesis from an already open parenthesis scope
by forward search of the string, returns -1 if no match is found
Parameters
Expand Down Expand Up @@ -237,15 +239,14 @@ def find_paren_match(string: str) -> int:
-1
"""
paren_count = 1
ind = -1
for i, char in enumerate(string):
if char == "(":
paren_count += 1
elif char == ")":
paren_count -= 1
if paren_count == 0:
return i
return ind
return -1


def get_line_prefix(
Expand Down Expand Up @@ -282,17 +283,16 @@ def get_line_prefix(
col += len(prepend_string)
line_prefix = curr_line[:col].lower()
# Ignore string literals
if qs:
if (line_prefix.find("'") > -1) or (line_prefix.find('"') > -1):
sq_count = 0
dq_count = 0
for char in line_prefix:
if (char == "'") and (dq_count % 2 == 0):
sq_count += 1
elif (char == '"') and (sq_count % 2 == 0):
dq_count += 1
if (dq_count % 2 == 1) or (sq_count % 2 == 1):
return None
if qs and ((line_prefix.find("'") > -1) or (line_prefix.find('"') > -1)):
sq_count = 0
dq_count = 0
for char in line_prefix:
if (char == "'") and (dq_count % 2 == 0):
sq_count += 1
elif (char == '"') and (sq_count % 2 == 0):
dq_count += 1
if (dq_count % 2 == 1) or (sq_count % 2 == 1):
return None
return line_prefix


Expand Down Expand Up @@ -329,14 +329,12 @@ def resolve_globs(glob_path: str, root_path: str = None) -> list[str]:
>>> resolve_globs('test') == [str(pathlib.Path(os.getcwd()) / 'test')]
True
"""
# Resolve absolute paths i.e. not in our root_path
if os.path.isabs(glob_path) or not root_path:
p = Path(glob_path).resolve()
root = p.anchor # drive letter + root path
rel = str(p.relative_to(root)) # contains glob pattern
return [str(p.resolve()) for p in Path(root).glob(rel)]
else:
if not os.path.isabs(glob_path) and root_path:
return [str(p.resolve()) for p in Path(root_path).resolve().glob(glob_path)]
p = Path(glob_path).resolve()
root = p.anchor # drive letter + root path
rel = str(p.relative_to(root)) # contains glob pattern
return [str(p.resolve()) for p in Path(root).glob(rel)]


def only_dirs(paths: list[str]) -> list[str]:
Expand Down Expand Up @@ -406,7 +404,9 @@ def map_keywords(keywords: list[str]):
return mapped_keywords, keyword_info


def get_keywords(keywords: list, keyword_info: dict = {}):
def get_keywords(keywords: list, keyword_info: dict = None):
if keyword_info is None:
keyword_info = {}
keyword_strings = []
for keyword_id in keywords:
string_rep = KEYWORD_LIST[keyword_id]
Expand Down Expand Up @@ -461,10 +461,7 @@ def get_paren_substring(string: str) -> str | None:
"""
i1 = string.find("(")
i2 = string.rfind(")")
if -1 < i1 < i2:
return string[i1 + 1 : i2]
else:
return None
return string[i1 + 1 : i2] if -1 < i1 < i2 else None


def get_paren_level(line: str) -> tuple[str, list[Range]]:
Expand Down Expand Up @@ -496,7 +493,7 @@ def get_paren_level(line: str) -> tuple[str, list[Range]]:
('', [Range(start=0, end=0)])
"""
if line == "":
if not line:
return "", [Range(0, 0)]
level = 0
in_string = False
Expand Down Expand Up @@ -526,9 +523,7 @@ def get_paren_level(line: str) -> tuple[str, list[Range]]:
if level == 0:
sections.append(Range(i, i1))
sections.reverse()
out_string = ""
for section in sections:
out_string += line[section.start : section.end]
out_string = "".join(line[section.start : section.end] for section in sections)
return out_string, sections


Expand Down Expand Up @@ -564,7 +559,7 @@ def get_var_stack(line: str) -> list[str]:
>>> get_var_stack('')
['']
"""
if len(line) == 0:
if not line:
return [""]
final_var, sections = get_paren_level(line)
if final_var == "":
Expand All @@ -574,10 +569,9 @@ def get_var_stack(line: str) -> list[str]:
for i, section in enumerate(sections):
if not line[section.start : section.end].strip().startswith("%"):
iLast = i
final_var = ""
for section in sections[iLast:]:
final_var += line[section.start : section.end]

final_var = "".join(
line[section.start : section.end] for section in sections[iLast:]
)
if final_var is not None:
final_var = "%".join([i.strip() for i in final_var.split("%")])
final_op_split: list[str] = FRegex.OBJBREAK.split(final_var)
Expand All @@ -586,6 +580,43 @@ def get_var_stack(line: str) -> list[str]:
return None


def get_placeholders(arg_list: list[str]) -> tuple[str, str]:
"""
Function used to generate placeholders for snippets
Parameters
----------
arg_list : list[str]
Method arguments list
Returns
-------
Tuple[str, str]
Tuple of arguments as a string and snippet string
Examples
--------
>>> get_placeholders(['x', 'y'])
('(x, y)', '(${1:x}, ${2:y})')
>>> get_placeholders(['x=1', 'y=2'])
('(x=1, y=2)', '(x=${1:1}, y=${2:2})')
>>> get_placeholders(['x', 'y=2', 'z'])
('(x, y=2, z)', '(${1:x}, y=${2:2}, ${3:z})')
"""
place_holders = []
for i, arg in enumerate(arg_list):
opt_split = arg.split("=")
if len(opt_split) > 1:
place_holders.append(f"{opt_split[0]}=${{{i+1}:{opt_split[1]}}}")
else:
place_holders.append(f"${{{i+1}:{arg}}}")
arg_str = f"({', '.join(arg_list)})"
arg_snip = f"({', '.join(place_holders)})"
return arg_str, arg_snip


def fortran_md(code: str, docs: str | None):
"""Convert Fortran code to markdown
Expand Down
30 changes: 10 additions & 20 deletions fortls/intrinsics.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import glob
import json
import os
import pathlib

from fortls.helper_functions import fortran_md, map_keywords
from fortls.helper_functions import fortran_md, get_placeholders, map_keywords
from fortls.objects import (
FortranAST,
FortranObj,
Expand All @@ -26,9 +27,7 @@ def set_lowercase_intrinsics():


def intrinsics_case(name: str, args: str):
if lowercase_intrinsics:
return name.lower(), args.lower()
return name, args
return (name.lower(), args.lower()) if lowercase_intrinsics else (name, args)


class Intrinsic(FortranObj):
Expand Down Expand Up @@ -68,19 +67,13 @@ def get_snippet(self, name_replace=None, drop_arg=-1):
arg_snip = None
else:
arg_list = self.args.split(",")
arg_str, arg_snip = self.get_placeholders(arg_list)
name = self.name
if name_replace is not None:
name = name_replace
snippet = None
if arg_snip is not None:
snippet = name + arg_snip
arg_str, arg_snip = get_placeholders(arg_list)
name = name_replace if name_replace is not None else self.name
snippet = name + arg_snip if arg_snip is not None else None
return name + arg_str, snippet

def get_signature(self):
arg_sigs = []
for arg in self.args.split(","):
arg_sigs.append({"label": arg})
arg_sigs = [{"label": arg} for arg in self.args.split(",")]
call_sig, _ = self.get_snippet()
return call_sig, self.doc_str, arg_sigs

Expand All @@ -89,13 +82,11 @@ def get_hover(self, long=False):

def get_hover_md(self, long=False):
msg, docs = self.get_hover(long)
msg = msg if msg else ""
msg = msg or ""
return fortran_md(msg, docs)

def is_callable(self):
if self.type == 2:
return True
return False
return self.type == 2


def load_intrinsics():
Expand Down Expand Up @@ -281,8 +272,7 @@ def update_m_intrinsics():
for f in sorted(files):
key = f.replace("M_intrinsics/md/", "")
key = key.replace(".md", "").upper() # remove md extension
with open(f) as md_f:
val = md_f.read()
val = pathlib.Path(f).read_text()
# remove manpage tag
val = val.replace(f"**{key.lower()}**(3)", f"**{key.lower()}**")
val = val.replace(f"**{key.upper()}**(3)", f"**{key.upper()}**")
Expand Down
2 changes: 1 addition & 1 deletion fortls/json_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def range_json(sln: int, sch: int, eln: int = None, ech: int = None):
}


def diagnostic_json(sln: int, sch: int, eln: int, ech: int, msg: str, sev: str):
def diagnostic_json(sln: int, sch: int, eln: int, ech: int, msg: str, sev: int):
return {**range_json(sln, sch, eln, ech), "message": msg, "severity": sev}


Expand Down
Loading

0 comments on commit 27b9d49

Please sign in to comment.