1class NodeVisitor(object):
2    def visit(self, node):
3        # This is ugly as hell, but we don't have multimethods and
4        # they aren't trivial to fake without access to the class
5        # object from the class body
6        func = getattr(self, "visit_%s" % (node.__class__.__name__))
7        return func(node)
8
9
10class Node(object):
11    def __init__(self, data=None):
12        self.data = data
13        self.parent = None
14        self.children = []
15
16    def append(self, other):
17        other.parent = self
18        self.children.append(other)
19
20    def remove(self):
21        self.parent.children.remove(self)
22
23    def __repr__(self):
24        return "<%s %s>" % (self.__class__.__name__, self.data)
25
26    def __str__(self):
27        rv = [repr(self)]
28        for item in self.children:
29            rv.extend("  %s" % line for line in str(item).split("\n"))
30        return "\n".join(rv)
31
32    def __eq__(self, other):
33        if not (self.__class__ == other.__class__ and
34                self.data == other.data and
35                len(self.children) == len(other.children)):
36            return False
37        for child, other_child in zip(self.children, other.children):
38            if not child == other_child:
39                return False
40        return True
41
42    def copy(self):
43        new = self.__class__(self.data)
44        for item in self.children:
45            new.append(item.copy())
46        return new
47
48
49class DataNode(Node):
50    def append(self, other):
51        # Append that retains the invariant that child data nodes
52        # come after child nodes of other types
53        other.parent = self
54        if isinstance(other, DataNode):
55            self.children.append(other)
56        else:
57            index = len(self.children)
58            while index > 0 and isinstance(self.children[index - 1], DataNode):
59                index -= 1
60            for i in xrange(index):
61                assert other.data != self.children[i].data
62            self.children.insert(index, other)
63
64
65class KeyValueNode(Node):
66    def append(self, other):
67        # Append that retains the invariant that conditional nodes
68        # come before unconditional nodes
69        other.parent = self
70        if isinstance(other, ValueNode):
71            if self.children:
72                assert not isinstance(self.children[-1], ValueNode)
73            self.children.append(other)
74        else:
75            if self.children and isinstance(self.children[-1], ValueNode):
76                self.children.insert(len(self.children) - 1, other)
77            else:
78                self.children.append(other)
79
80
81class ListNode(Node):
82    def append(self, other):
83        other.parent = self
84        self.children.append(other)
85
86
87class ValueNode(Node):
88    def append(self, other):
89        raise TypeError
90
91
92class AtomNode(ValueNode):
93    pass
94
95
96class ConditionalNode(Node):
97    pass
98
99
100class UnaryExpressionNode(Node):
101    def __init__(self, operator, operand):
102        Node.__init__(self)
103        self.append(operator)
104        self.append(operand)
105
106    def append(self, other):
107        Node.append(self, other)
108        assert len(self.children) <= 2
109
110    def copy(self):
111        new = self.__class__(self.children[0].copy(),
112                             self.children[1].copy())
113        return new
114
115
116class BinaryExpressionNode(Node):
117    def __init__(self, operator, operand_0, operand_1):
118        Node.__init__(self)
119        self.append(operator)
120        self.append(operand_0)
121        self.append(operand_1)
122
123    def append(self, other):
124        Node.append(self, other)
125        assert len(self.children) <= 3
126
127    def copy(self):
128        new = self.__class__(self.children[0].copy(),
129                             self.children[1].copy(),
130                             self.children[2].copy())
131        return new
132
133
134class UnaryOperatorNode(Node):
135    def append(self, other):
136        raise TypeError
137
138
139class BinaryOperatorNode(Node):
140    def append(self, other):
141        raise TypeError
142
143
144class IndexNode(Node):
145    pass
146
147
148class VariableNode(Node):
149    pass
150
151
152class StringNode(Node):
153    pass
154
155
156class NumberNode(ValueNode):
157    pass
158