UNPKG

23 kBJavaScriptView Raw
1/***********************************************************************
2
3 A JavaScript tokenizer / parser / beautifier / compressor.
4 https://github.com/mishoo/UglifyJS2
5
6 -------------------------------- (C) ---------------------------------
7
8 Author: Mihai Bazon
9 <mihai.bazon@gmail.com>
10 http://mihai.bazon.net/blog
11
12 Distributed under the BSD license:
13
14 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
15
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions
18 are met:
19
20 * Redistributions of source code must retain the above
21 copyright notice, this list of conditions and the following
22 disclaimer.
23
24 * Redistributions in binary form must reproduce the above
25 copyright notice, this list of conditions and the following
26 disclaimer in the documentation and/or other materials
27 provided with the distribution.
28
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
30 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
33 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
34 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
36 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
38 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
39 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 SUCH DAMAGE.
41
42 ***********************************************************************/
43
44"use strict";
45
46(function() {
47 function normalize_directives(body) {
48 var in_directive = true;
49 for (var i = 0; i < body.length; i++) {
50 if (in_directive && body[i] instanceof AST_Statement && body[i].body instanceof AST_String) {
51 body[i] = new AST_Directive({
52 start: body[i].start,
53 end: body[i].end,
54 value: body[i].body.value
55 });
56 } else if (in_directive && !(body[i] instanceof AST_Statement && body[i].body instanceof AST_String)) {
57 in_directive = false;
58 }
59 }
60 return body;
61 }
62
63 var MOZ_TO_ME = {
64 Program: function(M) {
65 return new AST_Toplevel({
66 start: my_start_token(M),
67 end: my_end_token(M),
68 body: normalize_directives(M.body.map(from_moz))
69 });
70 },
71 FunctionDeclaration: function(M) {
72 return new AST_Defun({
73 start: my_start_token(M),
74 end: my_end_token(M),
75 name: from_moz(M.id),
76 argnames: M.params.map(from_moz),
77 body: normalize_directives(from_moz(M.body).body)
78 });
79 },
80 FunctionExpression: function(M) {
81 return new AST_Function({
82 start: my_start_token(M),
83 end: my_end_token(M),
84 name: from_moz(M.id),
85 argnames: M.params.map(from_moz),
86 body: normalize_directives(from_moz(M.body).body)
87 });
88 },
89 ExpressionStatement: function(M) {
90 return new AST_SimpleStatement({
91 start: my_start_token(M),
92 end: my_end_token(M),
93 body: from_moz(M.expression)
94 });
95 },
96 TryStatement: function(M) {
97 var handlers = M.handlers || [M.handler];
98 if (handlers.length > 1 || M.guardedHandlers && M.guardedHandlers.length) {
99 throw new Error("Multiple catch clauses are not supported.");
100 }
101 return new AST_Try({
102 start : my_start_token(M),
103 end : my_end_token(M),
104 body : from_moz(M.block).body,
105 bcatch : from_moz(handlers[0]),
106 bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null
107 });
108 },
109 Property: function(M) {
110 var key = M.key;
111 var args = {
112 start : my_start_token(key),
113 end : my_end_token(M.value),
114 key : key.type == "Identifier" ? key.name : key.value,
115 value : from_moz(M.value)
116 };
117 if (M.kind == "init") return new AST_ObjectKeyVal(args);
118 args.key = new AST_SymbolAccessor({
119 name: args.key
120 });
121 args.value = new AST_Accessor(args.value);
122 if (M.kind == "get") return new AST_ObjectGetter(args);
123 if (M.kind == "set") return new AST_ObjectSetter(args);
124 },
125 ArrayExpression: function(M) {
126 return new AST_Array({
127 start : my_start_token(M),
128 end : my_end_token(M),
129 elements : M.elements.map(function(elem) {
130 return elem === null ? new AST_Hole() : from_moz(elem);
131 })
132 });
133 },
134 ObjectExpression: function(M) {
135 return new AST_Object({
136 start : my_start_token(M),
137 end : my_end_token(M),
138 properties : M.properties.map(function(prop) {
139 prop.type = "Property";
140 return from_moz(prop)
141 })
142 });
143 },
144 SequenceExpression: function(M) {
145 return new AST_Sequence({
146 start : my_start_token(M),
147 end : my_end_token(M),
148 expressions: M.expressions.map(from_moz)
149 });
150 },
151 MemberExpression: function(M) {
152 return new (M.computed ? AST_Sub : AST_Dot)({
153 start : my_start_token(M),
154 end : my_end_token(M),
155 property : M.computed ? from_moz(M.property) : M.property.name,
156 expression : from_moz(M.object)
157 });
158 },
159 SwitchCase: function(M) {
160 return new (M.test ? AST_Case : AST_Default)({
161 start : my_start_token(M),
162 end : my_end_token(M),
163 expression : from_moz(M.test),
164 body : M.consequent.map(from_moz)
165 });
166 },
167 VariableDeclaration: function(M) {
168 return new AST_Var({
169 start : my_start_token(M),
170 end : my_end_token(M),
171 definitions : M.declarations.map(from_moz)
172 });
173 },
174 Literal: function(M) {
175 var val = M.value, args = {
176 start : my_start_token(M),
177 end : my_end_token(M)
178 };
179 if (val === null) return new AST_Null(args);
180 var rx = M.regex;
181 if (rx && rx.pattern) {
182 // RegExpLiteral as per ESTree AST spec
183 args.value = new RegExp(rx.pattern, rx.flags);
184 args.value.raw_source = rx.pattern;
185 return new AST_RegExp(args);
186 } else if (rx) {
187 // support legacy RegExp
188 args.value = M.regex && M.raw ? M.raw : val;
189 return new AST_RegExp(args);
190 }
191 switch (typeof val) {
192 case "string":
193 args.value = val;
194 return new AST_String(args);
195 case "number":
196 args.value = val;
197 return new AST_Number(args);
198 case "boolean":
199 return new (val ? AST_True : AST_False)(args);
200 }
201 },
202 Identifier: function(M) {
203 var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
204 return new ( p.type == "LabeledStatement" ? AST_Label
205 : p.type == "VariableDeclarator" && p.id === M ? AST_SymbolVar
206 : p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg)
207 : p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg)
208 : p.type == "CatchClause" ? AST_SymbolCatch
209 : p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef
210 : AST_SymbolRef)({
211 start : my_start_token(M),
212 end : my_end_token(M),
213 name : M.name
214 });
215 }
216 };
217
218 MOZ_TO_ME.UpdateExpression =
219 MOZ_TO_ME.UnaryExpression = function To_Moz_Unary(M) {
220 var prefix = "prefix" in M ? M.prefix
221 : M.type == "UnaryExpression" ? true : false;
222 return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({
223 start : my_start_token(M),
224 end : my_end_token(M),
225 operator : M.operator,
226 expression : from_moz(M.argument)
227 });
228 };
229
230 map("EmptyStatement", AST_EmptyStatement);
231 map("BlockStatement", AST_BlockStatement, "body@body");
232 map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
233 map("LabeledStatement", AST_LabeledStatement, "label>label, body>body");
234 map("BreakStatement", AST_Break, "label>label");
235 map("ContinueStatement", AST_Continue, "label>label");
236 map("WithStatement", AST_With, "object>expression, body>body");
237 map("SwitchStatement", AST_Switch, "discriminant>expression, cases@body");
238 map("ReturnStatement", AST_Return, "argument>value");
239 map("ThrowStatement", AST_Throw, "argument>value");
240 map("WhileStatement", AST_While, "test>condition, body>body");
241 map("DoWhileStatement", AST_Do, "test>condition, body>body");
242 map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body");
243 map("ForInStatement", AST_ForIn, "left>init, right>object, body>body");
244 map("DebuggerStatement", AST_Debugger);
245 map("VariableDeclarator", AST_VarDef, "id>name, init>value");
246 map("CatchClause", AST_Catch, "param>argname, body%body");
247
248 map("ThisExpression", AST_This);
249 map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right");
250 map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right");
251 map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
252 map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative");
253 map("NewExpression", AST_New, "callee>expression, arguments@args");
254 map("CallExpression", AST_Call, "callee>expression, arguments@args");
255
256 def_to_moz(AST_Toplevel, function To_Moz_Program(M) {
257 return to_moz_scope("Program", M);
258 });
259
260 def_to_moz(AST_Defun, function To_Moz_FunctionDeclaration(M) {
261 return {
262 type: "FunctionDeclaration",
263 id: to_moz(M.name),
264 params: M.argnames.map(to_moz),
265 body: to_moz_scope("BlockStatement", M)
266 }
267 });
268
269 def_to_moz(AST_Function, function To_Moz_FunctionExpression(M) {
270 return {
271 type: "FunctionExpression",
272 id: to_moz(M.name),
273 params: M.argnames.map(to_moz),
274 body: to_moz_scope("BlockStatement", M)
275 }
276 });
277
278 def_to_moz(AST_Directive, function To_Moz_Directive(M) {
279 return {
280 type: "ExpressionStatement",
281 expression: {
282 type: "Literal",
283 value: M.value
284 }
285 };
286 });
287
288 def_to_moz(AST_SimpleStatement, function To_Moz_ExpressionStatement(M) {
289 return {
290 type: "ExpressionStatement",
291 expression: to_moz(M.body)
292 };
293 });
294
295 def_to_moz(AST_SwitchBranch, function To_Moz_SwitchCase(M) {
296 return {
297 type: "SwitchCase",
298 test: to_moz(M.expression),
299 consequent: M.body.map(to_moz)
300 };
301 });
302
303 def_to_moz(AST_Try, function To_Moz_TryStatement(M) {
304 return {
305 type: "TryStatement",
306 block: to_moz_block(M),
307 handler: to_moz(M.bcatch),
308 guardedHandlers: [],
309 finalizer: to_moz(M.bfinally)
310 };
311 });
312
313 def_to_moz(AST_Catch, function To_Moz_CatchClause(M) {
314 return {
315 type: "CatchClause",
316 param: to_moz(M.argname),
317 guard: null,
318 body: to_moz_block(M)
319 };
320 });
321
322 def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) {
323 return {
324 type: "VariableDeclaration",
325 kind: "var",
326 declarations: M.definitions.map(to_moz)
327 };
328 });
329
330 def_to_moz(AST_Sequence, function To_Moz_SequenceExpression(M) {
331 return {
332 type: "SequenceExpression",
333 expressions: M.expressions.map(to_moz)
334 };
335 });
336
337 def_to_moz(AST_PropAccess, function To_Moz_MemberExpression(M) {
338 var isComputed = M instanceof AST_Sub;
339 return {
340 type: "MemberExpression",
341 object: to_moz(M.expression),
342 computed: isComputed,
343 property: isComputed ? to_moz(M.property) : {type: "Identifier", name: M.property}
344 };
345 });
346
347 def_to_moz(AST_Unary, function To_Moz_Unary(M) {
348 return {
349 type: M.operator == "++" || M.operator == "--" ? "UpdateExpression" : "UnaryExpression",
350 operator: M.operator,
351 prefix: M instanceof AST_UnaryPrefix,
352 argument: to_moz(M.expression)
353 };
354 });
355
356 def_to_moz(AST_Binary, function To_Moz_BinaryExpression(M) {
357 return {
358 type: M.operator == "&&" || M.operator == "||" ? "LogicalExpression" : "BinaryExpression",
359 left: to_moz(M.left),
360 operator: M.operator,
361 right: to_moz(M.right)
362 };
363 });
364
365 def_to_moz(AST_Array, function To_Moz_ArrayExpression(M) {
366 return {
367 type: "ArrayExpression",
368 elements: M.elements.map(to_moz)
369 };
370 });
371
372 def_to_moz(AST_Object, function To_Moz_ObjectExpression(M) {
373 return {
374 type: "ObjectExpression",
375 properties: M.properties.map(to_moz)
376 };
377 });
378
379 def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
380 var key = {
381 type: "Literal",
382 value: M.key instanceof AST_SymbolAccessor ? M.key.name : M.key
383 };
384 var kind;
385 if (M instanceof AST_ObjectKeyVal) {
386 kind = "init";
387 } else
388 if (M instanceof AST_ObjectGetter) {
389 kind = "get";
390 } else
391 if (M instanceof AST_ObjectSetter) {
392 kind = "set";
393 }
394 return {
395 type: "Property",
396 kind: kind,
397 key: key,
398 value: to_moz(M.value)
399 };
400 });
401
402 def_to_moz(AST_Symbol, function To_Moz_Identifier(M) {
403 var def = M.definition();
404 return {
405 type: "Identifier",
406 name: def && def.mangled_name || M.name
407 };
408 });
409
410 def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) {
411 var flags = M.value.toString().match(/[gimuy]*$/)[0];
412 var value = "/" + M.value.raw_source + "/" + flags;
413 return {
414 type: "Literal",
415 value: value,
416 raw: value,
417 regex: {
418 pattern: M.value.raw_source,
419 flags: flags
420 }
421 };
422 });
423
424 def_to_moz(AST_Constant, function To_Moz_Literal(M) {
425 var value = M.value;
426 if (typeof value === 'number' && (value < 0 || (value === 0 && 1 / value < 0))) {
427 return {
428 type: "UnaryExpression",
429 operator: "-",
430 prefix: true,
431 argument: {
432 type: "Literal",
433 value: -value,
434 raw: M.start.raw
435 }
436 };
437 }
438 return {
439 type: "Literal",
440 value: value,
441 raw: M.start.raw
442 };
443 });
444
445 def_to_moz(AST_Atom, function To_Moz_Atom(M) {
446 return {
447 type: "Identifier",
448 name: String(M.value)
449 };
450 });
451
452 AST_Boolean.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast);
453 AST_Null.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast);
454 AST_Hole.DEFMETHOD("to_mozilla_ast", function To_Moz_ArrayHole() { return null });
455
456 AST_Block.DEFMETHOD("to_mozilla_ast", AST_BlockStatement.prototype.to_mozilla_ast);
457 AST_Lambda.DEFMETHOD("to_mozilla_ast", AST_Function.prototype.to_mozilla_ast);
458
459 /* -----[ tools ]----- */
460
461 function raw_token(moznode) {
462 if (moznode.type == "Literal") {
463 return moznode.raw != null ? moznode.raw : moznode.value + "";
464 }
465 }
466
467 function my_start_token(moznode) {
468 var loc = moznode.loc, start = loc && loc.start;
469 var range = moznode.range;
470 return new AST_Token({
471 file : loc && loc.source,
472 line : start && start.line,
473 col : start && start.column,
474 pos : range ? range[0] : moznode.start,
475 endline : start && start.line,
476 endcol : start && start.column,
477 endpos : range ? range[0] : moznode.start,
478 raw : raw_token(moznode),
479 });
480 }
481
482 function my_end_token(moznode) {
483 var loc = moznode.loc, end = loc && loc.end;
484 var range = moznode.range;
485 return new AST_Token({
486 file : loc && loc.source,
487 line : end && end.line,
488 col : end && end.column,
489 pos : range ? range[1] : moznode.end,
490 endline : end && end.line,
491 endcol : end && end.column,
492 endpos : range ? range[1] : moznode.end,
493 raw : raw_token(moznode),
494 });
495 }
496
497 function map(moztype, mytype, propmap) {
498 var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
499 moz_to_me += "return new U2." + mytype.name + "({\n" +
500 "start: my_start_token(M),\n" +
501 "end: my_end_token(M)";
502
503 var me_to_moz = "function To_Moz_" + moztype + "(M){\n";
504 me_to_moz += "return {\n" +
505 "type: " + JSON.stringify(moztype);
506
507 if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop) {
508 var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop);
509 if (!m) throw new Error("Can't understand property map: " + prop);
510 var moz = m[1], how = m[2], my = m[3];
511 moz_to_me += ",\n" + my + ": ";
512 me_to_moz += ",\n" + moz + ": ";
513 switch (how) {
514 case "@":
515 moz_to_me += "M." + moz + ".map(from_moz)";
516 me_to_moz += "M." + my + ".map(to_moz)";
517 break;
518 case ">":
519 moz_to_me += "from_moz(M." + moz + ")";
520 me_to_moz += "to_moz(M." + my + ")";
521 break;
522 case "=":
523 moz_to_me += "M." + moz;
524 me_to_moz += "M." + my;
525 break;
526 case "%":
527 moz_to_me += "from_moz(M." + moz + ").body";
528 me_to_moz += "to_moz_block(M)";
529 break;
530 default:
531 throw new Error("Can't understand operator in propmap: " + prop);
532 }
533 });
534
535 moz_to_me += "\n})\n}";
536 me_to_moz += "\n}\n}";
537
538 //moz_to_me = parse(moz_to_me).print_to_string({ beautify: true });
539 //me_to_moz = parse(me_to_moz).print_to_string({ beautify: true });
540 //console.log(moz_to_me);
541
542 moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
543 exports, my_start_token, my_end_token, from_moz
544 );
545 me_to_moz = new Function("to_moz", "to_moz_block", "to_moz_scope", "return(" + me_to_moz + ")")(
546 to_moz, to_moz_block, to_moz_scope
547 );
548 MOZ_TO_ME[moztype] = moz_to_me;
549 def_to_moz(mytype, me_to_moz);
550 }
551
552 var FROM_MOZ_STACK = null;
553
554 function from_moz(node) {
555 FROM_MOZ_STACK.push(node);
556 var ret = node != null ? MOZ_TO_ME[node.type](node) : null;
557 FROM_MOZ_STACK.pop();
558 return ret;
559 }
560
561 AST_Node.from_mozilla_ast = function(node) {
562 var save_stack = FROM_MOZ_STACK;
563 FROM_MOZ_STACK = [];
564 var ast = from_moz(node);
565 FROM_MOZ_STACK = save_stack;
566 ast.walk(new TreeWalker(function(node) {
567 if (node instanceof AST_LabelRef) {
568 for (var level = 0, parent; parent = this.parent(level); level++) {
569 if (parent instanceof AST_Scope) break;
570 if (parent instanceof AST_LabeledStatement && parent.label.name == node.name) {
571 node.thedef = parent.label;
572 break;
573 }
574 }
575 if (!node.thedef) {
576 var s = node.start;
577 js_error("Undefined label " + node.name, s.file, s.line, s.col, s.pos);
578 }
579 }
580 }));
581 return ast;
582 };
583
584 function set_moz_loc(mynode, moznode, myparent) {
585 var start = mynode.start;
586 var end = mynode.end;
587 if (start.pos != null && end.endpos != null) {
588 moznode.range = [start.pos, end.endpos];
589 }
590 if (start.line) {
591 moznode.loc = {
592 start: {line: start.line, column: start.col},
593 end: end.endline ? {line: end.endline, column: end.endcol} : null
594 };
595 if (start.file) {
596 moznode.loc.source = start.file;
597 }
598 }
599 return moznode;
600 }
601
602 function def_to_moz(mytype, handler) {
603 mytype.DEFMETHOD("to_mozilla_ast", function() {
604 return set_moz_loc(this, handler(this));
605 });
606 }
607
608 function to_moz(node) {
609 return node != null ? node.to_mozilla_ast() : null;
610 }
611
612 function to_moz_block(node) {
613 return {
614 type: "BlockStatement",
615 body: node.body.map(to_moz)
616 };
617 }
618
619 function to_moz_scope(type, node) {
620 var body = node.body.map(to_moz);
621 if (node.body[0] instanceof AST_SimpleStatement && node.body[0].body instanceof AST_String) {
622 body.unshift(to_moz(new AST_EmptyStatement(node.body[0])));
623 }
624 return {
625 type: type,
626 body: body
627 };
628 }
629})();