Coverage for src/m6rclib/metaphor_ast_node.py: 100%

45 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-11-19 09:50 +0000

1# Copyright 2024 M6R Ltd. 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14 

15""" 

16Types and classes for representing the AST (Abstract Syntax Tree) 

17of a Metaphor document. 

18""" 

19 

20from typing import List, Optional 

21from enum import IntEnum 

22 

23class MetaphorASTNodeType(IntEnum): 

24 """ 

25 Types of nodes that can appear in a Metaphor AST. 

26 """ 

27 ROOT: int = 0 

28 TEXT: int = 1 

29 ROLE: int = 2 

30 CONTEXT: int = 3 

31 ACTION: int = 4 

32 

33 

34class MetaphorASTNode: 

35 """ 

36 Represents a node in the Abstract Syntax Tree (AST). 

37  

38 Attributes: 

39 node_type (MetaphorASTNodeType): The type of the token the node represents. 

40 value (str): The value associated with the node. 

41 """ 

42 def __init__(self, node_type: MetaphorASTNodeType, value: str) -> None: 

43 self._node_type: MetaphorASTNodeType = node_type 

44 self._value: str = value 

45 self._parent: Optional['MetaphorASTNode'] = None 

46 self._children: List['MetaphorASTNode'] = [] 

47 

48 def __str__(self, indent: int = 0) -> str: 

49 """ 

50 Returns a string representation of the node and its children in a tree format. 

51 

52 Args: 

53 indent (int): The current indentation level (used recursively) 

54 

55 Returns: 

56 str: A formatted string showing the node's type, value, and children 

57 """ 

58 # Create the indentation string 

59 indent_str = " " * indent 

60 

61 # Start with this node's information 

62 result = f"{indent_str}{self.node_type.name}: {self.value}" 

63 

64 # Add all children with increased indentation 

65 for child in self._children: 

66 result += "\n" + child.__str__(indent + 1) 

67 

68 return result 

69 

70 def __repr__(self) -> str: 

71 """ 

72 Returns a concise representation of the node for debugging. 

73 

74 Returns: 

75 str: A string in format 'NodeType(value)[num_children]' 

76 """ 

77 return f"{self.node_type.name}({self.value})[{len(self._children)}]" 

78 

79 def attach_child(self, child: 'MetaphorASTNode') -> None: 

80 """Add a child node to this MetaphorASTNode.""" 

81 child.parent = self 

82 self._children.append(child) 

83 

84 def detach_child(self, child: 'MetaphorASTNode') -> None: 

85 """Detach a child node from this node in the AST.""" 

86 if child not in self.children: 

87 raise ValueError("Node is not a child of this node") 

88 

89 self._children.remove(child) 

90 child.parent = None 

91 

92 @property 

93 def node_type(self) -> MetaphorASTNodeType: 

94 """The type of this node.""" 

95 return self._node_type 

96 

97 @property 

98 def value(self) -> str: 

99 """The raw text value of this node.""" 

100 return self._value 

101 

102 @property 

103 def parent(self) -> Optional['MetaphorASTNode']: 

104 """The parent node, if any.""" 

105 return self._parent 

106 

107 @parent.setter 

108 def parent(self, new_parent: Optional['MetaphorASTNode']) -> None: 

109 self._parent = new_parent 

110 

111 @property 

112 def children(self) -> List['MetaphorASTNode']: 

113 """The node's children (returns a shallow copy to prevent direct list modification).""" 

114 return self._children.copy() 

115 

116 def get_children_of_type(self, node_type: MetaphorASTNodeType) -> List['MetaphorASTNode']: 

117 """ 

118 Returns a list of all immediate children that match the specified node type. 

119 

120 Args: 

121 node_type (MetaphorASTNodeType): The type of nodes to filter for 

122 

123 Returns: 

124 List[MetaphorASTNode]: List of child nodes matching the specified type 

125 """ 

126 return [child for child in self._children if child.node_type == node_type]