Coverage for src/m6rclib/ast_node.py: 85%

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 ASTNodeType(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 ASTNode:

35 """

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

37

38 Attributes:

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

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

41 """

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

43 self._node_type: ASTNodeType = node_type

44 self._value: str = value

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

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

47

48 def attach_child(self, child: 'ASTNode') -> None:

49 """Add a child node to this ASTNode."""

50 child.parent = self

51 self._children.append(child)

52

53 def detach_child(self, child: 'ASTNode') -> None:

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

55 if child not in self.children:

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

57

58 self._children.remove(child)

59 child.parent = None

60

61 @property

62 def node_type(self) -> ASTNodeType:

63 """The type of this node."""

64 return self._node_type

65

66 @property

67 def value(self) -> str:

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

69 return self._value

70

71 @property

72 def parent(self) -> Optional['ASTNode']:

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

74 return self._parent

75

76 @parent.setter

77 def parent(self, new_parent: Optional['ASTNode']) -> None:

78 self._parent = new_parent

79

80 @property

81 def children(self) -> List['ASTNode']:

82 """The node's children (returns a copy to prevent modification)."""

83 return self._children.copy()