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

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

eric ide

mercurial