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