Coverage for src/castep_linter/fortran/argument_parser.py: 89%

39 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-11-23 18:07 +0000

1"""Module containing an argument list parser""" 

2from enum import Enum, auto 

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

4 

5from castep_linter.fortran.fortran_node import Fortran, FortranNode, WrongNodeError 

6from castep_linter.fortran.identifier import Identifier 

7 

8 

9class ArgType(Enum): 

10 """Types of arguments for fortran functions/subroutines""" 

11 

12 KEYWORD = auto() 

13 POSITION = auto() 

14 # NONE = auto() 

15 

16 

17class ArgParser: 

18 """Parser for fortran argument lists""" 

19 

20 ALLOWED_NODES: ClassVar[List[Fortran]] = [Fortran.ARGUMENT_LIST] 

21 ArgType = ArgType 

22 

23 def __init__(self, arg_list: Optional[FortranNode] = None): 

24 if arg_list: 

25 self.args, self.kwargs = parse_arg_list(arg_list) 

26 else: 

27 self.args, self.kwargs = [], {} 

28 

29 def get(self, keyword: Identifier, position: Optional[int] = None): 

30 """Return a value from a fortran argument list by keyword and optionally position""" 

31 if position and len(self.args) >= position: 

32 return ArgType.POSITION, self.args[position - 1] 

33 if keyword in self.kwargs: 

34 return ArgType.KEYWORD, self.kwargs[keyword] 

35 

36 err = f"Argument {keyword} not found in argument list" 

37 raise KeyError(err) 

38 

39 

40def parse_arg_list(node: FortranNode) -> Tuple[List[FortranNode], Dict[Identifier, FortranNode]]: 

41 """ 

42 Convert a fortran argument list into a args, kwargs pair. 

43 The keyword arguments will be converted into identifiers. 

44 """ 

45 if not node.is_type(Fortran.ARGUMENT_LIST): 45 ↛ 46line 45 didn't jump to line 46, because the condition on line 45 was never true

46 err = "Expected argument list" 

47 raise WrongNodeError(err) 

48 

49 args = [] 

50 kwargs = {} 

51 

52 parsing_arg_list = True 

53 

54 for child in node.children[1:-1:2]: 

55 if child.is_type(Fortran.KEYWORD_ARGUMENT): 

56 parsing_arg_list = False 

57 

58 if parsing_arg_list: 

59 args.append(child) 

60 elif child.is_type(Fortran.KEYWORD_ARGUMENT): 60 ↛ 64line 60 didn't jump to line 64, because the condition on line 60 was never false

61 key, _, value = child.children 

62 kwargs[Identifier.from_node(key)] = value 

63 else: 

64 err = f"Unknown argument list item in keyword arguments: {child.type}" 

65 raise ValueError(err) 

66 

67 return args, kwargs