]> git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Lib/lib2to3/fixes/fix_metaclass.py
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Lib / lib2to3 / fixes / fix_metaclass.py
1 """Fixer for __metaclass__ = X -> (metaclass=X) methods.
2
3 The various forms of classef (inherits nothing, inherits once, inherints
4 many) don't parse the same in the CST so we look at ALL classes for
5 a __metaclass__ and if we find one normalize the inherits to all be
6 an arglist.
7
8 For one-liner classes ('class X: pass') there is no indent/dedent so
9 we normalize those into having a suite.
10
11 Moving the __metaclass__ into the classdef can also cause the class
12 body to be empty so there is some special casing for that as well.
13
14 This fixer also tries very hard to keep original indenting and spacing
15 in all those corner cases.
16
17 """
18 # Author: Jack Diederich
19
20 # Local imports
21 from .. import fixer_base
22 from ..pygram import token
23 from ..fixer_util import Name, syms, Node, Leaf
24
25
26 def has_metaclass(parent):
27 """ we have to check the cls_node without changing it.
28 There are two possiblities:
29 1) clsdef => suite => simple_stmt => expr_stmt => Leaf('__meta')
30 2) clsdef => simple_stmt => expr_stmt => Leaf('__meta')
31 """
32 for node in parent.children:
33 if node.type == syms.suite:
34 return has_metaclass(node)
35 elif node.type == syms.simple_stmt and node.children:
36 expr_node = node.children[0]
37 if expr_node.type == syms.expr_stmt and expr_node.children:
38 left_side = expr_node.children[0]
39 if isinstance(left_side, Leaf) and \
40 left_side.value == '__metaclass__':
41 return True
42 return False
43
44
45 def fixup_parse_tree(cls_node):
46 """ one-line classes don't get a suite in the parse tree so we add
47 one to normalize the tree
48 """
49 for node in cls_node.children:
50 if node.type == syms.suite:
51 # already in the preferred format, do nothing
52 return
53
54 # !%@#! oneliners have no suite node, we have to fake one up
55 for i, node in enumerate(cls_node.children):
56 if node.type == token.COLON:
57 break
58 else:
59 raise ValueError("No class suite and no ':'!")
60
61 # move everything into a suite node
62 suite = Node(syms.suite, [])
63 while cls_node.children[i+1:]:
64 move_node = cls_node.children[i+1]
65 suite.append_child(move_node.clone())
66 move_node.remove()
67 cls_node.append_child(suite)
68 node = suite
69
70
71 def fixup_simple_stmt(parent, i, stmt_node):
72 """ if there is a semi-colon all the parts count as part of the same
73 simple_stmt. We just want the __metaclass__ part so we move
74 everything efter the semi-colon into its own simple_stmt node
75 """
76 for semi_ind, node in enumerate(stmt_node.children):
77 if node.type == token.SEMI: # *sigh*
78 break
79 else:
80 return
81
82 node.remove() # kill the semicolon
83 new_expr = Node(syms.expr_stmt, [])
84 new_stmt = Node(syms.simple_stmt, [new_expr])
85 while stmt_node.children[semi_ind:]:
86 move_node = stmt_node.children[semi_ind]
87 new_expr.append_child(move_node.clone())
88 move_node.remove()
89 parent.insert_child(i, new_stmt)
90 new_leaf1 = new_stmt.children[0].children[0]
91 old_leaf1 = stmt_node.children[0].children[0]
92 new_leaf1.prefix = old_leaf1.prefix
93
94
95 def remove_trailing_newline(node):
96 if node.children and node.children[-1].type == token.NEWLINE:
97 node.children[-1].remove()
98
99
100 def find_metas(cls_node):
101 # find the suite node (Mmm, sweet nodes)
102 for node in cls_node.children:
103 if node.type == syms.suite:
104 break
105 else:
106 raise ValueError("No class suite!")
107
108 # look for simple_stmt[ expr_stmt[ Leaf('__metaclass__') ] ]
109 for i, simple_node in list(enumerate(node.children)):
110 if simple_node.type == syms.simple_stmt and simple_node.children:
111 expr_node = simple_node.children[0]
112 if expr_node.type == syms.expr_stmt and expr_node.children:
113 # Check if the expr_node is a simple assignment.
114 left_node = expr_node.children[0]
115 if isinstance(left_node, Leaf) and \
116 left_node.value == u'__metaclass__':
117 # We found a assignment to __metaclass__.
118 fixup_simple_stmt(node, i, simple_node)
119 remove_trailing_newline(simple_node)
120 yield (node, i, simple_node)
121
122
123 def fixup_indent(suite):
124 """ If an INDENT is followed by a thing with a prefix then nuke the prefix
125 Otherwise we get in trouble when removing __metaclass__ at suite start
126 """
127 kids = suite.children[::-1]
128 # find the first indent
129 while kids:
130 node = kids.pop()
131 if node.type == token.INDENT:
132 break
133
134 # find the first Leaf
135 while kids:
136 node = kids.pop()
137 if isinstance(node, Leaf) and node.type != token.DEDENT:
138 if node.prefix:
139 node.prefix = u''
140 return
141 else:
142 kids.extend(node.children[::-1])
143
144
145 class FixMetaclass(fixer_base.BaseFix):
146 BM_compatible = True
147
148 PATTERN = """
149 classdef<any*>
150 """
151
152 def transform(self, node, results):
153 if not has_metaclass(node):
154 return
155
156 fixup_parse_tree(node)
157
158 # find metaclasses, keep the last one
159 last_metaclass = None
160 for suite, i, stmt in find_metas(node):
161 last_metaclass = stmt
162 stmt.remove()
163
164 text_type = node.children[0].type # always Leaf(nnn, 'class')
165
166 # figure out what kind of classdef we have
167 if len(node.children) == 7:
168 # Node(classdef, ['class', 'name', '(', arglist, ')', ':', suite])
169 # 0 1 2 3 4 5 6
170 if node.children[3].type == syms.arglist:
171 arglist = node.children[3]
172 # Node(classdef, ['class', 'name', '(', 'Parent', ')', ':', suite])
173 else:
174 parent = node.children[3].clone()
175 arglist = Node(syms.arglist, [parent])
176 node.set_child(3, arglist)
177 elif len(node.children) == 6:
178 # Node(classdef, ['class', 'name', '(', ')', ':', suite])
179 # 0 1 2 3 4 5
180 arglist = Node(syms.arglist, [])
181 node.insert_child(3, arglist)
182 elif len(node.children) == 4:
183 # Node(classdef, ['class', 'name', ':', suite])
184 # 0 1 2 3
185 arglist = Node(syms.arglist, [])
186 node.insert_child(2, Leaf(token.RPAR, u')'))
187 node.insert_child(2, arglist)
188 node.insert_child(2, Leaf(token.LPAR, u'('))
189 else:
190 raise ValueError("Unexpected class definition")
191
192 # now stick the metaclass in the arglist
193 meta_txt = last_metaclass.children[0].children[0]
194 meta_txt.value = 'metaclass'
195 orig_meta_prefix = meta_txt.prefix
196
197 if arglist.children:
198 arglist.append_child(Leaf(token.COMMA, u','))
199 meta_txt.prefix = u' '
200 else:
201 meta_txt.prefix = u''
202
203 # compact the expression "metaclass = Meta" -> "metaclass=Meta"
204 expr_stmt = last_metaclass.children[0]
205 assert expr_stmt.type == syms.expr_stmt
206 expr_stmt.children[1].prefix = u''
207 expr_stmt.children[2].prefix = u''
208
209 arglist.append_child(last_metaclass)
210
211 fixup_indent(suite)
212
213 # check for empty suite
214 if not suite.children:
215 # one-liner that was just __metaclass_
216 suite.remove()
217 pass_leaf = Leaf(text_type, u'pass')
218 pass_leaf.prefix = orig_meta_prefix
219 node.append_child(pass_leaf)
220 node.append_child(Leaf(token.NEWLINE, u'\n'))
221
222 elif len(suite.children) > 1 and \
223 (suite.children[-2].type == token.INDENT and
224 suite.children[-1].type == token.DEDENT):
225 # there was only one line in the class body and it was __metaclass__
226 pass_leaf = Leaf(text_type, u'pass')
227 suite.insert_child(-1, pass_leaf)
228 suite.insert_child(-1, Leaf(token.NEWLINE, u'\n'))