Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: utils/cleanast.js

Issue 29350140: Issue 4353 - Remove non standard for each syntax (Closed)
Left Patch Set: Created Aug. 24, 2016, 11:08 a.m.
Right Patch Set: Removed unused code Created Aug. 24, 2016, 2:40 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « utils/astml.js ('k') | utils/comments.js » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /**
2 * A brief description of some nodes.
3 *
4 * Scope block information:
5 * variables (Variable[]): a list of variables declared in the block
6 * functions (Function[]): a list of functions declared in the block
7 * constants (Variable[]): a list of constants declared in the block
8 * classes (Class[]): a list of classes declared in the block
9 * objects (Class[]): a list of objects declared in the block
10 * code (Statement[]): a list of statements in the block
11 */
12
13 /**
14 * Takes the node rooted at the AST and decomposes it into readable sections.
15 */
16 function clean_ast(ast) {
17 assert(ast.type == TOK_LC);
18 let info = {
19 variables: [],
20 constants: [],
21 objects: [],
22 classes: [],
23 functions: [],
24 code: []
25 };
26
27 for (let statement of ast.kids) {
28 if (statement.op == JSOP_DEFVAR) {
29 let ret = make_variables(statement);
30 info.variables = info.variables.concat(ret.vars);
31 info.objects = info.objects.concat(ret.objs);
32 } else if (statement.op == JSOP_DEFCONST) {
33 let ret = make_variables(statement);
34 info.constants = info.constants.concat(ret.vars);
35 info.objects = info.objects.concat(ret.objs);
36 } else if (statement.type == TOK_FUNCTION) {
37 info.functions.push(make_function(statement));
38 } else if (prototype_assign(statement)) {
39 let obj = make_class(statement);
40 merge_class(info, obj);
41 } else {
42 info.code.push(statement);
43 }
44 }
45 return info;
46 }
47
48 /**
49 * Visits the AST using the given function as a parameter.
50 * The parameter will take in a single argument, the AST node.
51 */
52 function visit(root_ast, func, to_expand) {
53 function v_r(ast, func) {
54 if (ast == null)
55 return;
56 if (func(ast)) return;
57 for (let child of ast.kids)
58 v_r(child, func);
59 }
60
61 function sanitize(ast) {
62 if (ast == null)
63 return null;
64 if (ast.op == JSOP_NAME && ast.atom in to_expand) {
65 ast = sanitize(to_expand[ast.atom]);
66 ast.expanded = true;
67 }
68 let sanitized_ast = { kids: [] };
69 for (let key of ast) {
70 if (key == 'kids') {
71 for (let kid of ast.kids) {
72 sanitized_ast.kids.push(sanitize(kid));
73 }
74 } else {
75 sanitized_ast[key] = ast[key];
76 }
77 }
78 return sanitized_ast;
79 }
80
81 if (to_expand)
82 v_r(sanitize(root_ast), func);
83 else
84 v_r(root_ast, func);
85 }
86
87 function prototype_assign(statement) {
88 if (statement.type != TOK_SEMI || !statement.kids[0])
89 return false;
90 statement = statement.kids[0];
91 if (statement.type != TOK_ASSIGN || !statement.kids[0])
92 return false;
93
94 statement = statement.kids[0];
95 // Statement is either prototype or a property of prototype
96 if (statement.op != JSOP_SETPROP)
97 return false;
98 if (statement.atom == "prototype")
99 return true;
100 if (statement.kids[0] && statement.kids[0] == "prototype")
101 return true;
102
103 // Or not!
104 return false;
105 }
106
107 function make_class(class_root) {
108 let clazz = {};
109
110 class_root = class_root.kids[0];
111 let lhs = class_root.kids[0], rhs = class_root.kids[1];
112 if (lhs.atom == "prototype") {
113 clazz.init = rhs;
114 clazz = make_object(clazz);
115 } else {
116 clazz.functions = {};
117 clazz.functions[lhs.atom] = make_function(rhs);
118 lhs = lhs.kids[0];
119 }
120 clazz.name = lhs.kids[0].atom;
121 return clazz;
122 }
123
124 function merge_class(info_list, obj) {
125 let name = obj.name;
126 for (let i = 0; i < info_list.functions.length; i++) {
127 if (info_list.functions[i].name == name) {
128 obj.constructor = info_list.functions[i];
129 // remove the constructor from the list of global functions
130 info_list.functions.splice(i, 1);
131 break;
132 }
133 }
134 if (obj.constructor)
135 obj.loc = obj.constructor.loc;
136 let oldObj = null;
137 for (let i = 0; i < info_list.classes.length; i++) {
138 if (info_list.classes[i].name == name) {
139 oldObj = info_list.classes[i];
140 break;
141 }
142 }
143 if (oldObj) {
144 for (let prop in obj) {
145 if (!(prop in oldObj)) {
146 oldObj[prop] = obj[prop];
147 } else if (typeof obj[prop] == "object") {
148 for (let item in obj[prop])
149 oldObj[prop][item] = obj[prop][item];
150 }
151 }
152 } else {
153 info_list.classes = info_list.classes.concat(obj);
154 }
155 }
156 function make_variables(var_root) {
157 assert(var_root.op == JSOP_DEFVAR || var_root.op == JSOP_DEFCONST);
158 let variables = [];
159 let objects = [];
160 for (let name of var_root.kids) {
161 let v = { name: name.atom };
162 v.init = (name.kids.length > 0 ? name.kids[0] : null);
163 v.loc = get_location(var_root);
164 if (v.init && v.init.op == JSOP_NEWINIT && v.init.kids[0] &&
165 v.init.kids[0].type == TOK_COLON)
166 objects.push(make_object(v));
167 else
168 variables.push(v);
169 }
170 return { vars: variables, objs: objects };
171 }
172
173 function make_object(stub) {
174 stub.variables = {};
175 stub.functions = {};
176 stub.getters = {};
177 stub.setters = {};
178 let ast = stub.init;
179 let proto = stub.init.op == JSOP_GETPROP && stub.init.atom == 'prototype';
180 delete stub['init'];
181 if (proto) {
182 stub.inherits = [ast.kids[0].atom];
183 return stub;
184 }
185 for (let init of ast.kids) {
186 if (init.type != TOK_COLON) {
187 dump_ast(init);
188 }
189 assert(init.type == TOK_COLON);
190 if (init.kids[0].type == TOK_NAME) {
191 let name = init.kids[0].atom;
192 let value = init.kids[1];
193 if (init.op == JSOP_GETTER)
194 stub.getters[name] = make_function(value);
195 else if (init.op == JSOP_SETTER)
196 stub.setters[name] = make_function(value);
197 else if (value.type == TOK_FUNCTION)
198 stub.functions[name] = make_function(value);
199 else if (name == '__proto__') {
200 let supername;
201 if (value.op == JSOP_NEW)
202 supername = value.kids[0].atom;
203 else if (value.op == JSOP_GETPROP && value.atom == 'prototype')
204 supername = value.kids[0].atom;
205 else
206 assert(false);
207 if ('inherits' in stub)
208 stub.inherits.push(supoername);
209 else
210 stub.inherits = [supername];
211 }
212 else
213 stub.variables[name] = { loc: get_location(value), init: value };
214 } else {
215 dump_ast(init);
216 }
217 }
218 return stub;
219 }
220
221 function make_function(func_root) {
222 assert(func_root.type == TOK_FUNCTION);
223 let stmts = func_root.kids[0];
224 if (stmts.type == TOK_UPVARS)
225 stmts = stmts.kids[0];
226 if (stmts.type == TOK_ARGSBODY)
227 stmts = stmts.kids[stmts.kids.length - 1];
228 if (stmts.type == TOK_RETURN) {
229 // This is a lambda function. For simplicity's sake, I'm going to turn this
230 // into a regular function by wrapping with TOK_LC (consumers of functions
231 // will find this easier to use)
232 let newtop = { fakeNode: true, line: stmts.line, col: stmts.col,
233 type: TOK_LC, op: JSOP_NOP, kids: [stmts]};
234 stmts = newtop;
235 }
236 assert(stmts.type == TOK_LC);
237 return { name: func_root.name, body: stmts, loc: get_location(func_root)};
238 }
239
240 function assert(cmd) {
241 if (!cmd) {
242 throw new Error("Assertion failed");
243 }
244 }
245
246 function get_location(ast_node) {
247 return { line: ast_node.line, column: ast_node.column };
248 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld