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
« 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
5from castep_linter.fortran.fortran_node import Fortran, FortranNode, WrongNodeError
6from castep_linter.fortran.identifier import Identifier
9class ArgType(Enum):
10 """Types of arguments for fortran functions/subroutines"""
12 KEYWORD = auto()
13 POSITION = auto()
14 # NONE = auto()
17class ArgParser:
18 """Parser for fortran argument lists"""
20 ALLOWED_NODES: ClassVar[List[Fortran]] = [Fortran.ARGUMENT_LIST]
21 ArgType = ArgType
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 = [], {}
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]
36 err = f"Argument {keyword} not found in argument list"
37 raise KeyError(err)
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)
49 args = []
50 kwargs = {}
52 parsing_arg_list = True
54 for child in node.children[1:-1:2]:
55 if child.is_type(Fortran.KEYWORD_ARGUMENT):
56 parsing_arg_list = False
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)
67 return args, kwargs