Coverage for src/castep_linter/fortran/variable_declaration.py: 100%

1"""Module holding the VariableDeclaration type"""

2 from enum import Enum, auto

3 from typing import ClassVar, Dict, List, Optional, Set, Tuple

4

5 from castep_linter.fortran.argument_parser import ArgParser, ArgType

6 from castep_linter.fortran.fortran_node import Fortran, FortranNode

7 from castep_linter.fortran.fortran_statement import FortranStatementParser

8 from castep_linter.fortran.identifier import Identifier

9

10

11 class FType(Enum):

12 """Intrinsic variable types in fortran"""

13

14 REAL = auto()

15 DOUBLE = auto()

16 COMPLEX = auto()

17 INTEGER = auto()

18 LOGICAL = auto()

19 CHARACTER = auto()

20 OTHER = auto()

21

22

23 def parse_fort_type(var_decl_node: FortranNode) -> FType:

24 """Parse a variable declaration for type"""

25 try:

26 fortran_type = var_decl_node.get(Fortran.INTRINSIC_TYPE).raw.upper()

27 if fortran_type == "DOUBLE PRECISION":

28 return FType.DOUBLE

29 else:

30 return FType[fortran_type]

31 except KeyError:

32 return FType.OTHER

33

34

35 def parse_fort_type_qualifiers(var_decl_node: FortranNode) -> Set[str]:

36 """Parse a variable declaration for qualifiers, eg parameter"""

37 qualifiers = set()

38 for type_qualifier in var_decl_node.get_children_by_name(Fortran.TYPE_QUALIFIER):

39 qualifier = type_qualifier.raw.lower()

40 qualifiers.add(qualifier)

41 return qualifiers

42

43

44 def parse_fort_var_size(var_decl_node: FortranNode) -> ArgParser:

45 """Parse a variable declaration for a size, eg kind=8"""

46 try:

47 fortran_size = var_decl_node.get(Fortran.SIZE)

48 except KeyError:

49 return ArgParser()

50

51 return ArgParser(fortran_size.get(Fortran.ARGUMENT_LIST))

52

53

54 def parse_fort_var_names(var_decl_node: FortranNode) -> Dict[Identifier, Optional[str]]:

55 """Parse variable declaration statement for variables and optionally assignments"""

56 myvars: Dict[Identifier, Optional[str]] = {}

57 for assignment in var_decl_node.get_children_by_name(Fortran.ASSIGNMENT_STMT):

58 lhs, rhs = assignment.split()

59 # lhs, rhs = split_relational_node(assignment)

60 varname = Identifier.from_node(lhs)

61 if rhs.is_type(Fortran.STRING_LITERAL):

62 myvars[varname] = rhs.parse_string_literal()

63 else:

64 myvars[varname] = None

65 return myvars

66

67

68 class VariableDeclaration(FortranStatementParser):

69 """Class representing a variable declaration"""

70

71 ALLOWED_NODES: ClassVar[List[Fortran]] = [Fortran.VARIABLE_DECLARATION]

72

73 def __init__(self, var_decl_node: FortranNode) -> None:

74 super().__init__(var_decl_node)

75

76 self.type = parse_fort_type(var_decl_node)

77 self.qualifiers = parse_fort_type_qualifiers(var_decl_node)

78 self.vars = parse_fort_var_names(var_decl_node)

79 self.args = parse_fort_var_size(var_decl_node)

80

81 def get_arg(

82 self, keyword: Identifier, position: Optional[int] = None

83 ) -> Tuple[ArgType, FortranNode]:

84 """Get an argument from the call expression"""

85 return self.args.get(keyword, position)