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

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"""

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

17 of a Metaphor document.

18"""

19

20 from typing import List, Optional

21 from enum import IntEnum

22

23 class 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

34 class 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]