ThirdParty/Jasy/jasy/js/parse/Node.py

branch
Py2 comp.
changeset 2847
1843ef6e2656
parent 2779
4d433896b6d6
child 3145
a9de05d4a22f
equal deleted inserted replaced
2846:b852fe4d153a 2847:1843ef6e2656
1 #
2 # Jasy - Web Tooling Framework
3 # Copyright 2010-2012 Zynga Inc.
4 #
5
6 #
7 # License: MPL 1.1/GPL 2.0/LGPL 2.1
8 # Authors:
9 # - Brendan Eich <brendan@mozilla.org> (Original JavaScript) (2004)
10 # - Sebastian Werner <info@sebastian-werner.net> (Refactoring Python) (2010)
11 #
12
13 from __future__ import unicode_literals # __IGNORE_WARNING__
14
15 import copy
16
17 class Node(list):
18
19 __slots__ = [
20 # core data
21 "line", "type", "tokenizer", "start", "end", "rel", "parent",
22
23 # dynamic added data by other modules
24 "comments", "scope",
25
26 # node type specific
27 "value", "expression", "body", "functionForm", "parenthesized", "fileId",
28 "params", "name", "readOnly", "initializer", "condition", "isLoop", "isEach",
29 "object", "assignOp", "iterator", "thenPart", "exception", "elsePart", "setup",
30 "postfix", "update", "tryBlock", "block", "defaultIndex", "discriminant", "label",
31 "statements", "finallyBlock", "statement", "variables", "names", "guard", "for",
32 "tail", "expressionClosure"
33 ]
34
35 def __init__(self, tokenizer=None, type=None, args=[]):
36 list.__init__(self)
37
38 self.start = 0
39 self.end = 0
40 self.line = None
41
42 if tokenizer:
43 token = getattr(tokenizer, "token", None)
44 if token:
45 # We may define a custom type but use the same positioning as another
46 # token, e.g. transform curlys in block nodes, etc.
47 self.type = type if type else getattr(token, "type", None)
48 self.line = token.line
49
50 # Start & end are file positions for error handling.
51 self.start = token.start
52 self.end = token.end
53
54 else:
55 self.type = type
56 self.line = tokenizer.line
57 self.start = None
58 self.end = None
59
60 self.tokenizer = tokenizer
61
62 elif type:
63 self.type = type
64
65 for arg in args:
66 self.append(arg)
67
68 def getUnrelatedChildren(self):
69 """Collects all unrelated children"""
70
71 collection = []
72 for child in self:
73 if not hasattr(child, "rel"):
74 collection.append(child)
75
76 return collection
77
78 def getChildrenLength(self, filter=True):
79 """Number of (per default unrelated) children"""
80
81 count = 0
82 for child in self:
83 if not filter or not hasattr(child, "rel"):
84 count += 1
85 return count
86
87 def remove(self, kid):
88 """Removes the given kid"""
89
90 if not kid in self:
91 raise Exception("Given node is no child!")
92
93 if hasattr(kid, "rel"):
94 delattr(self, kid.rel)
95 del kid.rel
96 del kid.parent
97
98 list.remove(self, kid)
99
100 def insert(self, index, kid):
101 """Inserts the given kid at the given index"""
102
103 if index is None:
104 return self.append(kid)
105
106 if hasattr(kid, "parent"):
107 kid.parent.remove(kid)
108
109 kid.parent = self
110
111 return list.insert(self, index, kid)
112
113 def append(self, kid, rel=None):
114 """Appends the given kid with an optional relation hint"""
115
116 # kid can be null e.g. [1, , 2].
117 if kid:
118 if hasattr(kid, "parent"):
119 kid.parent.remove(kid)
120
121 # Debug
122 if not isinstance(kid, Node):
123 raise Exception("Invalid kid: %s" % kid)
124
125 if hasattr(kid, "tokenizer"):
126 if hasattr(kid, "start"):
127 if not hasattr(self, "start") or \
128 self.start == None or \
129 kid.start < self.start:
130 self.start = kid.start
131
132 if hasattr(kid, "end"):
133 if not hasattr(self, "end") or \
134 self.end == None or \
135 self.end < kid.end:
136 self.end = kid.end
137
138 kid.parent = self
139
140 # alias for function
141 if rel != None:
142 setattr(self, rel, kid)
143 setattr(kid, "rel", rel)
144
145 # Block None kids when they should be related
146 if not kid and rel:
147 return
148
149 return list.append(self, kid)
150
151 def replace(self, kid, repl):
152 """Replaces the given kid with a replacement kid"""
153
154 if repl in self:
155 self.remove(repl)
156
157 self[self.index(kid)] = repl
158
159 if hasattr(kid, "rel"):
160 repl.rel = kid.rel
161 setattr(self, kid.rel, repl)
162
163 # cleanup old kid
164 delattr(kid, "rel")
165
166 elif hasattr(repl, "rel"):
167 # delete old relation on new child
168 delattr(repl, "rel")
169
170 delattr(kid, "parent")
171 repl.parent = self
172
173 return kid
174
175 def __deepcopy__(self, memo):
176 """Used by deepcopy function to clone Node instances"""
177
178 # Create copy
179 if hasattr(self, "tokenizer"):
180 result = Node(tokenizer=self.tokenizer)
181 else:
182 result = Node(type=self.type)
183
184 # Copy children
185 for child in self:
186 if child is None:
187 list.append(result, None)
188 else:
189 # Using simple list appends for better performance
190 childCopy = copy.deepcopy(child, memo)
191 childCopy.parent = result
192 list.append(result, childCopy)
193
194 # Sync attributes
195 # Note: "parent" attribute is handled by append() already
196 for name in self.__slots__:
197 if hasattr(self, name) and not name in ("parent", "tokenizer"):
198 value = getattr(self, name)
199 if value is None:
200 pass
201 elif type(value) in (bool, int, float, str):
202 setattr(result, name, value)
203 elif type(value) in (list, set, dict, Node):
204 setattr(result, name, copy.deepcopy(value, memo))
205 # Scope can be assigned (will be re-created when needed for the
206 # copied node)
207 elif name == "scope":
208 result.scope = self.scope
209
210 return result
211
212 def __eq__(self, other):
213 return self is other
214
215 def __bool__(self):
216 return True

eric ide

mercurial