Coverage for src/lumen/fhirpath/parser/ASTPathListener.py: 100%

33 statements  

« prev     ^ index     » next       coverage.py v7.16.0, created at 2026-08-31 18:46 +0000

1from antlr4.tree.Tree import TerminalNodeImpl 

2from lumen.fhirpath.parser.generated.FHIRPathListener import FHIRPathListener 

3 

4 

5def has_node_type_text(node_type): 

6 # In general we need mostly terminal nodes (e.g. Identifier and any Literal) 

7 # But the code also uses TypeSpecifier, InvocationExpression and TermExpression 

8 return node_type.endswith("Literal") or node_type in [ 

9 "LiteralTerm", 

10 "Identifier", 

11 "TypeSpecifier", 

12 "InvocationExpression", 

13 "TermExpression", 

14 ] 

15 

16 

17class ASTPathListener(FHIRPathListener): 

18 def __init__(self): 

19 self.parentStack = [{}] 

20 

21 def pushNode(self, nodeType, ctx): 

22 parentNode = self.parentStack[-1] 

23 node = {"type": nodeType, "terminalNodeText": []} 

24 if has_node_type_text(nodeType): 

25 node["text"] = ctx.getText() 

26 for child in ctx.children: 

27 if isinstance(child, TerminalNodeImpl): 

28 node["terminalNodeText"].append(child.getText()) 

29 

30 if "children" not in parentNode: 

31 parentNode["children"] = [] 

32 

33 parentNode["children"].append(node) 

34 

35 self.parentStack.append(node) 

36 

37 def popNode(self): 

38 if len(self.parentStack) > 0: 

39 self.parentStack.pop() 

40 

41 def __getattribute__(self, name): 

42 attr = object.__getattribute__(self, name) 

43 

44 if name in FHIRPathListener.__dict__ and callable(attr): 

45 

46 def newfunc(*args, **kwargs): 

47 if name.startswith("enter"): 

48 self.pushNode(name[5:], args[0]) 

49 

50 if name.startswith("exit"): 

51 self.popNode() 

52 

53 return attr(*args, **kwargs) 

54 

55 return newfunc 

56 return attr