Merge 13196026eb into 9e19e63551
This commit is contained in:
commit
364af7fa0f
|
|
@ -1047,7 +1047,7 @@ var result = UglifyJS.minify(ast, {
|
|||
|
||||
Transversal and transformation of the native AST can be performed through
|
||||
[`TreeWalker`](https://github.com/mishoo/UglifyJS2/blob/master/lib/ast.js) and
|
||||
[`TreeTransformer`](https://github.com/mishoo/UglifyJS2/blob/master/lib/transform.js)
|
||||
[`TreeTransformer`](https://github.com/mishoo/UglifyJS2/blob/master/lib/ast.js)
|
||||
respectively.
|
||||
|
||||
### ESTree / SpiderMonkey AST
|
||||
|
|
|
|||
34
bin/uglifyjs
34
bin/uglifyjs
|
|
@ -10,6 +10,7 @@ var info = require("../package.json");
|
|||
var path = require("path");
|
||||
var program = require("commander");
|
||||
var UglifyJS = require("../tools/node");
|
||||
var AST = UglifyJS.AST;
|
||||
|
||||
var skip_keys = [ "cname", "inlined", "parent_scope", "scope", "uses_eval", "uses_with" ];
|
||||
var files = {};
|
||||
|
|
@ -100,7 +101,7 @@ if (program.mangleProps) {
|
|||
if (typeof program.mangleProps != "object") program.mangleProps = {};
|
||||
if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = [];
|
||||
require("../tools/domprops").forEach(function(name) {
|
||||
UglifyJS._push_uniq(program.mangleProps.reserved, name);
|
||||
UglifyJS.push_uniq(program.mangleProps.reserved, name);
|
||||
});
|
||||
}
|
||||
if (typeof options.mangle != "object") options.mangle = {};
|
||||
|
|
@ -144,12 +145,23 @@ if (program.verbose) {
|
|||
} else if (program.warn) {
|
||||
options.warnings = true;
|
||||
}
|
||||
function getVarNameFromPath(filename) {
|
||||
var name = /((\w|-)+)(\.js)?$/.exec(filename)[1].replace("-", "_");
|
||||
return "__" + name + "_exports";
|
||||
}
|
||||
if (program.self) {
|
||||
if (program.args.length) {
|
||||
print_error("WARN: Ignoring input files since --self was passed");
|
||||
}
|
||||
if (!options.wrap) options.wrap = "UglifyJS";
|
||||
files["__require_emulation"] = "var __origExports = exports;" + getVarNameFromPath + "function require(filename){return require[getVarNameFromPath(filename)];}";
|
||||
simple_glob(UglifyJS.FILES).forEach(function(name) {
|
||||
var exportCode;
|
||||
if (/exports\.js$/.test(name))
|
||||
exportCode = "var exports = __origExports";
|
||||
else
|
||||
exportCode = "var exports = require['" + getVarNameFromPath(name) + "'] = {};";
|
||||
files["_" + name + "_exports"] = exportCode;
|
||||
files[convert_path(name)] = read_file(name);
|
||||
});
|
||||
run();
|
||||
|
|
@ -171,11 +183,11 @@ if (program.self) {
|
|||
}
|
||||
|
||||
function convert_ast(fn) {
|
||||
return UglifyJS.AST_Node.from_mozilla_ast(Object.keys(files).reduce(fn, null));
|
||||
return AST.Node.from_mozilla_ast(Object.keys(files).reduce(fn, null));
|
||||
}
|
||||
|
||||
function run() {
|
||||
UglifyJS.AST_Node.warn_function = function(msg) {
|
||||
AST.Node.warn_function = function(msg) {
|
||||
print_error("WARN: " + msg);
|
||||
};
|
||||
var content = program.sourceMap && program.sourceMap.content;
|
||||
|
|
@ -249,11 +261,11 @@ function run() {
|
|||
return value.size() ? value.map(symdef) : undefined;
|
||||
}
|
||||
if (skip_key(key)) return;
|
||||
if (value instanceof UglifyJS.AST_Token) return;
|
||||
if (value instanceof AST.Token) return;
|
||||
if (value instanceof UglifyJS.Dictionary) return;
|
||||
if (value instanceof UglifyJS.AST_Node) {
|
||||
if (value instanceof AST.Node) {
|
||||
var result = {
|
||||
_class: "AST_" + value.TYPE
|
||||
_class: "AST." + value.TYPE
|
||||
};
|
||||
value.CTOR.PROPS.forEach(function(prop) {
|
||||
result[prop] = value[prop];
|
||||
|
|
@ -348,27 +360,27 @@ function parse_js(flag) {
|
|||
code: false
|
||||
}
|
||||
}).ast.walk(new UglifyJS.TreeWalker(function(node) {
|
||||
if (node instanceof UglifyJS.AST_Assign) {
|
||||
if (node instanceof AST.Assign) {
|
||||
var name = node.left.print_to_string();
|
||||
var value = node.right;
|
||||
if (flag) {
|
||||
options[name] = value;
|
||||
} else if (value instanceof UglifyJS.AST_Array) {
|
||||
} else if (value instanceof AST.Array) {
|
||||
options[name] = value.elements.map(to_string);
|
||||
} else {
|
||||
options[name] = to_string(value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_PropAccess) {
|
||||
if (node instanceof AST.Symbol || node instanceof AST.PropAccess) {
|
||||
var name = node.print_to_string();
|
||||
options[name] = true;
|
||||
return true;
|
||||
}
|
||||
if (!(node instanceof UglifyJS.AST_Sequence)) throw node;
|
||||
if (!(node instanceof AST.Sequence)) throw node;
|
||||
|
||||
function to_string(value) {
|
||||
return value instanceof UglifyJS.AST_Constant ? value.getValue() : value.print_to_string({
|
||||
return value instanceof AST.Constant ? value.getValue() : value.print_to_string({
|
||||
quote_keys: true
|
||||
});
|
||||
}
|
||||
|
|
|
|||
383
lib/ast.js
383
lib/ast.js
|
|
@ -43,6 +43,13 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var utils = require("./utils");
|
||||
var noop = utils.noop;
|
||||
var string_template = utils.string_template;
|
||||
var HOP = utils.HOP;
|
||||
var MAP = utils.MAP;
|
||||
var merge = utils.merge;
|
||||
|
||||
function DEFNODE(type, props, methods, base) {
|
||||
if (typeof base === "undefined") base = AST_Node;
|
||||
props = props ? props.split(/\s+/) : [];
|
||||
|
|
@ -323,34 +330,6 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
|||
$documentation: "The toplevel scope",
|
||||
$propdoc: {
|
||||
globals: "[Object/S] a map of name -> SymbolDef for all undeclared names",
|
||||
},
|
||||
wrap_commonjs: function(name) {
|
||||
var body = this.body;
|
||||
var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");";
|
||||
wrapped_tl = parse(wrapped_tl);
|
||||
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node) {
|
||||
if (node instanceof AST_Directive && node.value == "$ORIG") {
|
||||
return MAP.splice(body);
|
||||
}
|
||||
}));
|
||||
return wrapped_tl;
|
||||
},
|
||||
wrap_enclose: function(args_values) {
|
||||
if (typeof args_values != "string") args_values = "";
|
||||
var index = args_values.indexOf(":");
|
||||
if (index < 0) index = args_values.length;
|
||||
var body = this.body;
|
||||
return parse([
|
||||
"(function(",
|
||||
args_values.slice(0, index),
|
||||
'){"$ORIG"})(',
|
||||
args_values.slice(index + 1),
|
||||
")"
|
||||
].join("")).transform(new TreeTransformer(function(node) {
|
||||
if (node instanceof AST_Directive && node.value == "$ORIG") {
|
||||
return MAP.splice(body);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}, AST_Scope);
|
||||
|
||||
|
|
@ -952,3 +931,351 @@ TreeWalker.prototype = {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
function TreeTransformer(before, after) {
|
||||
TreeWalker.call(this);
|
||||
this.before = before;
|
||||
this.after = after;
|
||||
}
|
||||
TreeTransformer.prototype = new TreeWalker;
|
||||
|
||||
(function(DEF) {
|
||||
function do_list(list, tw) {
|
||||
return MAP(list, function(node) {
|
||||
return node.transform(tw, true);
|
||||
});
|
||||
}
|
||||
|
||||
DEF(AST_Node, noop);
|
||||
DEF(AST_LabeledStatement, function(self, tw) {
|
||||
self.label = self.label.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
DEF(AST_SimpleStatement, function(self, tw) {
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
DEF(AST_Block, function(self, tw) {
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
DEF(AST_Do, function(self, tw) {
|
||||
self.body = self.body.transform(tw);
|
||||
self.condition = self.condition.transform(tw);
|
||||
});
|
||||
DEF(AST_While, function(self, tw) {
|
||||
self.condition = self.condition.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
DEF(AST_For, function(self, tw) {
|
||||
if (self.init) self.init = self.init.transform(tw);
|
||||
if (self.condition) self.condition = self.condition.transform(tw);
|
||||
if (self.step) self.step = self.step.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
DEF(AST_ForIn, function(self, tw) {
|
||||
self.init = self.init.transform(tw);
|
||||
self.object = self.object.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
DEF(AST_With, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
DEF(AST_Exit, function(self, tw) {
|
||||
if (self.value) self.value = self.value.transform(tw);
|
||||
});
|
||||
DEF(AST_LoopControl, function(self, tw) {
|
||||
if (self.label) self.label = self.label.transform(tw);
|
||||
});
|
||||
DEF(AST_If, function(self, tw) {
|
||||
self.condition = self.condition.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
if (self.alternative) self.alternative = self.alternative.transform(tw);
|
||||
});
|
||||
DEF(AST_Switch, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
DEF(AST_Case, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
DEF(AST_Try, function(self, tw) {
|
||||
self.body = do_list(self.body, tw);
|
||||
if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
|
||||
if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
|
||||
});
|
||||
DEF(AST_Catch, function(self, tw) {
|
||||
self.argname = self.argname.transform(tw);
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
DEF(AST_Definitions, function(self, tw) {
|
||||
self.definitions = do_list(self.definitions, tw);
|
||||
});
|
||||
DEF(AST_VarDef, function(self, tw) {
|
||||
self.name = self.name.transform(tw);
|
||||
if (self.value) self.value = self.value.transform(tw);
|
||||
});
|
||||
DEF(AST_Lambda, function(self, tw) {
|
||||
if (self.name) self.name = self.name.transform(tw);
|
||||
self.argnames = do_list(self.argnames, tw);
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
DEF(AST_Call, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.args = do_list(self.args, tw);
|
||||
});
|
||||
DEF(AST_Sequence, function(self, tw) {
|
||||
self.expressions = do_list(self.expressions, tw);
|
||||
});
|
||||
DEF(AST_Dot, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
});
|
||||
DEF(AST_Sub, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.property = self.property.transform(tw);
|
||||
});
|
||||
DEF(AST_Unary, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
});
|
||||
DEF(AST_Binary, function(self, tw) {
|
||||
self.left = self.left.transform(tw);
|
||||
self.right = self.right.transform(tw);
|
||||
});
|
||||
DEF(AST_Conditional, function(self, tw) {
|
||||
self.condition = self.condition.transform(tw);
|
||||
self.consequent = self.consequent.transform(tw);
|
||||
self.alternative = self.alternative.transform(tw);
|
||||
});
|
||||
DEF(AST_Array, function(self, tw) {
|
||||
self.elements = do_list(self.elements, tw);
|
||||
});
|
||||
DEF(AST_Object, function(self, tw) {
|
||||
self.properties = do_list(self.properties, tw);
|
||||
});
|
||||
DEF(AST_ObjectProperty, function(self, tw) {
|
||||
self.value = self.value.transform(tw);
|
||||
});
|
||||
})(function(node, descend) {
|
||||
node.DEFMETHOD("transform", function(tw, in_list) {
|
||||
var x, y;
|
||||
tw.push(this);
|
||||
if (tw.before) x = tw.before(this, descend, in_list);
|
||||
if (typeof x === "undefined") {
|
||||
x = this;
|
||||
descend(x, tw);
|
||||
if (tw.after) {
|
||||
y = tw.after(x, in_list);
|
||||
if (typeof y !== "undefined") x = y;
|
||||
}
|
||||
}
|
||||
tw.pop();
|
||||
return x;
|
||||
});
|
||||
});
|
||||
|
||||
/***********************************************************************
|
||||
/* Helpers
|
||||
/**********************************************************************/
|
||||
|
||||
// return true if the node at the top of the stack (that means the
|
||||
// innermost node in the current output) is lexically the first in
|
||||
// a statement.
|
||||
function first_in_statement(stack) {
|
||||
var node = stack.parent(-1);
|
||||
for (var i = 0, p; p = stack.parent(i++); node = p) {
|
||||
if (p.TYPE == "Call") {
|
||||
if (p.expression === node) continue;
|
||||
} else if (p instanceof AST_Binary) {
|
||||
if (p.left === node) continue;
|
||||
} else if (p instanceof AST_Conditional) {
|
||||
if (p.condition === node) continue;
|
||||
} else if (p instanceof AST_PropAccess) {
|
||||
if (p.expression === node) continue;
|
||||
} else if (p instanceof AST_Sequence) {
|
||||
if (p.expressions[0] === node) continue;
|
||||
} else if (p instanceof AST_Statement) {
|
||||
return p.body === node;
|
||||
} else if (p instanceof AST_UnaryPostfix) {
|
||||
if (p.expression === node) continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
merge(exports, {
|
||||
DEFNODE : DEFNODE,
|
||||
AST_Token : AST_Token,
|
||||
AST_Node : AST_Node,
|
||||
AST_Statement : AST_Statement,
|
||||
AST_Debugger : AST_Debugger,
|
||||
AST_Directive : AST_Directive,
|
||||
AST_SimpleStatement : AST_SimpleStatement,
|
||||
walk_body : walk_body,
|
||||
AST_Block : AST_Block,
|
||||
AST_BlockStatement : AST_BlockStatement,
|
||||
AST_EmptyStatement : AST_EmptyStatement,
|
||||
AST_StatementWithBody : AST_StatementWithBody,
|
||||
AST_LabeledStatement : AST_LabeledStatement,
|
||||
AST_IterationStatement : AST_IterationStatement,
|
||||
AST_DWLoop : AST_DWLoop,
|
||||
AST_Do : AST_Do,
|
||||
AST_While : AST_While,
|
||||
AST_For : AST_For,
|
||||
AST_ForIn : AST_ForIn,
|
||||
AST_With : AST_With,
|
||||
AST_Scope : AST_Scope,
|
||||
AST_Toplevel : AST_Toplevel,
|
||||
AST_Lambda : AST_Lambda,
|
||||
AST_Accessor : AST_Accessor,
|
||||
AST_Function : AST_Function,
|
||||
AST_Defun : AST_Defun,
|
||||
AST_Jump : AST_Jump,
|
||||
AST_Exit : AST_Exit,
|
||||
AST_Return : AST_Return,
|
||||
AST_Throw : AST_Throw,
|
||||
AST_LoopControl : AST_LoopControl,
|
||||
AST_Break : AST_Break,
|
||||
AST_Continue : AST_Continue,
|
||||
AST_If : AST_If,
|
||||
AST_Switch : AST_Switch,
|
||||
AST_SwitchBranch : AST_SwitchBranch,
|
||||
AST_Default : AST_Default,
|
||||
AST_Case : AST_Case,
|
||||
AST_Try : AST_Try,
|
||||
AST_Catch : AST_Catch,
|
||||
AST_Finally : AST_Finally,
|
||||
AST_Definitions : AST_Definitions,
|
||||
AST_Var : AST_Var,
|
||||
AST_VarDef : AST_VarDef,
|
||||
AST_Call : AST_Call,
|
||||
AST_New : AST_New,
|
||||
AST_Sequence : AST_Sequence,
|
||||
AST_PropAccess : AST_PropAccess,
|
||||
AST_Dot : AST_Dot,
|
||||
AST_Sub : AST_Sub,
|
||||
AST_Unary : AST_Unary,
|
||||
AST_UnaryPrefix : AST_UnaryPrefix,
|
||||
AST_UnaryPostfix : AST_UnaryPostfix,
|
||||
AST_Binary : AST_Binary,
|
||||
AST_Conditional : AST_Conditional,
|
||||
AST_Assign : AST_Assign,
|
||||
AST_Array : AST_Array,
|
||||
AST_Object : AST_Object,
|
||||
AST_ObjectProperty : AST_ObjectProperty,
|
||||
AST_ObjectKeyVal : AST_ObjectKeyVal,
|
||||
AST_ObjectSetter : AST_ObjectSetter,
|
||||
AST_ObjectGetter : AST_ObjectGetter,
|
||||
AST_Symbol : AST_Symbol,
|
||||
AST_SymbolAccessor : AST_SymbolAccessor,
|
||||
AST_SymbolDeclaration : AST_SymbolDeclaration,
|
||||
AST_SymbolVar : AST_SymbolVar,
|
||||
AST_SymbolFunarg : AST_SymbolFunarg,
|
||||
AST_SymbolDefun : AST_SymbolDefun,
|
||||
AST_SymbolLambda : AST_SymbolLambda,
|
||||
AST_SymbolCatch : AST_SymbolCatch,
|
||||
AST_Label : AST_Label,
|
||||
AST_SymbolRef : AST_SymbolRef,
|
||||
AST_LabelRef : AST_LabelRef,
|
||||
AST_This : AST_This,
|
||||
AST_Constant : AST_Constant,
|
||||
AST_String : AST_String,
|
||||
AST_Number : AST_Number,
|
||||
AST_RegExp : AST_RegExp,
|
||||
AST_Atom : AST_Atom,
|
||||
AST_Null : AST_Null,
|
||||
AST_NaN : AST_NaN,
|
||||
AST_Undefined : AST_Undefined,
|
||||
AST_Hole : AST_Hole,
|
||||
AST_Infinity : AST_Infinity,
|
||||
AST_Boolean : AST_Boolean,
|
||||
AST_False : AST_False,
|
||||
AST_True : AST_True,
|
||||
TreeWalker : TreeWalker,
|
||||
TreeTransformer : TreeTransformer,
|
||||
first_in_statement : first_in_statement,
|
||||
Token : AST_Token,
|
||||
Node : AST_Node,
|
||||
Statement : AST_Statement,
|
||||
Debugger : AST_Debugger,
|
||||
Directive : AST_Directive,
|
||||
SimpleStatement : AST_SimpleStatement,
|
||||
Block : AST_Block,
|
||||
BlockStatement : AST_BlockStatement,
|
||||
EmptyStatement : AST_EmptyStatement,
|
||||
StatementWithBody : AST_StatementWithBody,
|
||||
LabeledStatement : AST_LabeledStatement,
|
||||
IterationStatement : AST_IterationStatement,
|
||||
DWLoop : AST_DWLoop,
|
||||
Do : AST_Do,
|
||||
While : AST_While,
|
||||
For : AST_For,
|
||||
ForIn : AST_ForIn,
|
||||
With : AST_With,
|
||||
Scope : AST_Scope,
|
||||
Toplevel : AST_Toplevel,
|
||||
Lambda : AST_Lambda,
|
||||
Accessor : AST_Accessor,
|
||||
Function : AST_Function,
|
||||
Defun : AST_Defun,
|
||||
Jump : AST_Jump,
|
||||
Exit : AST_Exit,
|
||||
Return : AST_Return,
|
||||
Throw : AST_Throw,
|
||||
LoopControl : AST_LoopControl,
|
||||
Break : AST_Break,
|
||||
Continue : AST_Continue,
|
||||
If : AST_If,
|
||||
Switch : AST_Switch,
|
||||
SwitchBranch : AST_SwitchBranch,
|
||||
Default : AST_Default,
|
||||
Case : AST_Case,
|
||||
Try : AST_Try,
|
||||
Catch : AST_Catch,
|
||||
Finally : AST_Finally,
|
||||
Definitions : AST_Definitions,
|
||||
Var : AST_Var,
|
||||
VarDef : AST_VarDef,
|
||||
Call : AST_Call,
|
||||
New : AST_New,
|
||||
Sequence : AST_Sequence,
|
||||
PropAccess : AST_PropAccess,
|
||||
Dot : AST_Dot,
|
||||
Sub : AST_Sub,
|
||||
Unary : AST_Unary,
|
||||
UnaryPrefix : AST_UnaryPrefix,
|
||||
UnaryPostfix : AST_UnaryPostfix,
|
||||
Binary : AST_Binary,
|
||||
Conditional : AST_Conditional,
|
||||
Assign : AST_Assign,
|
||||
Array : AST_Array,
|
||||
Object : AST_Object,
|
||||
ObjectProperty : AST_ObjectProperty,
|
||||
ObjectKeyVal : AST_ObjectKeyVal,
|
||||
ObjectSetter : AST_ObjectSetter,
|
||||
ObjectGetter : AST_ObjectGetter,
|
||||
Symbol : AST_Symbol,
|
||||
SymbolAccessor : AST_SymbolAccessor,
|
||||
SymbolDeclaration : AST_SymbolDeclaration,
|
||||
SymbolVar : AST_SymbolVar,
|
||||
SymbolFunarg : AST_SymbolFunarg,
|
||||
SymbolDefun : AST_SymbolDefun,
|
||||
SymbolLambda : AST_SymbolLambda,
|
||||
SymbolCatch : AST_SymbolCatch,
|
||||
Label : AST_Label,
|
||||
SymbolRef : AST_SymbolRef,
|
||||
LabelRef : AST_LabelRef,
|
||||
This : AST_This,
|
||||
Constant : AST_Constant,
|
||||
String : AST_String,
|
||||
Number : AST_Number,
|
||||
RegExp : AST_RegExp,
|
||||
Atom : AST_Atom,
|
||||
Null : AST_Null,
|
||||
NaN : AST_NaN,
|
||||
Undefined : AST_Undefined,
|
||||
Hole : AST_Hole,
|
||||
Infinity : AST_Infinity,
|
||||
Boolean : AST_Boolean,
|
||||
False : AST_False,
|
||||
True : AST_True,
|
||||
});
|
||||
|
|
|
|||
2141
lib/compress.js
2141
lib/compress.js
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,27 @@
|
|||
"use strict";
|
||||
|
||||
var utils = require("./utils");
|
||||
var defaults = utils.defaults;
|
||||
var Dictionary = utils.Dictionary;
|
||||
var HOP = utils.HOP;
|
||||
var MAP = utils.MAP;
|
||||
var merge = utils.merge;
|
||||
|
||||
var AST = require("./ast");
|
||||
var TreeTransformer = AST.TreeTransformer;
|
||||
|
||||
var parse = require("./parse");
|
||||
var parse = parse.parse;
|
||||
|
||||
var OutputStream = require("./output").OutputStream;
|
||||
var Compressor = require("./compress").Compressor;
|
||||
|
||||
var SourceMap = require("./sourcemap").SourceMap;
|
||||
|
||||
var propmangle = require("./propmangle");
|
||||
var reserve_quoted_keys = propmangle.reserve_quoted_keys;
|
||||
var mangle_properties = propmangle.mangle_properties;
|
||||
|
||||
var to_ascii = typeof atob == "undefined" ? function(b64) {
|
||||
return new Buffer(b64, "base64").toString();
|
||||
} : atob;
|
||||
|
|
@ -10,7 +32,7 @@ var to_base64 = typeof btoa == "undefined" ? function(str) {
|
|||
function read_source_map(name, code) {
|
||||
var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code);
|
||||
if (!match) {
|
||||
AST_Node.warn("inline source map not found: " + name);
|
||||
AST.Node.warn("inline source map not found: " + name);
|
||||
return null;
|
||||
}
|
||||
return to_ascii(match[2]);
|
||||
|
|
@ -51,7 +73,36 @@ function to_json(cache) {
|
|||
}
|
||||
|
||||
function minify(files, options) {
|
||||
var warn_function = AST_Node.warn_function;
|
||||
function wrap_commonjs(toplevel_node, name) {
|
||||
var body = toplevel_node.body;
|
||||
var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");";
|
||||
wrapped_tl = parse(wrapped_tl);
|
||||
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node) {
|
||||
if (node instanceof AST.Directive && node.value == "$ORIG") {
|
||||
return MAP.splice(body);
|
||||
}
|
||||
}));
|
||||
return wrapped_tl;
|
||||
}
|
||||
function wrap_enclose(toplevel_node, args_values) {
|
||||
if (typeof args_values != "string") args_values = "";
|
||||
var index = args_values.indexOf(":");
|
||||
if (index < 0) index = args_values.length;
|
||||
var body = toplevel_node.body;
|
||||
return parse([
|
||||
"(function(",
|
||||
args_values.slice(0, index),
|
||||
'){"$ORIG"})(',
|
||||
args_values.slice(index + 1),
|
||||
")"
|
||||
].join("")).transform(new TreeTransformer(function(node) {
|
||||
if (node instanceof AST.Directive && node.value == "$ORIG") {
|
||||
return MAP.splice(body);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
var warn_function = AST.Node.warn_function;
|
||||
try {
|
||||
options = defaults(options, {
|
||||
compress: {},
|
||||
|
|
@ -116,14 +167,14 @@ function minify(files, options) {
|
|||
}, true);
|
||||
}
|
||||
var warnings = [];
|
||||
if (options.warnings && !AST_Node.warn_function) {
|
||||
AST_Node.warn_function = function(warning) {
|
||||
if (options.warnings && !AST.Node.warn_function) {
|
||||
AST.Node.warn_function = function(warning) {
|
||||
warnings.push(warning);
|
||||
};
|
||||
}
|
||||
if (timings) timings.parse = Date.now();
|
||||
var source_maps, toplevel;
|
||||
if (files instanceof AST_Toplevel) {
|
||||
if (files instanceof AST.Toplevel) {
|
||||
toplevel = files;
|
||||
} else {
|
||||
if (typeof files == "string") {
|
||||
|
|
@ -156,10 +207,10 @@ function minify(files, options) {
|
|||
reserve_quoted_keys(toplevel, quoted_props);
|
||||
}
|
||||
if (options.wrap) {
|
||||
toplevel = toplevel.wrap_commonjs(options.wrap);
|
||||
toplevel = wrap_commonjs(toplevel, options.wrap);
|
||||
}
|
||||
if (options.enclose) {
|
||||
toplevel = toplevel.wrap_enclose(options.enclose);
|
||||
toplevel = wrap_enclose(toplevel, options.enclose);
|
||||
}
|
||||
if (timings) timings.rename = Date.now();
|
||||
if (options.rename) {
|
||||
|
|
@ -192,7 +243,7 @@ function minify(files, options) {
|
|||
root: options.sourceMap.root
|
||||
});
|
||||
if (options.sourceMap.includeSources) {
|
||||
if (files instanceof AST_Toplevel) {
|
||||
if (files instanceof AST.Toplevel) {
|
||||
throw new Error("original source content unavailable");
|
||||
} else for (var name in files) if (HOP(files, name)) {
|
||||
options.output.source_map.get().setSourceContent(name, files[name]);
|
||||
|
|
@ -241,6 +292,17 @@ function minify(files, options) {
|
|||
} catch (ex) {
|
||||
return { error: ex };
|
||||
} finally {
|
||||
AST_Node.warn_function = warn_function;
|
||||
AST.Node.warn_function = warn_function;
|
||||
}
|
||||
}
|
||||
|
||||
merge(exports, {
|
||||
to_ascii : to_ascii,
|
||||
to_base64 : to_base64,
|
||||
read_source_map : read_source_map,
|
||||
parse_source_map : parse_source_map,
|
||||
set_shorthand : set_shorthand,
|
||||
init_cache : init_cache,
|
||||
to_json : to_json,
|
||||
minify : minify,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -43,17 +43,20 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var AST = require("./ast");
|
||||
var TreeWalker = AST.TreeWalker;
|
||||
|
||||
(function() {
|
||||
function normalize_directives(body) {
|
||||
var in_directive = true;
|
||||
for (var i = 0; i < body.length; i++) {
|
||||
if (in_directive && body[i] instanceof AST_Statement && body[i].body instanceof AST_String) {
|
||||
body[i] = new AST_Directive({
|
||||
if (in_directive && body[i] instanceof AST.Statement && body[i].body instanceof AST.String) {
|
||||
body[i] = new AST.Directive({
|
||||
start: body[i].start,
|
||||
end: body[i].end,
|
||||
value: body[i].body.value
|
||||
});
|
||||
} else if (in_directive && !(body[i] instanceof AST_Statement && body[i].body instanceof AST_String)) {
|
||||
} else if (in_directive && !(body[i] instanceof AST.Statement && body[i].body instanceof AST.String)) {
|
||||
in_directive = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -62,14 +65,14 @@
|
|||
|
||||
var MOZ_TO_ME = {
|
||||
Program: function(M) {
|
||||
return new AST_Toplevel({
|
||||
return new AST.Toplevel({
|
||||
start: my_start_token(M),
|
||||
end: my_end_token(M),
|
||||
body: normalize_directives(M.body.map(from_moz))
|
||||
});
|
||||
},
|
||||
FunctionDeclaration: function(M) {
|
||||
return new AST_Defun({
|
||||
return new AST.Defun({
|
||||
start: my_start_token(M),
|
||||
end: my_end_token(M),
|
||||
name: from_moz(M.id),
|
||||
|
|
@ -78,7 +81,7 @@
|
|||
});
|
||||
},
|
||||
FunctionExpression: function(M) {
|
||||
return new AST_Function({
|
||||
return new AST.Function({
|
||||
start: my_start_token(M),
|
||||
end: my_end_token(M),
|
||||
name: from_moz(M.id),
|
||||
|
|
@ -87,7 +90,7 @@
|
|||
});
|
||||
},
|
||||
ExpressionStatement: function(M) {
|
||||
return new AST_SimpleStatement({
|
||||
return new AST.SimpleStatement({
|
||||
start: my_start_token(M),
|
||||
end: my_end_token(M),
|
||||
body: from_moz(M.expression)
|
||||
|
|
@ -98,12 +101,12 @@
|
|||
if (handlers.length > 1 || M.guardedHandlers && M.guardedHandlers.length) {
|
||||
throw new Error("Multiple catch clauses are not supported.");
|
||||
}
|
||||
return new AST_Try({
|
||||
return new AST.Try({
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
body : from_moz(M.block).body,
|
||||
bcatch : from_moz(handlers[0]),
|
||||
bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null
|
||||
bfinally : M.finalizer ? new AST.Finally(from_moz(M.finalizer)) : null
|
||||
});
|
||||
},
|
||||
Property: function(M) {
|
||||
|
|
@ -114,25 +117,25 @@
|
|||
key : key.type == "Identifier" ? key.name : key.value,
|
||||
value : from_moz(M.value)
|
||||
};
|
||||
if (M.kind == "init") return new AST_ObjectKeyVal(args);
|
||||
args.key = new AST_SymbolAccessor({
|
||||
if (M.kind == "init") return new AST.ObjectKeyVal(args);
|
||||
args.key = new AST.SymbolAccessor({
|
||||
name: args.key
|
||||
});
|
||||
args.value = new AST_Accessor(args.value);
|
||||
if (M.kind == "get") return new AST_ObjectGetter(args);
|
||||
if (M.kind == "set") return new AST_ObjectSetter(args);
|
||||
args.value = new AST.Accessor(args.value);
|
||||
if (M.kind == "get") return new AST.ObjectGetter(args);
|
||||
if (M.kind == "set") return new AST.ObjectSetter(args);
|
||||
},
|
||||
ArrayExpression: function(M) {
|
||||
return new AST_Array({
|
||||
return new AST.Array({
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
elements : M.elements.map(function(elem) {
|
||||
return elem === null ? new AST_Hole() : from_moz(elem);
|
||||
return elem === null ? new AST.Hole() : from_moz(elem);
|
||||
})
|
||||
});
|
||||
},
|
||||
ObjectExpression: function(M) {
|
||||
return new AST_Object({
|
||||
return new AST.Object({
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
properties : M.properties.map(function(prop) {
|
||||
|
|
@ -142,14 +145,14 @@
|
|||
});
|
||||
},
|
||||
SequenceExpression: function(M) {
|
||||
return new AST_Sequence({
|
||||
return new AST.Sequence({
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
expressions: M.expressions.map(from_moz)
|
||||
});
|
||||
},
|
||||
MemberExpression: function(M) {
|
||||
return new (M.computed ? AST_Sub : AST_Dot)({
|
||||
return new (M.computed ? AST.Sub : AST.Dot)({
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
property : M.computed ? from_moz(M.property) : M.property.name,
|
||||
|
|
@ -157,7 +160,7 @@
|
|||
});
|
||||
},
|
||||
SwitchCase: function(M) {
|
||||
return new (M.test ? AST_Case : AST_Default)({
|
||||
return new (M.test ? AST.Case : AST.Default)({
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
expression : from_moz(M.test),
|
||||
|
|
@ -165,7 +168,7 @@
|
|||
});
|
||||
},
|
||||
VariableDeclaration: function(M) {
|
||||
return new AST_Var({
|
||||
return new AST.Var({
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
definitions : M.declarations.map(from_moz)
|
||||
|
|
@ -176,38 +179,38 @@
|
|||
start : my_start_token(M),
|
||||
end : my_end_token(M)
|
||||
};
|
||||
if (val === null) return new AST_Null(args);
|
||||
if (val === null) return new AST.Null(args);
|
||||
var rx = M.regex;
|
||||
if (rx && rx.pattern) {
|
||||
// RegExpLiteral as per ESTree AST spec
|
||||
args.value = new RegExp(rx.pattern, rx.flags);
|
||||
args.value.raw_source = rx.pattern;
|
||||
return new AST_RegExp(args);
|
||||
return new AST.RegExp(args);
|
||||
} else if (rx) {
|
||||
// support legacy RegExp
|
||||
args.value = M.regex && M.raw ? M.raw : val;
|
||||
return new AST_RegExp(args);
|
||||
return new AST.RegExp(args);
|
||||
}
|
||||
switch (typeof val) {
|
||||
case "string":
|
||||
args.value = val;
|
||||
return new AST_String(args);
|
||||
return new AST.String(args);
|
||||
case "number":
|
||||
args.value = val;
|
||||
return new AST_Number(args);
|
||||
return new AST.Number(args);
|
||||
case "boolean":
|
||||
return new (val ? AST_True : AST_False)(args);
|
||||
return new (val ? AST.True : AST.False)(args);
|
||||
}
|
||||
},
|
||||
Identifier: function(M) {
|
||||
var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
|
||||
return new ( p.type == "LabeledStatement" ? AST_Label
|
||||
: p.type == "VariableDeclarator" && p.id === M ? AST_SymbolVar
|
||||
: p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg)
|
||||
: p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg)
|
||||
: p.type == "CatchClause" ? AST_SymbolCatch
|
||||
: p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef
|
||||
: AST_SymbolRef)({
|
||||
return new ( p.type == "LabeledStatement" ? AST.Label
|
||||
: p.type == "VariableDeclarator" && p.id === M ? AST.SymbolVar
|
||||
: p.type == "FunctionExpression" ? (p.id === M ? AST.SymbolLambda : AST.SymbolFunarg)
|
||||
: p.type == "FunctionDeclaration" ? (p.id === M ? AST.SymbolDefun : AST.SymbolFunarg)
|
||||
: p.type == "CatchClause" ? AST.SymbolCatch
|
||||
: p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST.LabelRef
|
||||
: AST.SymbolRef)({
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
name : M.name
|
||||
|
|
@ -219,7 +222,7 @@
|
|||
MOZ_TO_ME.UnaryExpression = function To_Moz_Unary(M) {
|
||||
var prefix = "prefix" in M ? M.prefix
|
||||
: M.type == "UnaryExpression" ? true : false;
|
||||
return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({
|
||||
return new (prefix ? AST.UnaryPrefix : AST.UnaryPostfix)({
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
operator : M.operator,
|
||||
|
|
@ -227,37 +230,37 @@
|
|||
});
|
||||
};
|
||||
|
||||
map("EmptyStatement", AST_EmptyStatement);
|
||||
map("BlockStatement", AST_BlockStatement, "body@body");
|
||||
map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
|
||||
map("LabeledStatement", AST_LabeledStatement, "label>label, body>body");
|
||||
map("BreakStatement", AST_Break, "label>label");
|
||||
map("ContinueStatement", AST_Continue, "label>label");
|
||||
map("WithStatement", AST_With, "object>expression, body>body");
|
||||
map("SwitchStatement", AST_Switch, "discriminant>expression, cases@body");
|
||||
map("ReturnStatement", AST_Return, "argument>value");
|
||||
map("ThrowStatement", AST_Throw, "argument>value");
|
||||
map("WhileStatement", AST_While, "test>condition, body>body");
|
||||
map("DoWhileStatement", AST_Do, "test>condition, body>body");
|
||||
map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body");
|
||||
map("ForInStatement", AST_ForIn, "left>init, right>object, body>body");
|
||||
map("DebuggerStatement", AST_Debugger);
|
||||
map("VariableDeclarator", AST_VarDef, "id>name, init>value");
|
||||
map("CatchClause", AST_Catch, "param>argname, body%body");
|
||||
map("EmptyStatement", AST.EmptyStatement);
|
||||
map("BlockStatement", AST.BlockStatement, "body@body");
|
||||
map("IfStatement", AST.If, "test>condition, consequent>body, alternate>alternative");
|
||||
map("LabeledStatement", AST.LabeledStatement, "label>label, body>body");
|
||||
map("BreakStatement", AST.Break, "label>label");
|
||||
map("ContinueStatement", AST.Continue, "label>label");
|
||||
map("WithStatement", AST.With, "object>expression, body>body");
|
||||
map("SwitchStatement", AST.Switch, "discriminant>expression, cases@body");
|
||||
map("ReturnStatement", AST.Return, "argument>value");
|
||||
map("ThrowStatement", AST.Throw, "argument>value");
|
||||
map("WhileStatement", AST.While, "test>condition, body>body");
|
||||
map("DoWhileStatement", AST.Do, "test>condition, body>body");
|
||||
map("ForStatement", AST.For, "init>init, test>condition, update>step, body>body");
|
||||
map("ForInStatement", AST.ForIn, "left>init, right>object, body>body");
|
||||
map("DebuggerStatement", AST.Debugger);
|
||||
map("VariableDeclarator", AST.VarDef, "id>name, init>value");
|
||||
map("CatchClause", AST.Catch, "param>argname, body%body");
|
||||
|
||||
map("ThisExpression", AST_This);
|
||||
map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right");
|
||||
map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right");
|
||||
map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
|
||||
map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative");
|
||||
map("NewExpression", AST_New, "callee>expression, arguments@args");
|
||||
map("CallExpression", AST_Call, "callee>expression, arguments@args");
|
||||
map("ThisExpression", AST.This);
|
||||
map("BinaryExpression", AST.Binary, "operator=operator, left>left, right>right");
|
||||
map("LogicalExpression", AST.Binary, "operator=operator, left>left, right>right");
|
||||
map("AssignmentExpression", AST.Assign, "operator=operator, left>left, right>right");
|
||||
map("ConditionalExpression", AST.Conditional, "test>condition, consequent>consequent, alternate>alternative");
|
||||
map("NewExpression", AST.New, "callee>expression, arguments@args");
|
||||
map("CallExpression", AST.Call, "callee>expression, arguments@args");
|
||||
|
||||
def_to_moz(AST_Toplevel, function To_Moz_Program(M) {
|
||||
def_to_moz(AST.Toplevel, function To_Moz_Program(M) {
|
||||
return to_moz_scope("Program", M);
|
||||
});
|
||||
|
||||
def_to_moz(AST_Defun, function To_Moz_FunctionDeclaration(M) {
|
||||
def_to_moz(AST.Defun, function To_Moz_FunctionDeclaration(M) {
|
||||
return {
|
||||
type: "FunctionDeclaration",
|
||||
id: to_moz(M.name),
|
||||
|
|
@ -266,7 +269,7 @@
|
|||
}
|
||||
});
|
||||
|
||||
def_to_moz(AST_Function, function To_Moz_FunctionExpression(M) {
|
||||
def_to_moz(AST.Function, function To_Moz_FunctionExpression(M) {
|
||||
return {
|
||||
type: "FunctionExpression",
|
||||
id: to_moz(M.name),
|
||||
|
|
@ -275,7 +278,7 @@
|
|||
}
|
||||
});
|
||||
|
||||
def_to_moz(AST_Directive, function To_Moz_Directive(M) {
|
||||
def_to_moz(AST.Directive, function To_Moz_Directive(M) {
|
||||
return {
|
||||
type: "ExpressionStatement",
|
||||
expression: {
|
||||
|
|
@ -285,14 +288,14 @@
|
|||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_SimpleStatement, function To_Moz_ExpressionStatement(M) {
|
||||
def_to_moz(AST.SimpleStatement, function To_Moz_ExpressionStatement(M) {
|
||||
return {
|
||||
type: "ExpressionStatement",
|
||||
expression: to_moz(M.body)
|
||||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_SwitchBranch, function To_Moz_SwitchCase(M) {
|
||||
def_to_moz(AST.SwitchBranch, function To_Moz_SwitchCase(M) {
|
||||
return {
|
||||
type: "SwitchCase",
|
||||
test: to_moz(M.expression),
|
||||
|
|
@ -300,7 +303,7 @@
|
|||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Try, function To_Moz_TryStatement(M) {
|
||||
def_to_moz(AST.Try, function To_Moz_TryStatement(M) {
|
||||
return {
|
||||
type: "TryStatement",
|
||||
block: to_moz_block(M),
|
||||
|
|
@ -310,7 +313,7 @@
|
|||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Catch, function To_Moz_CatchClause(M) {
|
||||
def_to_moz(AST.Catch, function To_Moz_CatchClause(M) {
|
||||
return {
|
||||
type: "CatchClause",
|
||||
param: to_moz(M.argname),
|
||||
|
|
@ -319,7 +322,7 @@
|
|||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) {
|
||||
def_to_moz(AST.Definitions, function To_Moz_VariableDeclaration(M) {
|
||||
return {
|
||||
type: "VariableDeclaration",
|
||||
kind: "var",
|
||||
|
|
@ -327,15 +330,15 @@
|
|||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Sequence, function To_Moz_SequenceExpression(M) {
|
||||
def_to_moz(AST.Sequence, function To_Moz_SequenceExpression(M) {
|
||||
return {
|
||||
type: "SequenceExpression",
|
||||
expressions: M.expressions.map(to_moz)
|
||||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_PropAccess, function To_Moz_MemberExpression(M) {
|
||||
var isComputed = M instanceof AST_Sub;
|
||||
def_to_moz(AST.PropAccess, function To_Moz_MemberExpression(M) {
|
||||
var isComputed = M instanceof AST.Sub;
|
||||
return {
|
||||
type: "MemberExpression",
|
||||
object: to_moz(M.expression),
|
||||
|
|
@ -344,16 +347,16 @@
|
|||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Unary, function To_Moz_Unary(M) {
|
||||
def_to_moz(AST.Unary, function To_Moz_Unary(M) {
|
||||
return {
|
||||
type: M.operator == "++" || M.operator == "--" ? "UpdateExpression" : "UnaryExpression",
|
||||
operator: M.operator,
|
||||
prefix: M instanceof AST_UnaryPrefix,
|
||||
prefix: M instanceof AST.UnaryPrefix,
|
||||
argument: to_moz(M.expression)
|
||||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Binary, function To_Moz_BinaryExpression(M) {
|
||||
def_to_moz(AST.Binary, function To_Moz_BinaryExpression(M) {
|
||||
return {
|
||||
type: M.operator == "&&" || M.operator == "||" ? "LogicalExpression" : "BinaryExpression",
|
||||
left: to_moz(M.left),
|
||||
|
|
@ -362,33 +365,33 @@
|
|||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Array, function To_Moz_ArrayExpression(M) {
|
||||
def_to_moz(AST.Array, function To_Moz_ArrayExpression(M) {
|
||||
return {
|
||||
type: "ArrayExpression",
|
||||
elements: M.elements.map(to_moz)
|
||||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Object, function To_Moz_ObjectExpression(M) {
|
||||
def_to_moz(AST.Object, function To_Moz_ObjectExpression(M) {
|
||||
return {
|
||||
type: "ObjectExpression",
|
||||
properties: M.properties.map(to_moz)
|
||||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
|
||||
def_to_moz(AST.ObjectProperty, function To_Moz_Property(M) {
|
||||
var key = {
|
||||
type: "Literal",
|
||||
value: M.key instanceof AST_SymbolAccessor ? M.key.name : M.key
|
||||
value: M.key instanceof AST.SymbolAccessor ? M.key.name : M.key
|
||||
};
|
||||
var kind;
|
||||
if (M instanceof AST_ObjectKeyVal) {
|
||||
if (M instanceof AST.ObjectKeyVal) {
|
||||
kind = "init";
|
||||
} else
|
||||
if (M instanceof AST_ObjectGetter) {
|
||||
if (M instanceof AST.ObjectGetter) {
|
||||
kind = "get";
|
||||
} else
|
||||
if (M instanceof AST_ObjectSetter) {
|
||||
if (M instanceof AST.ObjectSetter) {
|
||||
kind = "set";
|
||||
}
|
||||
return {
|
||||
|
|
@ -399,7 +402,7 @@
|
|||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Symbol, function To_Moz_Identifier(M) {
|
||||
def_to_moz(AST.Symbol, function To_Moz_Identifier(M) {
|
||||
var def = M.definition();
|
||||
return {
|
||||
type: "Identifier",
|
||||
|
|
@ -407,7 +410,7 @@
|
|||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) {
|
||||
def_to_moz(AST.RegExp, function To_Moz_RegExpLiteral(M) {
|
||||
var flags = M.value.toString().match(/[gimuy]*$/)[0];
|
||||
var value = "/" + M.value.raw_source + "/" + flags;
|
||||
return {
|
||||
|
|
@ -421,7 +424,7 @@
|
|||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Constant, function To_Moz_Literal(M) {
|
||||
def_to_moz(AST.Constant, function To_Moz_Literal(M) {
|
||||
var value = M.value;
|
||||
if (typeof value === 'number' && (value < 0 || (value === 0 && 1 / value < 0))) {
|
||||
return {
|
||||
|
|
@ -442,19 +445,19 @@
|
|||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Atom, function To_Moz_Atom(M) {
|
||||
def_to_moz(AST.Atom, function To_Moz_Atom(M) {
|
||||
return {
|
||||
type: "Identifier",
|
||||
name: String(M.value)
|
||||
};
|
||||
});
|
||||
|
||||
AST_Boolean.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast);
|
||||
AST_Null.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast);
|
||||
AST_Hole.DEFMETHOD("to_mozilla_ast", function To_Moz_ArrayHole() { return null });
|
||||
AST.Boolean.DEFMETHOD("to_mozilla_ast", AST.Constant.prototype.to_mozilla_ast);
|
||||
AST.Null.DEFMETHOD("to_mozilla_ast", AST.Constant.prototype.to_mozilla_ast);
|
||||
AST.Hole.DEFMETHOD("to_mozilla_ast", function To_Moz_ArrayHole() { return null });
|
||||
|
||||
AST_Block.DEFMETHOD("to_mozilla_ast", AST_BlockStatement.prototype.to_mozilla_ast);
|
||||
AST_Lambda.DEFMETHOD("to_mozilla_ast", AST_Function.prototype.to_mozilla_ast);
|
||||
AST.Block.DEFMETHOD("to_mozilla_ast", AST.BlockStatement.prototype.to_mozilla_ast);
|
||||
AST.Lambda.DEFMETHOD("to_mozilla_ast", AST.Function.prototype.to_mozilla_ast);
|
||||
|
||||
/* -----[ tools ]----- */
|
||||
|
||||
|
|
@ -467,7 +470,7 @@
|
|||
function my_start_token(moznode) {
|
||||
var loc = moznode.loc, start = loc && loc.start;
|
||||
var range = moznode.range;
|
||||
return new AST_Token({
|
||||
return new AST.Token({
|
||||
file : loc && loc.source,
|
||||
line : start && start.line,
|
||||
col : start && start.column,
|
||||
|
|
@ -482,7 +485,7 @@
|
|||
function my_end_token(moznode) {
|
||||
var loc = moznode.loc, end = loc && loc.end;
|
||||
var range = moznode.range;
|
||||
return new AST_Token({
|
||||
return new AST.Token({
|
||||
file : loc && loc.source,
|
||||
line : end && end.line,
|
||||
col : end && end.column,
|
||||
|
|
@ -540,7 +543,7 @@
|
|||
//console.log(moz_to_me);
|
||||
|
||||
moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
|
||||
exports, my_start_token, my_end_token, from_moz
|
||||
AST, my_start_token, my_end_token, from_moz
|
||||
);
|
||||
me_to_moz = new Function("to_moz", "to_moz_block", "to_moz_scope", "return(" + me_to_moz + ")")(
|
||||
to_moz, to_moz_block, to_moz_scope
|
||||
|
|
@ -558,16 +561,16 @@
|
|||
return ret;
|
||||
}
|
||||
|
||||
AST_Node.from_mozilla_ast = function(node) {
|
||||
AST.Node.from_mozilla_ast = function(node) {
|
||||
var save_stack = FROM_MOZ_STACK;
|
||||
FROM_MOZ_STACK = [];
|
||||
var ast = from_moz(node);
|
||||
FROM_MOZ_STACK = save_stack;
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_LabelRef) {
|
||||
if (node instanceof AST.LabelRef) {
|
||||
for (var level = 0, parent; parent = this.parent(level); level++) {
|
||||
if (parent instanceof AST_Scope) break;
|
||||
if (parent instanceof AST_LabeledStatement && parent.label.name == node.name) {
|
||||
if (parent instanceof AST.Scope) break;
|
||||
if (parent instanceof AST.LabeledStatement && parent.label.name == node.name) {
|
||||
node.thedef = parent.label;
|
||||
break;
|
||||
}
|
||||
|
|
@ -618,8 +621,8 @@
|
|||
|
||||
function to_moz_scope(type, node) {
|
||||
var body = node.body.map(to_moz);
|
||||
if (node.body[0] instanceof AST_SimpleStatement && node.body[0].body instanceof AST_String) {
|
||||
body.unshift(to_moz(new AST_EmptyStatement(node.body[0])));
|
||||
if (node.body[0] instanceof AST.SimpleStatement && node.body[0].body instanceof AST.String) {
|
||||
body.unshift(to_moz(new AST.EmptyStatement(node.body[0])));
|
||||
}
|
||||
return {
|
||||
type: type,
|
||||
|
|
|
|||
354
lib/output.js
354
lib/output.js
|
|
@ -43,6 +43,28 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var utils = require("./utils");
|
||||
var repeat_string = utils.repeat_string;
|
||||
var defaults = utils.defaults;
|
||||
var noop = utils.noop;
|
||||
var return_false = utils.return_false;
|
||||
var return_true = utils.return_true;
|
||||
var makePredicate = utils.makePredicate;
|
||||
var all = utils.all;
|
||||
var merge = utils.merge;
|
||||
|
||||
var AST = require("./ast");
|
||||
var first_in_statement = AST.first_in_statement;
|
||||
var TreeWalker = AST.TreeWalker;
|
||||
|
||||
var parse = require("./parse");
|
||||
var is_surrogate_pair_head = parse.is_surrogate_pair_head;
|
||||
var is_surrogate_pair_tail = parse.is_surrogate_pair_tail;
|
||||
var is_identifier_char = parse.is_identifier_char;
|
||||
var is_identifier_string = parse.is_identifier_string;
|
||||
var PRECEDENCE = parse.PRECEDENCE;
|
||||
var RESERVED_WORDS = parse.RESERVED_WORDS;
|
||||
|
||||
var EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/;
|
||||
|
||||
function is_some_comments(comment) {
|
||||
|
|
@ -217,7 +239,7 @@ function OutputStream(options) {
|
|||
!mapping.name && mapping.token.type == "name" ? mapping.token.value : mapping.name
|
||||
);
|
||||
} catch(ex) {
|
||||
AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
|
||||
AST.Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", {
|
||||
file: mapping.token.file,
|
||||
line: mapping.token.line,
|
||||
col: mapping.token.col,
|
||||
|
|
@ -248,7 +270,7 @@ function OutputStream(options) {
|
|||
current_col = right.length;
|
||||
}
|
||||
if (current_col > options.max_line_len) {
|
||||
AST_Node.warn("Output exceeds {max_line_len} characters", options);
|
||||
AST.Node.warn("Output exceeds {max_line_len} characters", options);
|
||||
}
|
||||
}
|
||||
if (might_add_newline) {
|
||||
|
|
@ -477,17 +499,17 @@ function OutputStream(options) {
|
|||
}
|
||||
comments._dumped = self;
|
||||
|
||||
if (node instanceof AST_Exit && node.value) {
|
||||
if (node instanceof AST.Exit && node.value) {
|
||||
var tw = new TreeWalker(function(node) {
|
||||
var parent = tw.parent();
|
||||
if (parent instanceof AST_Exit
|
||||
|| parent instanceof AST_Binary && parent.left === node
|
||||
if (parent instanceof AST.Exit
|
||||
|| parent instanceof AST.Binary && parent.left === node
|
||||
|| parent.TYPE == "Call" && parent.expression === node
|
||||
|| parent instanceof AST_Conditional && parent.condition === node
|
||||
|| parent instanceof AST_Dot && parent.expression === node
|
||||
|| parent instanceof AST_Sequence && parent.expressions[0] === node
|
||||
|| parent instanceof AST_Sub && parent.expression === node
|
||||
|| parent instanceof AST_UnaryPostfix) {
|
||||
|| parent instanceof AST.Conditional && parent.condition === node
|
||||
|| parent instanceof AST.Dot && parent.expression === node
|
||||
|| parent instanceof AST.Sequence && parent.expressions[0] === node
|
||||
|| parent instanceof AST.Sub && parent.expression === node
|
||||
|| parent instanceof AST.UnaryPostfix) {
|
||||
var text = node.start.comments_before;
|
||||
if (text && text._dumped !== self) {
|
||||
text._dumped = self;
|
||||
|
|
@ -550,7 +572,7 @@ function OutputStream(options) {
|
|||
if (!token) return;
|
||||
var comments = token[tail ? "comments_before" : "comments_after"];
|
||||
if (!comments || comments._dumped === self) return;
|
||||
if (!(node instanceof AST_Statement || all(comments, function(c) {
|
||||
if (!(node instanceof AST.Statement || all(comments, function(c) {
|
||||
return !/comment[134]/.test(c.type);
|
||||
}))) return;
|
||||
comments._dumped = self;
|
||||
|
|
@ -643,12 +665,12 @@ function OutputStream(options) {
|
|||
var active_scope = null;
|
||||
var use_asm = null;
|
||||
|
||||
AST_Node.DEFMETHOD("print", function(stream, force_parens) {
|
||||
AST.Node.DEFMETHOD("print", function(stream, force_parens) {
|
||||
var self = this, generator = self._codegen;
|
||||
if (self instanceof AST_Scope) {
|
||||
if (self instanceof AST.Scope) {
|
||||
active_scope = self;
|
||||
}
|
||||
else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") {
|
||||
else if (!use_asm && self instanceof AST.Directive && self.value == "use asm") {
|
||||
use_asm = active_scope;
|
||||
}
|
||||
function doit() {
|
||||
|
|
@ -668,9 +690,9 @@ function OutputStream(options) {
|
|||
use_asm = null;
|
||||
}
|
||||
});
|
||||
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
||||
AST.Node.DEFMETHOD("_print", AST.Node.prototype.print);
|
||||
|
||||
AST_Node.DEFMETHOD("print_to_string", function(options) {
|
||||
AST.Node.DEFMETHOD("print_to_string", function(options) {
|
||||
var s = OutputStream(options);
|
||||
this.print(s);
|
||||
return s.get();
|
||||
|
|
@ -688,25 +710,25 @@ function OutputStream(options) {
|
|||
}
|
||||
}
|
||||
|
||||
PARENS(AST_Node, return_false);
|
||||
PARENS(AST.Node, return_false);
|
||||
|
||||
// a function expression needs parens around it when it's provably
|
||||
// the first token to appear in a statement.
|
||||
PARENS(AST_Function, function(output) {
|
||||
PARENS(AST.Function, function(output) {
|
||||
if (!output.has_parens() && first_in_statement(output)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (output.option('webkit')) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_PropAccess && p.expression === this) {
|
||||
if (p instanceof AST.PropAccess && p.expression === this) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (output.option('wrap_iife')) {
|
||||
var p = output.parent();
|
||||
return p instanceof AST_Call && p.expression === this;
|
||||
return p instanceof AST.Call && p.expression === this;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -714,43 +736,43 @@ function OutputStream(options) {
|
|||
|
||||
// same goes for an object literal, because otherwise it would be
|
||||
// interpreted as a block of code.
|
||||
PARENS(AST_Object, function(output) {
|
||||
PARENS(AST.Object, function(output) {
|
||||
return !output.has_parens() && first_in_statement(output);
|
||||
});
|
||||
|
||||
PARENS(AST_Unary, function(output) {
|
||||
PARENS(AST.Unary, function(output) {
|
||||
var p = output.parent();
|
||||
return p instanceof AST_PropAccess && p.expression === this
|
||||
|| p instanceof AST_Call && p.expression === this;
|
||||
return p instanceof AST.PropAccess && p.expression === this
|
||||
|| p instanceof AST.Call && p.expression === this;
|
||||
});
|
||||
|
||||
PARENS(AST_Sequence, function(output) {
|
||||
PARENS(AST.Sequence, function(output) {
|
||||
var p = output.parent();
|
||||
return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4)
|
||||
|| p instanceof AST_Unary // !(foo, bar, baz)
|
||||
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
|
||||
|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
|
||||
|| p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||
|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
||||
|| p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
|
||||
|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
|
||||
return p instanceof AST.Call // (foo, bar)() or foo(1, (2, 3), 4)
|
||||
|| p instanceof AST.Unary // !(foo, bar, baz)
|
||||
|| p instanceof AST.Binary // 1 + (2, 3) + 4 ==> 8
|
||||
|| p instanceof AST.VarDef // var a = (1, 2), b = a + a; ==> b == 4
|
||||
|| p instanceof AST.PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||
|| p instanceof AST.Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
||||
|| p instanceof AST.ObjectProperty // { foo: (1, 2) }.foo ==> 2
|
||||
|| p instanceof AST.Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
|
||||
* ==> 20 (side effect, set a := 10 and b := 20) */
|
||||
;
|
||||
});
|
||||
|
||||
PARENS(AST_Binary, function(output) {
|
||||
PARENS(AST.Binary, function(output) {
|
||||
var p = output.parent();
|
||||
// (foo && bar)()
|
||||
if (p instanceof AST_Call && p.expression === this)
|
||||
if (p instanceof AST.Call && p.expression === this)
|
||||
return true;
|
||||
// typeof (foo && bar)
|
||||
if (p instanceof AST_Unary)
|
||||
if (p instanceof AST.Unary)
|
||||
return true;
|
||||
// (foo && bar)["prop"], (foo && bar).prop
|
||||
if (p instanceof AST_PropAccess && p.expression === this)
|
||||
if (p instanceof AST.PropAccess && p.expression === this)
|
||||
return true;
|
||||
// this deals with precedence: 3 * (2 + 1)
|
||||
if (p instanceof AST_Binary) {
|
||||
if (p instanceof AST.Binary) {
|
||||
var po = p.operator, pp = PRECEDENCE[po];
|
||||
var so = this.operator, sp = PRECEDENCE[so];
|
||||
if (pp > sp
|
||||
|
|
@ -761,9 +783,9 @@ function OutputStream(options) {
|
|||
}
|
||||
});
|
||||
|
||||
PARENS(AST_PropAccess, function(output) {
|
||||
PARENS(AST.PropAccess, function(output) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_New && p.expression === this) {
|
||||
if (p instanceof AST.New && p.expression === this) {
|
||||
// i.e. new (foo.bar().baz)
|
||||
//
|
||||
// if there's one call into this subtree, then we need
|
||||
|
|
@ -772,8 +794,8 @@ function OutputStream(options) {
|
|||
// expression.
|
||||
var parens = false;
|
||||
this.walk(new TreeWalker(function(node) {
|
||||
if (parens || node instanceof AST_Scope) return true;
|
||||
if (node instanceof AST_Call) {
|
||||
if (parens || node instanceof AST.Scope) return true;
|
||||
if (node instanceof AST.Call) {
|
||||
parens = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -782,31 +804,31 @@ function OutputStream(options) {
|
|||
}
|
||||
});
|
||||
|
||||
PARENS(AST_Call, function(output) {
|
||||
PARENS(AST.Call, function(output) {
|
||||
var p = output.parent(), p1;
|
||||
if (p instanceof AST_New && p.expression === this)
|
||||
if (p instanceof AST.New && p.expression === this)
|
||||
return true;
|
||||
|
||||
// workaround for Safari bug.
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=123506
|
||||
return this.expression instanceof AST_Function
|
||||
&& p instanceof AST_PropAccess
|
||||
return this.expression instanceof AST.Function
|
||||
&& p instanceof AST.PropAccess
|
||||
&& p.expression === this
|
||||
&& (p1 = output.parent(1)) instanceof AST_Assign
|
||||
&& (p1 = output.parent(1)) instanceof AST.Assign
|
||||
&& p1.left === p;
|
||||
});
|
||||
|
||||
PARENS(AST_New, function(output) {
|
||||
PARENS(AST.New, function(output) {
|
||||
var p = output.parent();
|
||||
if (!need_constructor_parens(this, output)
|
||||
&& (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
|
||||
|| p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
|
||||
&& (p instanceof AST.PropAccess // (new Date).getTime(), (new Date)["getTime"]()
|
||||
|| p instanceof AST.Call && p.expression === this)) // (new foo)(bar)
|
||||
return true;
|
||||
});
|
||||
|
||||
PARENS(AST_Number, function(output) {
|
||||
PARENS(AST.Number, function(output) {
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_PropAccess && p.expression === this) {
|
||||
if (p instanceof AST.PropAccess && p.expression === this) {
|
||||
var value = this.getValue();
|
||||
if (value < 0 || /^0/.test(make_num(value))) {
|
||||
return true;
|
||||
|
|
@ -814,32 +836,32 @@ function OutputStream(options) {
|
|||
}
|
||||
});
|
||||
|
||||
PARENS([ AST_Assign, AST_Conditional ], function(output) {
|
||||
PARENS([ AST.Assign, AST.Conditional ], function(output) {
|
||||
var p = output.parent();
|
||||
// !(a = false) → true
|
||||
if (p instanceof AST_Unary)
|
||||
if (p instanceof AST.Unary)
|
||||
return true;
|
||||
// 1 + (a = 2) + 3 → 6, side effect setting a = 2
|
||||
if (p instanceof AST_Binary && !(p instanceof AST_Assign))
|
||||
if (p instanceof AST.Binary && !(p instanceof AST.Assign))
|
||||
return true;
|
||||
// (a = func)() —or— new (a = Object)()
|
||||
if (p instanceof AST_Call && p.expression === this)
|
||||
if (p instanceof AST.Call && p.expression === this)
|
||||
return true;
|
||||
// (a = foo) ? bar : baz
|
||||
if (p instanceof AST_Conditional && p.condition === this)
|
||||
if (p instanceof AST.Conditional && p.condition === this)
|
||||
return true;
|
||||
// (a = foo)["prop"] —or— (a = foo).prop
|
||||
if (p instanceof AST_PropAccess && p.expression === this)
|
||||
if (p instanceof AST.PropAccess && p.expression === this)
|
||||
return true;
|
||||
});
|
||||
|
||||
/* -----[ PRINTERS ]----- */
|
||||
|
||||
DEFPRINT(AST_Directive, function(self, output) {
|
||||
DEFPRINT(AST.Directive, function(self, output) {
|
||||
output.print_string(self.value, self.quote);
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_Debugger, function(self, output) {
|
||||
DEFPRINT(AST.Debugger, function(self, output) {
|
||||
output.print("debugger");
|
||||
output.semicolon();
|
||||
});
|
||||
|
|
@ -850,13 +872,13 @@ function OutputStream(options) {
|
|||
var last = body.length - 1;
|
||||
in_directive = allow_directives;
|
||||
body.forEach(function(stmt, i) {
|
||||
if (in_directive === true && !(stmt instanceof AST_Directive ||
|
||||
stmt instanceof AST_EmptyStatement ||
|
||||
(stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String)
|
||||
if (in_directive === true && !(stmt instanceof AST.Directive ||
|
||||
stmt instanceof AST.EmptyStatement ||
|
||||
(stmt instanceof AST.SimpleStatement && stmt.body instanceof AST.String)
|
||||
)) {
|
||||
in_directive = false;
|
||||
}
|
||||
if (!(stmt instanceof AST_EmptyStatement)) {
|
||||
if (!(stmt instanceof AST.EmptyStatement)) {
|
||||
output.indent();
|
||||
stmt.print(output);
|
||||
if (!(i == last && is_toplevel)) {
|
||||
|
|
@ -865,8 +887,8 @@ function OutputStream(options) {
|
|||
}
|
||||
}
|
||||
if (in_directive === true &&
|
||||
stmt instanceof AST_SimpleStatement &&
|
||||
stmt.body instanceof AST_String
|
||||
stmt instanceof AST.SimpleStatement &&
|
||||
stmt.body instanceof AST.String
|
||||
) {
|
||||
in_directive = false;
|
||||
}
|
||||
|
|
@ -874,24 +896,24 @@ function OutputStream(options) {
|
|||
in_directive = false;
|
||||
}
|
||||
|
||||
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) {
|
||||
AST.StatementWithBody.DEFMETHOD("_do_print_body", function(output) {
|
||||
force_statement(this.body, output);
|
||||
});
|
||||
|
||||
DEFPRINT(AST_Statement, function(self, output) {
|
||||
DEFPRINT(AST.Statement, function(self, output) {
|
||||
self.body.print(output);
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_Toplevel, function(self, output) {
|
||||
DEFPRINT(AST.Toplevel, function(self, output) {
|
||||
display_body(self.body, true, output, true);
|
||||
output.print("");
|
||||
});
|
||||
DEFPRINT(AST_LabeledStatement, function(self, output) {
|
||||
DEFPRINT(AST.LabeledStatement, function(self, output) {
|
||||
self.label.print(output);
|
||||
output.colon();
|
||||
self.body.print(output);
|
||||
});
|
||||
DEFPRINT(AST_SimpleStatement, function(self, output) {
|
||||
DEFPRINT(AST.SimpleStatement, function(self, output) {
|
||||
self.body.print(output);
|
||||
output.semicolon();
|
||||
});
|
||||
|
|
@ -909,13 +931,13 @@ function OutputStream(options) {
|
|||
});
|
||||
} else print_braced_empty(self, output);
|
||||
}
|
||||
DEFPRINT(AST_BlockStatement, function(self, output) {
|
||||
DEFPRINT(AST.BlockStatement, function(self, output) {
|
||||
print_braced(self, output);
|
||||
});
|
||||
DEFPRINT(AST_EmptyStatement, function(self, output) {
|
||||
DEFPRINT(AST.EmptyStatement, function(self, output) {
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_Do, function(self, output) {
|
||||
DEFPRINT(AST.Do, function(self, output) {
|
||||
output.print("do");
|
||||
output.space();
|
||||
make_block(self.body, output);
|
||||
|
|
@ -927,7 +949,7 @@ function OutputStream(options) {
|
|||
});
|
||||
output.semicolon();
|
||||
});
|
||||
DEFPRINT(AST_While, function(self, output) {
|
||||
DEFPRINT(AST.While, function(self, output) {
|
||||
output.print("while");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
|
|
@ -936,12 +958,12 @@ function OutputStream(options) {
|
|||
output.space();
|
||||
self._do_print_body(output);
|
||||
});
|
||||
DEFPRINT(AST_For, function(self, output) {
|
||||
DEFPRINT(AST.For, function(self, output) {
|
||||
output.print("for");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
if (self.init) {
|
||||
if (self.init instanceof AST_Definitions) {
|
||||
if (self.init instanceof AST.Definitions) {
|
||||
self.init.print(output);
|
||||
} else {
|
||||
parenthesize_for_noin(self.init, output, true);
|
||||
|
|
@ -965,7 +987,7 @@ function OutputStream(options) {
|
|||
output.space();
|
||||
self._do_print_body(output);
|
||||
});
|
||||
DEFPRINT(AST_ForIn, function(self, output) {
|
||||
DEFPRINT(AST.ForIn, function(self, output) {
|
||||
output.print("for");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
|
|
@ -978,7 +1000,7 @@ function OutputStream(options) {
|
|||
output.space();
|
||||
self._do_print_body(output);
|
||||
});
|
||||
DEFPRINT(AST_With, function(self, output) {
|
||||
DEFPRINT(AST.With, function(self, output) {
|
||||
output.print("with");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
|
|
@ -989,7 +1011,7 @@ function OutputStream(options) {
|
|||
});
|
||||
|
||||
/* -----[ functions ]----- */
|
||||
AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) {
|
||||
AST.Lambda.DEFMETHOD("_do_print", function(output, nokeyword) {
|
||||
var self = this;
|
||||
if (!nokeyword) {
|
||||
output.print("function");
|
||||
|
|
@ -1007,7 +1029,7 @@ function OutputStream(options) {
|
|||
output.space();
|
||||
print_braced(self, output, true);
|
||||
});
|
||||
DEFPRINT(AST_Lambda, function(self, output) {
|
||||
DEFPRINT(AST.Lambda, function(self, output) {
|
||||
self._do_print(output);
|
||||
});
|
||||
|
||||
|
|
@ -1021,16 +1043,16 @@ function OutputStream(options) {
|
|||
output.semicolon();
|
||||
}
|
||||
|
||||
DEFPRINT(AST_Return, function(self, output) {
|
||||
DEFPRINT(AST.Return, function(self, output) {
|
||||
print_jump(output, "return", self.value);
|
||||
});
|
||||
DEFPRINT(AST_Throw, function(self, output) {
|
||||
DEFPRINT(AST.Throw, function(self, output) {
|
||||
print_jump(output, "throw", self.value);
|
||||
});
|
||||
DEFPRINT(AST_Break, function(self, output) {
|
||||
DEFPRINT(AST.Break, function(self, output) {
|
||||
print_jump(output, "break", self.label);
|
||||
});
|
||||
DEFPRINT(AST_Continue, function(self, output) {
|
||||
DEFPRINT(AST.Continue, function(self, output) {
|
||||
print_jump(output, "continue", self.label);
|
||||
});
|
||||
|
||||
|
|
@ -1038,7 +1060,7 @@ function OutputStream(options) {
|
|||
function make_then(self, output) {
|
||||
var b = self.body;
|
||||
if (output.option("braces")
|
||||
|| output.option("ie8") && b instanceof AST_Do)
|
||||
|| output.option("ie8") && b instanceof AST.Do)
|
||||
return make_block(b, output);
|
||||
// The squeezer replaces "block"-s that contain only a single
|
||||
// statement with the statement itself; technically, the AST
|
||||
|
|
@ -1049,21 +1071,21 @@ function OutputStream(options) {
|
|||
// adds the block braces if needed.
|
||||
if (!b) return output.force_semicolon();
|
||||
while (true) {
|
||||
if (b instanceof AST_If) {
|
||||
if (b instanceof AST.If) {
|
||||
if (!b.alternative) {
|
||||
make_block(self.body, output);
|
||||
return;
|
||||
}
|
||||
b = b.alternative;
|
||||
}
|
||||
else if (b instanceof AST_StatementWithBody) {
|
||||
else if (b instanceof AST.StatementWithBody) {
|
||||
b = b.body;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
force_statement(self.body, output);
|
||||
}
|
||||
DEFPRINT(AST_If, function(self, output) {
|
||||
DEFPRINT(AST.If, function(self, output) {
|
||||
output.print("if");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
|
|
@ -1075,7 +1097,7 @@ function OutputStream(options) {
|
|||
output.space();
|
||||
output.print("else");
|
||||
output.space();
|
||||
if (self.alternative instanceof AST_If)
|
||||
if (self.alternative instanceof AST.If)
|
||||
self.alternative.print(output);
|
||||
else
|
||||
force_statement(self.alternative, output);
|
||||
|
|
@ -1085,7 +1107,7 @@ function OutputStream(options) {
|
|||
});
|
||||
|
||||
/* -----[ switch ]----- */
|
||||
DEFPRINT(AST_Switch, function(self, output) {
|
||||
DEFPRINT(AST.Switch, function(self, output) {
|
||||
output.print("switch");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
|
|
@ -1103,7 +1125,7 @@ function OutputStream(options) {
|
|||
});
|
||||
});
|
||||
});
|
||||
AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) {
|
||||
AST.SwitchBranch.DEFMETHOD("_do_print_body", function(output) {
|
||||
output.newline();
|
||||
this.body.forEach(function(stmt) {
|
||||
output.indent();
|
||||
|
|
@ -1111,11 +1133,11 @@ function OutputStream(options) {
|
|||
output.newline();
|
||||
});
|
||||
});
|
||||
DEFPRINT(AST_Default, function(self, output) {
|
||||
DEFPRINT(AST.Default, function(self, output) {
|
||||
output.print("default:");
|
||||
self._do_print_body(output);
|
||||
});
|
||||
DEFPRINT(AST_Case, function(self, output) {
|
||||
DEFPRINT(AST.Case, function(self, output) {
|
||||
output.print("case");
|
||||
output.space();
|
||||
self.expression.print(output);
|
||||
|
|
@ -1124,7 +1146,7 @@ function OutputStream(options) {
|
|||
});
|
||||
|
||||
/* -----[ exceptions ]----- */
|
||||
DEFPRINT(AST_Try, function(self, output) {
|
||||
DEFPRINT(AST.Try, function(self, output) {
|
||||
output.print("try");
|
||||
output.space();
|
||||
print_braced(self, output);
|
||||
|
|
@ -1137,7 +1159,7 @@ function OutputStream(options) {
|
|||
self.bfinally.print(output);
|
||||
}
|
||||
});
|
||||
DEFPRINT(AST_Catch, function(self, output) {
|
||||
DEFPRINT(AST.Catch, function(self, output) {
|
||||
output.print("catch");
|
||||
output.space();
|
||||
output.with_parens(function() {
|
||||
|
|
@ -1146,13 +1168,13 @@ function OutputStream(options) {
|
|||
output.space();
|
||||
print_braced(self, output);
|
||||
});
|
||||
DEFPRINT(AST_Finally, function(self, output) {
|
||||
DEFPRINT(AST.Finally, function(self, output) {
|
||||
output.print("finally");
|
||||
output.space();
|
||||
print_braced(self, output);
|
||||
});
|
||||
|
||||
DEFPRINT(AST_Var, function(self, output) {
|
||||
DEFPRINT(AST.Var, function(self, output) {
|
||||
output.print("var");
|
||||
output.space();
|
||||
self.definitions.forEach(function(def, i) {
|
||||
|
|
@ -1160,7 +1182,7 @@ function OutputStream(options) {
|
|||
def.print(output);
|
||||
});
|
||||
var p = output.parent();
|
||||
if (p.init !== self || !(p instanceof AST_For || p instanceof AST_ForIn)) output.semicolon();
|
||||
if (p.init !== self || !(p instanceof AST.For || p instanceof AST.ForIn)) output.semicolon();
|
||||
});
|
||||
|
||||
function parenthesize_for_noin(node, output, noin) {
|
||||
|
|
@ -1168,8 +1190,8 @@ function OutputStream(options) {
|
|||
// need to take some precautions here:
|
||||
// https://github.com/mishoo/UglifyJS2/issues/60
|
||||
if (noin) node.walk(new TreeWalker(function(node) {
|
||||
if (parens || node instanceof AST_Scope) return true;
|
||||
if (node instanceof AST_Binary && node.operator == "in") {
|
||||
if (parens || node instanceof AST.Scope) return true;
|
||||
if (node instanceof AST.Binary && node.operator == "in") {
|
||||
parens = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1177,24 +1199,24 @@ function OutputStream(options) {
|
|||
node.print(output, parens);
|
||||
}
|
||||
|
||||
DEFPRINT(AST_VarDef, function(self, output) {
|
||||
DEFPRINT(AST.VarDef, function(self, output) {
|
||||
self.name.print(output);
|
||||
if (self.value) {
|
||||
output.space();
|
||||
output.print("=");
|
||||
output.space();
|
||||
var p = output.parent(1);
|
||||
var noin = p instanceof AST_For || p instanceof AST_ForIn;
|
||||
var noin = p instanceof AST.For || p instanceof AST.ForIn;
|
||||
parenthesize_for_noin(self.value, output, noin);
|
||||
}
|
||||
});
|
||||
|
||||
/* -----[ other expressions ]----- */
|
||||
DEFPRINT(AST_Call, function(self, output) {
|
||||
DEFPRINT(AST.Call, function(self, output) {
|
||||
self.expression.print(output);
|
||||
if (self instanceof AST_New && !need_constructor_parens(self, output))
|
||||
if (self instanceof AST.New && !need_constructor_parens(self, output))
|
||||
return;
|
||||
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
|
||||
if (self.expression instanceof AST.Call || self.expression instanceof AST.Lambda) {
|
||||
output.add_mapping(self.start);
|
||||
}
|
||||
output.with_parens(function() {
|
||||
|
|
@ -1204,12 +1226,12 @@ function OutputStream(options) {
|
|||
});
|
||||
});
|
||||
});
|
||||
DEFPRINT(AST_New, function(self, output) {
|
||||
DEFPRINT(AST.New, function(self, output) {
|
||||
output.print("new");
|
||||
output.space();
|
||||
AST_Call.prototype._codegen(self, output);
|
||||
AST.Call.prototype._codegen(self, output);
|
||||
});
|
||||
DEFPRINT(AST_Sequence, function(self, output) {
|
||||
DEFPRINT(AST.Sequence, function(self, output) {
|
||||
self.expressions.forEach(function(node, index) {
|
||||
if (index > 0) {
|
||||
output.comma();
|
||||
|
|
@ -1221,7 +1243,7 @@ function OutputStream(options) {
|
|||
node.print(output);
|
||||
});
|
||||
});
|
||||
DEFPRINT(AST_Dot, function(self, output) {
|
||||
DEFPRINT(AST.Dot, function(self, output) {
|
||||
var expr = self.expression;
|
||||
expr.print(output);
|
||||
var prop = self.property;
|
||||
|
|
@ -1231,7 +1253,7 @@ function OutputStream(options) {
|
|||
output.print_string(prop);
|
||||
output.print("]");
|
||||
} else {
|
||||
if (expr instanceof AST_Number && expr.getValue() >= 0) {
|
||||
if (expr instanceof AST.Number && expr.getValue() >= 0) {
|
||||
if (!/[xa-f.)]/i.test(output.last())) {
|
||||
output.print(".");
|
||||
}
|
||||
|
|
@ -1242,32 +1264,32 @@ function OutputStream(options) {
|
|||
output.print_name(prop);
|
||||
}
|
||||
});
|
||||
DEFPRINT(AST_Sub, function(self, output) {
|
||||
DEFPRINT(AST.Sub, function(self, output) {
|
||||
self.expression.print(output);
|
||||
output.print("[");
|
||||
self.property.print(output);
|
||||
output.print("]");
|
||||
});
|
||||
DEFPRINT(AST_UnaryPrefix, function(self, output) {
|
||||
DEFPRINT(AST.UnaryPrefix, function(self, output) {
|
||||
var op = self.operator;
|
||||
output.print(op);
|
||||
if (/^[a-z]/i.test(op)
|
||||
|| (/[+-]$/.test(op)
|
||||
&& self.expression instanceof AST_UnaryPrefix
|
||||
&& self.expression instanceof AST.UnaryPrefix
|
||||
&& /^[+-]/.test(self.expression.operator))) {
|
||||
output.space();
|
||||
}
|
||||
self.expression.print(output);
|
||||
});
|
||||
DEFPRINT(AST_UnaryPostfix, function(self, output) {
|
||||
DEFPRINT(AST.UnaryPostfix, function(self, output) {
|
||||
self.expression.print(output);
|
||||
output.print(self.operator);
|
||||
});
|
||||
DEFPRINT(AST_Binary, function(self, output) {
|
||||
DEFPRINT(AST.Binary, function(self, output) {
|
||||
var op = self.operator;
|
||||
self.left.print(output);
|
||||
if (op[0] == ">" /* ">>" ">>>" ">" ">=" */
|
||||
&& self.left instanceof AST_UnaryPostfix
|
||||
&& self.left instanceof AST.UnaryPostfix
|
||||
&& self.left.operator == "--") {
|
||||
// space is mandatory to avoid outputting -->
|
||||
output.print(" ");
|
||||
|
|
@ -1277,9 +1299,9 @@ function OutputStream(options) {
|
|||
}
|
||||
output.print(op);
|
||||
if ((op == "<" || op == "<<")
|
||||
&& self.right instanceof AST_UnaryPrefix
|
||||
&& self.right instanceof AST.UnaryPrefix
|
||||
&& self.right.operator == "!"
|
||||
&& self.right.expression instanceof AST_UnaryPrefix
|
||||
&& self.right.expression instanceof AST.UnaryPrefix
|
||||
&& self.right.expression.operator == "--") {
|
||||
// space is mandatory to avoid outputting <!--
|
||||
output.print(" ");
|
||||
|
|
@ -1289,7 +1311,7 @@ function OutputStream(options) {
|
|||
}
|
||||
self.right.print(output);
|
||||
});
|
||||
DEFPRINT(AST_Conditional, function(self, output) {
|
||||
DEFPRINT(AST.Conditional, function(self, output) {
|
||||
self.condition.print(output);
|
||||
output.space();
|
||||
output.print("?");
|
||||
|
|
@ -1301,7 +1323,7 @@ function OutputStream(options) {
|
|||
});
|
||||
|
||||
/* -----[ literals ]----- */
|
||||
DEFPRINT(AST_Array, function(self, output) {
|
||||
DEFPRINT(AST.Array, function(self, output) {
|
||||
output.with_square(function() {
|
||||
var a = self.elements, len = a.length;
|
||||
if (len > 0) output.space();
|
||||
|
|
@ -1311,13 +1333,13 @@ function OutputStream(options) {
|
|||
// If the final element is a hole, we need to make sure it
|
||||
// doesn't look like a trailing comma, by inserting an actual
|
||||
// trailing comma.
|
||||
if (i === len - 1 && exp instanceof AST_Hole)
|
||||
if (i === len - 1 && exp instanceof AST.Hole)
|
||||
output.comma();
|
||||
});
|
||||
if (len > 0) output.space();
|
||||
});
|
||||
});
|
||||
DEFPRINT(AST_Object, function(self, output) {
|
||||
DEFPRINT(AST.Object, function(self, output) {
|
||||
if (self.properties.length > 0) output.with_block(function() {
|
||||
self.properties.forEach(function(prop, i) {
|
||||
if (i) {
|
||||
|
|
@ -1337,7 +1359,7 @@ function OutputStream(options) {
|
|||
output.print_string(key);
|
||||
} else if ("" + +key == key && key >= 0) {
|
||||
output.print(make_num(key));
|
||||
} else if (RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
|
||||
} else if (parse.RESERVED_WORDS[key] ? !output.option("ie8") : is_identifier_string(key)) {
|
||||
if (quote && output.option("keep_quoted_props")) {
|
||||
output.print_string(key, quote);
|
||||
} else {
|
||||
|
|
@ -1348,38 +1370,38 @@ function OutputStream(options) {
|
|||
}
|
||||
}
|
||||
|
||||
DEFPRINT(AST_ObjectKeyVal, function(self, output) {
|
||||
DEFPRINT(AST.ObjectKeyVal, function(self, output) {
|
||||
print_property_name(self.key, self.quote, output);
|
||||
output.colon();
|
||||
self.value.print(output);
|
||||
});
|
||||
AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, output) {
|
||||
AST.ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, output) {
|
||||
output.print(type);
|
||||
output.space();
|
||||
print_property_name(this.key.name, this.quote, output);
|
||||
this.value._do_print(output, true);
|
||||
});
|
||||
DEFPRINT(AST_ObjectSetter, function(self, output) {
|
||||
DEFPRINT(AST.ObjectSetter, function(self, output) {
|
||||
self._print_getter_setter("set", output);
|
||||
});
|
||||
DEFPRINT(AST_ObjectGetter, function(self, output) {
|
||||
DEFPRINT(AST.ObjectGetter, function(self, output) {
|
||||
self._print_getter_setter("get", output);
|
||||
});
|
||||
DEFPRINT(AST_Symbol, function(self, output) {
|
||||
DEFPRINT(AST.Symbol, function(self, output) {
|
||||
var def = self.definition();
|
||||
output.print_name(def ? def.mangled_name || def.name : self.name);
|
||||
});
|
||||
DEFPRINT(AST_Hole, noop);
|
||||
DEFPRINT(AST_This, function(self, output) {
|
||||
DEFPRINT(AST.Hole, noop);
|
||||
DEFPRINT(AST.This, function(self, output) {
|
||||
output.print("this");
|
||||
});
|
||||
DEFPRINT(AST_Constant, function(self, output) {
|
||||
DEFPRINT(AST.Constant, function(self, output) {
|
||||
output.print(self.getValue());
|
||||
});
|
||||
DEFPRINT(AST_String, function(self, output) {
|
||||
DEFPRINT(AST.String, function(self, output) {
|
||||
output.print_string(self.getValue(), self.quote, in_directive);
|
||||
});
|
||||
DEFPRINT(AST_Number, function(self, output) {
|
||||
DEFPRINT(AST.Number, function(self, output) {
|
||||
if (use_asm && self.start && self.start.raw != null) {
|
||||
output.print(self.start.raw);
|
||||
} else {
|
||||
|
|
@ -1387,7 +1409,7 @@ function OutputStream(options) {
|
|||
}
|
||||
});
|
||||
|
||||
DEFPRINT(AST_RegExp, function(self, output) {
|
||||
DEFPRINT(AST.RegExp, function(self, output) {
|
||||
var regexp = self.getValue();
|
||||
var str = regexp.toString();
|
||||
if (regexp.raw_source) {
|
||||
|
|
@ -1396,7 +1418,7 @@ function OutputStream(options) {
|
|||
str = output.to_utf8(str);
|
||||
output.print(str);
|
||||
var p = output.parent();
|
||||
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
|
||||
if (p instanceof AST.Binary && /^in/.test(p.operator) && p.left === self)
|
||||
output.print(" ");
|
||||
});
|
||||
|
||||
|
|
@ -1404,14 +1426,14 @@ function OutputStream(options) {
|
|||
if (output.option("braces")) {
|
||||
make_block(stat, output);
|
||||
} else {
|
||||
if (!stat || stat instanceof AST_EmptyStatement)
|
||||
if (!stat || stat instanceof AST.EmptyStatement)
|
||||
output.force_semicolon();
|
||||
else
|
||||
stat.print(output);
|
||||
}
|
||||
}
|
||||
|
||||
// self should be AST_New. decide if we want to show parens or not.
|
||||
// self should be AST.New. decide if we want to show parens or not.
|
||||
function need_constructor_parens(self, output) {
|
||||
// Always print parentheses with arguments
|
||||
if (self.args.length > 0) return true;
|
||||
|
|
@ -1455,9 +1477,9 @@ function OutputStream(options) {
|
|||
}
|
||||
|
||||
function make_block(stmt, output) {
|
||||
if (!stmt || stmt instanceof AST_EmptyStatement)
|
||||
if (!stmt || stmt instanceof AST.EmptyStatement)
|
||||
output.print("{}");
|
||||
else if (stmt instanceof AST_BlockStatement)
|
||||
else if (stmt instanceof AST.BlockStatement)
|
||||
stmt.print(output);
|
||||
else output.with_block(function() {
|
||||
output.indent();
|
||||
|
|
@ -1477,44 +1499,50 @@ function OutputStream(options) {
|
|||
DEFMAP([
|
||||
// We could easily add info for ALL nodes, but it seems to me that
|
||||
// would be quite wasteful, hence this noop in the base class.
|
||||
AST_Node,
|
||||
AST.Node,
|
||||
// since the label symbol will mark it
|
||||
AST_LabeledStatement,
|
||||
AST_Toplevel,
|
||||
AST.LabeledStatement,
|
||||
AST.Toplevel,
|
||||
], noop);
|
||||
|
||||
// XXX: I'm not exactly sure if we need it for all of these nodes,
|
||||
// or if we should add even more.
|
||||
DEFMAP([
|
||||
AST_Array,
|
||||
AST_BlockStatement,
|
||||
AST_Catch,
|
||||
AST_Constant,
|
||||
AST_Debugger,
|
||||
AST_Definitions,
|
||||
AST_Directive,
|
||||
AST_Finally,
|
||||
AST_Jump,
|
||||
AST_Lambda,
|
||||
AST_New,
|
||||
AST_Object,
|
||||
AST_StatementWithBody,
|
||||
AST_Symbol,
|
||||
AST_Switch,
|
||||
AST_SwitchBranch,
|
||||
AST_Try,
|
||||
AST.Array,
|
||||
AST.BlockStatement,
|
||||
AST.Catch,
|
||||
AST.Constant,
|
||||
AST.Debugger,
|
||||
AST.Definitions,
|
||||
AST.Directive,
|
||||
AST.Finally,
|
||||
AST.Jump,
|
||||
AST.Lambda,
|
||||
AST.New,
|
||||
AST.Object,
|
||||
AST.StatementWithBody,
|
||||
AST.Symbol,
|
||||
AST.Switch,
|
||||
AST.SwitchBranch,
|
||||
AST.Try,
|
||||
], function(output) {
|
||||
output.add_mapping(this.start);
|
||||
});
|
||||
|
||||
DEFMAP([
|
||||
AST_ObjectGetter,
|
||||
AST_ObjectSetter,
|
||||
AST.ObjectGetter,
|
||||
AST.ObjectSetter,
|
||||
], function(output) {
|
||||
output.add_mapping(this.start, this.key.name);
|
||||
});
|
||||
|
||||
DEFMAP([ AST_ObjectProperty ], function(output) {
|
||||
DEFMAP([ AST.ObjectProperty ], function(output) {
|
||||
output.add_mapping(this.start, this.key);
|
||||
});
|
||||
})();
|
||||
|
||||
merge(exports, {
|
||||
EXPECT_DIRECTIVE : EXPECT_DIRECTIVE,
|
||||
is_some_comments : is_some_comments,
|
||||
OutputStream : OutputStream,
|
||||
});
|
||||
|
|
|
|||
190
lib/parse.js
190
lib/parse.js
|
|
@ -44,6 +44,18 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var utils = require("./utils");
|
||||
var characters = utils.characters;
|
||||
var find_if = utils.find_if;
|
||||
var configure_error_stack = utils.configure_error_stack;
|
||||
var defaults = utils.defaults;
|
||||
var makePredicate = utils.makePredicate;
|
||||
var all = utils.all;
|
||||
var HOP = utils.HOP;
|
||||
var merge = utils.merge;
|
||||
|
||||
var AST = require("./ast");
|
||||
|
||||
var KEYWORDS = 'break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with';
|
||||
var KEYWORDS_ATOM = 'false null true';
|
||||
var RESERVED_WORDS = 'abstract boolean byte char class double enum export extends final float goto implements import int interface let long native package private protected public short static super synchronized this throws transient volatile yield'
|
||||
|
|
@ -322,7 +334,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||
ret.comments_after = S.comments_before = [];
|
||||
}
|
||||
S.newline_before = false;
|
||||
return new AST_Token(ret);
|
||||
return new AST.Token(ret);
|
||||
}
|
||||
|
||||
function skip_whitespace() {
|
||||
|
|
@ -833,7 +845,7 @@ function parse($TEXT, options) {
|
|||
}
|
||||
}
|
||||
var dir = S.in_directives, stat = simple_statement();
|
||||
return dir ? new AST_Directive(stat.body) : stat;
|
||||
return dir ? new AST.Directive(stat.body) : stat;
|
||||
case "num":
|
||||
case "regexp":
|
||||
case "operator":
|
||||
|
|
@ -848,7 +860,7 @@ function parse($TEXT, options) {
|
|||
case "punc":
|
||||
switch (S.token.value) {
|
||||
case "{":
|
||||
return new AST_BlockStatement({
|
||||
return new AST.BlockStatement({
|
||||
start : S.token,
|
||||
body : block_(),
|
||||
end : prev()
|
||||
|
|
@ -859,7 +871,7 @@ function parse($TEXT, options) {
|
|||
case ";":
|
||||
S.in_directives = false;
|
||||
next();
|
||||
return new AST_EmptyStatement();
|
||||
return new AST.EmptyStatement();
|
||||
default:
|
||||
unexpected();
|
||||
}
|
||||
|
|
@ -868,16 +880,16 @@ function parse($TEXT, options) {
|
|||
switch (S.token.value) {
|
||||
case "break":
|
||||
next();
|
||||
return break_cont(AST_Break);
|
||||
return break_cont(AST.Break);
|
||||
|
||||
case "continue":
|
||||
next();
|
||||
return break_cont(AST_Continue);
|
||||
return break_cont(AST.Continue);
|
||||
|
||||
case "debugger":
|
||||
next();
|
||||
semicolon();
|
||||
return new AST_Debugger();
|
||||
return new AST.Debugger();
|
||||
|
||||
case "do":
|
||||
next();
|
||||
|
|
@ -885,14 +897,14 @@ function parse($TEXT, options) {
|
|||
expect_token("keyword", "while");
|
||||
var condition = parenthesised();
|
||||
semicolon(true);
|
||||
return new AST_Do({
|
||||
return new AST.Do({
|
||||
body : body,
|
||||
condition : condition
|
||||
});
|
||||
|
||||
case "while":
|
||||
next();
|
||||
return new AST_While({
|
||||
return new AST.While({
|
||||
condition : parenthesised(),
|
||||
body : in_loop(statement)
|
||||
});
|
||||
|
|
@ -906,7 +918,7 @@ function parse($TEXT, options) {
|
|||
croak("In strict mode code, functions can only be declared at top level or immediately within another function.");
|
||||
}
|
||||
next();
|
||||
return function_(AST_Defun);
|
||||
return function_(AST.Defun);
|
||||
|
||||
case "if":
|
||||
next();
|
||||
|
|
@ -923,13 +935,13 @@ function parse($TEXT, options) {
|
|||
value = expression(true);
|
||||
semicolon();
|
||||
}
|
||||
return new AST_Return({
|
||||
return new AST.Return({
|
||||
value: value
|
||||
});
|
||||
|
||||
case "switch":
|
||||
next();
|
||||
return new AST_Switch({
|
||||
return new AST.Switch({
|
||||
expression : parenthesised(),
|
||||
body : in_loop(switch_body_)
|
||||
});
|
||||
|
|
@ -940,7 +952,7 @@ function parse($TEXT, options) {
|
|||
croak("Illegal newline after 'throw'");
|
||||
var value = expression(true);
|
||||
semicolon();
|
||||
return new AST_Throw({
|
||||
return new AST.Throw({
|
||||
value: value
|
||||
});
|
||||
|
||||
|
|
@ -959,7 +971,7 @@ function parse($TEXT, options) {
|
|||
croak("Strict mode may not include a with statement");
|
||||
}
|
||||
next();
|
||||
return new AST_With({
|
||||
return new AST.With({
|
||||
expression : parenthesised(),
|
||||
body : statement()
|
||||
});
|
||||
|
|
@ -969,7 +981,7 @@ function parse($TEXT, options) {
|
|||
});
|
||||
|
||||
function labeled_statement() {
|
||||
var label = as_symbol(AST_Label);
|
||||
var label = as_symbol(AST.Label);
|
||||
if (!all(S.labels, function(l) {
|
||||
return l.name != label.name;
|
||||
})) {
|
||||
|
|
@ -983,29 +995,29 @@ function parse($TEXT, options) {
|
|||
S.labels.push(label);
|
||||
var stat = statement();
|
||||
S.labels.pop();
|
||||
if (!(stat instanceof AST_IterationStatement)) {
|
||||
if (!(stat instanceof AST.IterationStatement)) {
|
||||
// check for `continue` that refers to this label.
|
||||
// those should be reported as syntax errors.
|
||||
// https://github.com/mishoo/UglifyJS2/issues/287
|
||||
label.references.forEach(function(ref) {
|
||||
if (ref instanceof AST_Continue) {
|
||||
if (ref instanceof AST.Continue) {
|
||||
ref = ref.label.start;
|
||||
croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
|
||||
ref.line, ref.col, ref.pos);
|
||||
}
|
||||
});
|
||||
}
|
||||
return new AST_LabeledStatement({ body: stat, label: label });
|
||||
return new AST.LabeledStatement({ body: stat, label: label });
|
||||
}
|
||||
|
||||
function simple_statement(tmp) {
|
||||
return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) });
|
||||
return new AST.SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) });
|
||||
}
|
||||
|
||||
function break_cont(type) {
|
||||
var label = null, ldef;
|
||||
if (!can_insert_semicolon()) {
|
||||
label = as_symbol(AST_LabelRef, true);
|
||||
label = as_symbol(AST.LabelRef, true);
|
||||
}
|
||||
if (label != null) {
|
||||
ldef = find_if(function(l) {
|
||||
|
|
@ -1028,7 +1040,7 @@ function parse($TEXT, options) {
|
|||
? (next(), var_(true))
|
||||
: expression(true, true);
|
||||
if (is("operator", "in")) {
|
||||
if (init instanceof AST_Var) {
|
||||
if (init instanceof AST.Var) {
|
||||
if (init.definitions.length > 1)
|
||||
croak("Only one variable declaration allowed in for..in loop", init.start.line, init.start.col, init.start.pos);
|
||||
} else if (!is_assignable(init)) {
|
||||
|
|
@ -1047,7 +1059,7 @@ function parse($TEXT, options) {
|
|||
expect(";");
|
||||
var step = is("punc", ")") ? null : expression(true);
|
||||
expect(")");
|
||||
return new AST_For({
|
||||
return new AST.For({
|
||||
init : init,
|
||||
condition : test,
|
||||
step : step,
|
||||
|
|
@ -1058,7 +1070,7 @@ function parse($TEXT, options) {
|
|||
function for_in(init) {
|
||||
var obj = expression(true);
|
||||
expect(")");
|
||||
return new AST_ForIn({
|
||||
return new AST.ForIn({
|
||||
init : init,
|
||||
object : obj,
|
||||
body : in_loop(statement)
|
||||
|
|
@ -1066,17 +1078,17 @@ function parse($TEXT, options) {
|
|||
}
|
||||
|
||||
var function_ = function(ctor) {
|
||||
var in_statement = ctor === AST_Defun;
|
||||
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
|
||||
var in_statement = ctor === AST.Defun;
|
||||
var name = is("name") ? as_symbol(in_statement ? AST.SymbolDefun : AST.SymbolLambda) : null;
|
||||
if (in_statement && !name)
|
||||
unexpected();
|
||||
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
|
||||
if (name && ctor !== AST.Accessor && !(name instanceof AST.SymbolDeclaration))
|
||||
unexpected(prev());
|
||||
expect("(");
|
||||
var argnames = [];
|
||||
for (var first = true; !is("punc", ")");) {
|
||||
if (first) first = false; else expect(",");
|
||||
argnames.push(as_symbol(AST_SymbolFunarg));
|
||||
argnames.push(as_symbol(AST.SymbolFunarg));
|
||||
}
|
||||
next();
|
||||
var loop = S.in_loop;
|
||||
|
|
@ -1108,7 +1120,7 @@ function parse($TEXT, options) {
|
|||
next();
|
||||
belse = statement();
|
||||
}
|
||||
return new AST_If({
|
||||
return new AST.If({
|
||||
condition : cond,
|
||||
body : body,
|
||||
alternative : belse
|
||||
|
|
@ -1134,7 +1146,7 @@ function parse($TEXT, options) {
|
|||
if (is("keyword", "case")) {
|
||||
if (branch) branch.end = prev();
|
||||
cur = [];
|
||||
branch = new AST_Case({
|
||||
branch = new AST.Case({
|
||||
start : (tmp = S.token, next(), tmp),
|
||||
expression : expression(true),
|
||||
body : cur
|
||||
|
|
@ -1145,7 +1157,7 @@ function parse($TEXT, options) {
|
|||
else if (is("keyword", "default")) {
|
||||
if (branch) branch.end = prev();
|
||||
cur = [];
|
||||
branch = new AST_Default({
|
||||
branch = new AST.Default({
|
||||
start : (tmp = S.token, next(), expect(":"), tmp),
|
||||
body : cur
|
||||
});
|
||||
|
|
@ -1167,9 +1179,9 @@ function parse($TEXT, options) {
|
|||
var start = S.token;
|
||||
next();
|
||||
expect("(");
|
||||
var name = as_symbol(AST_SymbolCatch);
|
||||
var name = as_symbol(AST.SymbolCatch);
|
||||
expect(")");
|
||||
bcatch = new AST_Catch({
|
||||
bcatch = new AST.Catch({
|
||||
start : start,
|
||||
argname : name,
|
||||
body : block_(),
|
||||
|
|
@ -1179,7 +1191,7 @@ function parse($TEXT, options) {
|
|||
if (is("keyword", "finally")) {
|
||||
var start = S.token;
|
||||
next();
|
||||
bfinally = new AST_Finally({
|
||||
bfinally = new AST.Finally({
|
||||
start : start,
|
||||
body : block_(),
|
||||
end : prev()
|
||||
|
|
@ -1187,7 +1199,7 @@ function parse($TEXT, options) {
|
|||
}
|
||||
if (!bcatch && !bfinally)
|
||||
croak("Missing catch/finally blocks");
|
||||
return new AST_Try({
|
||||
return new AST.Try({
|
||||
body : body,
|
||||
bcatch : bcatch,
|
||||
bfinally : bfinally
|
||||
|
|
@ -1197,9 +1209,9 @@ function parse($TEXT, options) {
|
|||
function vardefs(no_in) {
|
||||
var a = [];
|
||||
for (;;) {
|
||||
a.push(new AST_VarDef({
|
||||
a.push(new AST.VarDef({
|
||||
start : S.token,
|
||||
name : as_symbol(AST_SymbolVar),
|
||||
name : as_symbol(AST.SymbolVar),
|
||||
value : is("operator", "=") ? (next(), expression(false, no_in)) : null,
|
||||
end : prev()
|
||||
}));
|
||||
|
|
@ -1211,7 +1223,7 @@ function parse($TEXT, options) {
|
|||
}
|
||||
|
||||
var var_ = function(no_in) {
|
||||
return new AST_Var({
|
||||
return new AST.Var({
|
||||
start : prev(),
|
||||
definitions : vardefs(no_in),
|
||||
end : prev()
|
||||
|
|
@ -1228,7 +1240,7 @@ function parse($TEXT, options) {
|
|||
} else {
|
||||
args = [];
|
||||
}
|
||||
var call = new AST_New({
|
||||
var call = new AST.New({
|
||||
start : start,
|
||||
expression : newexp,
|
||||
args : args,
|
||||
|
|
@ -1242,13 +1254,13 @@ function parse($TEXT, options) {
|
|||
var tok = S.token, ret;
|
||||
switch (tok.type) {
|
||||
case "name":
|
||||
ret = _make_symbol(AST_SymbolRef);
|
||||
ret = _make_symbol(AST.SymbolRef);
|
||||
break;
|
||||
case "num":
|
||||
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
||||
ret = new AST.Number({ start: tok, end: tok, value: tok.value });
|
||||
break;
|
||||
case "string":
|
||||
ret = new AST_String({
|
||||
ret = new AST.String({
|
||||
start : tok,
|
||||
end : tok,
|
||||
value : tok.value,
|
||||
|
|
@ -1256,18 +1268,18 @@ function parse($TEXT, options) {
|
|||
});
|
||||
break;
|
||||
case "regexp":
|
||||
ret = new AST_RegExp({ start: tok, end: tok, value: tok.value });
|
||||
ret = new AST.RegExp({ start: tok, end: tok, value: tok.value });
|
||||
break;
|
||||
case "atom":
|
||||
switch (tok.value) {
|
||||
case "false":
|
||||
ret = new AST_False({ start: tok, end: tok });
|
||||
ret = new AST.False({ start: tok, end: tok });
|
||||
break;
|
||||
case "true":
|
||||
ret = new AST_True({ start: tok, end: tok });
|
||||
ret = new AST.True({ start: tok, end: tok });
|
||||
break;
|
||||
case "null":
|
||||
ret = new AST_Null({ start: tok, end: tok });
|
||||
ret = new AST.Null({ start: tok, end: tok });
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
@ -1305,7 +1317,7 @@ function parse($TEXT, options) {
|
|||
[].push.apply(ex.end.comments_after, end.comments_after);
|
||||
end.comments_after = ex.end.comments_after;
|
||||
ex.end = end;
|
||||
if (ex instanceof AST_Call) mark_pure(ex);
|
||||
if (ex instanceof AST.Call) mark_pure(ex);
|
||||
return subscripts(ex, allow_calls);
|
||||
case "[":
|
||||
return subscripts(array_(), allow_calls);
|
||||
|
|
@ -1316,7 +1328,7 @@ function parse($TEXT, options) {
|
|||
}
|
||||
if (is("keyword", "function")) {
|
||||
next();
|
||||
var func = function_(AST_Function);
|
||||
var func = function_(AST.Function);
|
||||
func.start = start;
|
||||
func.end = prev();
|
||||
return subscripts(func, allow_calls);
|
||||
|
|
@ -1333,7 +1345,7 @@ function parse($TEXT, options) {
|
|||
if (first) first = false; else expect(",");
|
||||
if (allow_trailing_comma && is("punc", closing)) break;
|
||||
if (is("punc", ",") && allow_empty) {
|
||||
a.push(new AST_Hole({ start: S.token, end: S.token }));
|
||||
a.push(new AST.Hole({ start: S.token, end: S.token }));
|
||||
} else {
|
||||
a.push(expression(false));
|
||||
}
|
||||
|
|
@ -1344,13 +1356,13 @@ function parse($TEXT, options) {
|
|||
|
||||
var array_ = embed_tokens(function() {
|
||||
expect("[");
|
||||
return new AST_Array({
|
||||
return new AST.Array({
|
||||
elements: expr_list("]", !options.strict, true)
|
||||
});
|
||||
});
|
||||
|
||||
var create_accessor = embed_tokens(function() {
|
||||
return function_(AST_Accessor);
|
||||
return function_(AST.Accessor);
|
||||
});
|
||||
|
||||
var object_ = embed_tokens(function() {
|
||||
|
|
@ -1365,13 +1377,13 @@ function parse($TEXT, options) {
|
|||
var type = start.type;
|
||||
var name = as_property_name();
|
||||
if (type == "name" && !is("punc", ":")) {
|
||||
var key = new AST_SymbolAccessor({
|
||||
var key = new AST.SymbolAccessor({
|
||||
start: S.token,
|
||||
name: "" + as_property_name(),
|
||||
end: prev()
|
||||
});
|
||||
if (name == "get") {
|
||||
a.push(new AST_ObjectGetter({
|
||||
a.push(new AST.ObjectGetter({
|
||||
start : start,
|
||||
key : key,
|
||||
value : create_accessor(),
|
||||
|
|
@ -1380,7 +1392,7 @@ function parse($TEXT, options) {
|
|||
continue;
|
||||
}
|
||||
if (name == "set") {
|
||||
a.push(new AST_ObjectSetter({
|
||||
a.push(new AST.ObjectSetter({
|
||||
start : start,
|
||||
key : key,
|
||||
value : create_accessor(),
|
||||
|
|
@ -1390,7 +1402,7 @@ function parse($TEXT, options) {
|
|||
}
|
||||
}
|
||||
expect(":");
|
||||
a.push(new AST_ObjectKeyVal({
|
||||
a.push(new AST.ObjectKeyVal({
|
||||
start : start,
|
||||
quote : start.quote,
|
||||
key : "" + name,
|
||||
|
|
@ -1399,7 +1411,7 @@ function parse($TEXT, options) {
|
|||
}));
|
||||
}
|
||||
next();
|
||||
return new AST_Object({ properties: a });
|
||||
return new AST.Object({ properties: a });
|
||||
});
|
||||
|
||||
function as_property_name() {
|
||||
|
|
@ -1428,7 +1440,7 @@ function parse($TEXT, options) {
|
|||
|
||||
function _make_symbol(type) {
|
||||
var name = S.token.value;
|
||||
return new (name == "this" ? AST_This : type)({
|
||||
return new (name == "this" ? AST.This : type)({
|
||||
name : String(name),
|
||||
start : S.token,
|
||||
end : S.token
|
||||
|
|
@ -1446,7 +1458,7 @@ function parse($TEXT, options) {
|
|||
return null;
|
||||
}
|
||||
var sym = _make_symbol(type);
|
||||
if (S.input.has_directive("use strict") && sym instanceof AST_SymbolDeclaration) {
|
||||
if (S.input.has_directive("use strict") && sym instanceof AST.SymbolDeclaration) {
|
||||
strict_verify_symbol(sym);
|
||||
}
|
||||
next();
|
||||
|
|
@ -1470,7 +1482,7 @@ function parse($TEXT, options) {
|
|||
var start = expr.start;
|
||||
if (is("punc", ".")) {
|
||||
next();
|
||||
return subscripts(new AST_Dot({
|
||||
return subscripts(new AST.Dot({
|
||||
start : start,
|
||||
expression : expr,
|
||||
property : as_name(),
|
||||
|
|
@ -1481,7 +1493,7 @@ function parse($TEXT, options) {
|
|||
next();
|
||||
var prop = expression(true);
|
||||
expect("]");
|
||||
return subscripts(new AST_Sub({
|
||||
return subscripts(new AST.Sub({
|
||||
start : start,
|
||||
expression : expr,
|
||||
property : prop,
|
||||
|
|
@ -1490,7 +1502,7 @@ function parse($TEXT, options) {
|
|||
}
|
||||
if (allow_calls && is("punc", "(")) {
|
||||
next();
|
||||
var call = new AST_Call({
|
||||
var call = new AST.Call({
|
||||
start : start,
|
||||
expression : expr,
|
||||
args : expr_list(")"),
|
||||
|
|
@ -1507,14 +1519,14 @@ function parse($TEXT, options) {
|
|||
if (is("operator") && UNARY_PREFIX[start.value]) {
|
||||
next();
|
||||
handle_regexp();
|
||||
var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(allow_calls));
|
||||
var ex = make_unary(AST.UnaryPrefix, start, maybe_unary(allow_calls));
|
||||
ex.start = start;
|
||||
ex.end = prev();
|
||||
return ex;
|
||||
}
|
||||
var val = expr_atom(allow_calls);
|
||||
while (is("operator") && UNARY_POSTFIX[S.token.value] && !has_newline_before(S.token)) {
|
||||
val = make_unary(AST_UnaryPostfix, S.token, val);
|
||||
val = make_unary(AST.UnaryPostfix, S.token, val);
|
||||
val.start = start;
|
||||
val.end = S.token;
|
||||
next();
|
||||
|
|
@ -1531,7 +1543,7 @@ function parse($TEXT, options) {
|
|||
croak("Invalid use of " + op + " operator", token.line, token.col, token.pos);
|
||||
break;
|
||||
case "delete":
|
||||
if (expr instanceof AST_SymbolRef && S.input.has_directive("use strict"))
|
||||
if (expr instanceof AST.SymbolRef && S.input.has_directive("use strict"))
|
||||
croak("Calling delete on expression not allowed in strict mode", expr.start.line, expr.start.col, expr.start.pos);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1545,7 +1557,7 @@ function parse($TEXT, options) {
|
|||
if (prec != null && prec > min_prec) {
|
||||
next();
|
||||
var right = expr_op(maybe_unary(true), prec, no_in);
|
||||
return expr_op(new AST_Binary({
|
||||
return expr_op(new AST.Binary({
|
||||
start : left.start,
|
||||
left : left,
|
||||
operator : op,
|
||||
|
|
@ -1567,7 +1579,7 @@ function parse($TEXT, options) {
|
|||
next();
|
||||
var yes = expression(false);
|
||||
expect(":");
|
||||
return new AST_Conditional({
|
||||
return new AST.Conditional({
|
||||
start : start,
|
||||
condition : expr,
|
||||
consequent : yes,
|
||||
|
|
@ -1579,7 +1591,7 @@ function parse($TEXT, options) {
|
|||
};
|
||||
|
||||
function is_assignable(expr) {
|
||||
return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
|
||||
return expr instanceof AST.PropAccess || expr instanceof AST.SymbolRef;
|
||||
}
|
||||
|
||||
var maybe_assign = function(no_in) {
|
||||
|
|
@ -1588,7 +1600,7 @@ function parse($TEXT, options) {
|
|||
if (is("operator") && ASSIGNMENT[val]) {
|
||||
if (is_assignable(left)) {
|
||||
next();
|
||||
return new AST_Assign({
|
||||
return new AST.Assign({
|
||||
start : start,
|
||||
left : left,
|
||||
operator : val,
|
||||
|
|
@ -1610,7 +1622,7 @@ function parse($TEXT, options) {
|
|||
next();
|
||||
commas = true;
|
||||
}
|
||||
return exprs.length == 1 ? exprs[0] : new AST_Sequence({
|
||||
return exprs.length == 1 ? exprs[0] : new AST.Sequence({
|
||||
start : start,
|
||||
expressions : exprs,
|
||||
end : peek()
|
||||
|
|
@ -1641,8 +1653,48 @@ function parse($TEXT, options) {
|
|||
toplevel.body = toplevel.body.concat(body);
|
||||
toplevel.end = end;
|
||||
} else {
|
||||
toplevel = new AST_Toplevel({ start: start, body: body, end: end });
|
||||
toplevel = new AST.Toplevel({ start: start, body: body, end: end });
|
||||
}
|
||||
return toplevel;
|
||||
}();
|
||||
}
|
||||
|
||||
merge(exports, {
|
||||
KEYWORDS : KEYWORDS,
|
||||
KEYWORDS_ATOM : KEYWORDS_ATOM,
|
||||
RESERVED_WORDS : RESERVED_WORDS,
|
||||
KEYWORDS_BEFORE_EXPRESSION : KEYWORDS_BEFORE_EXPRESSION,
|
||||
OPERATOR_CHARS : OPERATOR_CHARS,
|
||||
RE_HEX_NUMBER : RE_HEX_NUMBER,
|
||||
RE_OCT_NUMBER : RE_OCT_NUMBER,
|
||||
OPERATORS : OPERATORS,
|
||||
WHITESPACE_CHARS : WHITESPACE_CHARS,
|
||||
NEWLINE_CHARS : NEWLINE_CHARS,
|
||||
PUNC_BEFORE_EXPRESSION : PUNC_BEFORE_EXPRESSION,
|
||||
PUNC_CHARS : PUNC_CHARS,
|
||||
UNICODE : UNICODE,
|
||||
is_letter : is_letter,
|
||||
is_surrogate_pair_head : is_surrogate_pair_head,
|
||||
is_surrogate_pair_tail : is_surrogate_pair_tail,
|
||||
is_digit : is_digit,
|
||||
is_alphanumeric_char : is_alphanumeric_char,
|
||||
is_unicode_digit : is_unicode_digit,
|
||||
is_unicode_combining_mark : is_unicode_combining_mark,
|
||||
is_unicode_connector_punctuation : is_unicode_connector_punctuation,
|
||||
is_identifier : is_identifier,
|
||||
is_identifier_start : is_identifier_start,
|
||||
is_identifier_char : is_identifier_char,
|
||||
is_identifier_string : is_identifier_string,
|
||||
parse_js_number : parse_js_number,
|
||||
JS_Parse_Error : JS_Parse_Error,
|
||||
js_error : js_error,
|
||||
is_token : is_token,
|
||||
EX_EOF : EX_EOF,
|
||||
tokenizer : tokenizer,
|
||||
UNARY_PREFIX : UNARY_PREFIX,
|
||||
UNARY_POSTFIX : UNARY_POSTFIX,
|
||||
ASSIGNMENT : ASSIGNMENT,
|
||||
PRECEDENCE : PRECEDENCE,
|
||||
ATOMIC_START_TOKEN : ATOMIC_START_TOKEN,
|
||||
parse : parse,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -43,6 +43,19 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var utils = require("./utils");
|
||||
var defaults = utils.defaults;
|
||||
var push_uniq = utils.push_uniq;
|
||||
var Dictionary = utils.Dictionary;
|
||||
var merge = utils.merge;
|
||||
|
||||
var scope = require("./scope");
|
||||
var base54 = scope.base54;
|
||||
|
||||
var AST = require("./ast");
|
||||
var TreeWalker = AST.TreeWalker;
|
||||
var TreeTransformer = AST.TreeTransformer;
|
||||
|
||||
function find_builtins(reserved) {
|
||||
// NaN will be included due to Number.NaN
|
||||
[
|
||||
|
|
@ -73,9 +86,9 @@ function reserve_quoted_keys(ast, reserved) {
|
|||
}
|
||||
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_ObjectKeyVal && node.quote) {
|
||||
if (node instanceof AST.ObjectKeyVal && node.quote) {
|
||||
add(node.key);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
} else if (node instanceof AST.Sub) {
|
||||
addStrings(node.property, add);
|
||||
}
|
||||
}));
|
||||
|
|
@ -83,11 +96,11 @@ function reserve_quoted_keys(ast, reserved) {
|
|||
|
||||
function addStrings(node, add) {
|
||||
node.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Sequence) {
|
||||
if (node instanceof AST.Sequence) {
|
||||
addStrings(node.tail_node(), add);
|
||||
} else if (node instanceof AST_String) {
|
||||
} else if (node instanceof AST.String) {
|
||||
add(node.value);
|
||||
} else if (node instanceof AST_Conditional) {
|
||||
} else if (node instanceof AST.Conditional) {
|
||||
addStrings(node.consequent, add);
|
||||
addStrings(node.alternative, add);
|
||||
}
|
||||
|
|
@ -137,20 +150,20 @@ function mangle_properties(ast, options) {
|
|||
|
||||
// step 1: find candidates to mangle
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_ObjectKeyVal) {
|
||||
if (node instanceof AST.ObjectKeyVal) {
|
||||
add(node.key);
|
||||
}
|
||||
else if (node instanceof AST_ObjectProperty) {
|
||||
else if (node instanceof AST.ObjectProperty) {
|
||||
// setter or getter, since KeyVal is handled above
|
||||
add(node.key.name);
|
||||
}
|
||||
else if (node instanceof AST_Dot) {
|
||||
else if (node instanceof AST.Dot) {
|
||||
add(node.property);
|
||||
}
|
||||
else if (node instanceof AST_Sub) {
|
||||
else if (node instanceof AST.Sub) {
|
||||
addStrings(node.property, add);
|
||||
}
|
||||
else if (node instanceof AST_Call
|
||||
else if (node instanceof AST.Call
|
||||
&& node.expression.print_to_string() == "Object.defineProperty") {
|
||||
addStrings(node.args[1], add);
|
||||
}
|
||||
|
|
@ -158,20 +171,20 @@ function mangle_properties(ast, options) {
|
|||
|
||||
// step 2: transform the tree, renaming properties
|
||||
return ast.transform(new TreeTransformer(function(node) {
|
||||
if (node instanceof AST_ObjectKeyVal) {
|
||||
if (node instanceof AST.ObjectKeyVal) {
|
||||
node.key = mangle(node.key);
|
||||
}
|
||||
else if (node instanceof AST_ObjectProperty) {
|
||||
else if (node instanceof AST.ObjectProperty) {
|
||||
// setter or getter
|
||||
node.key.name = mangle(node.key.name);
|
||||
}
|
||||
else if (node instanceof AST_Dot) {
|
||||
else if (node instanceof AST.Dot) {
|
||||
node.property = mangle(node.property);
|
||||
}
|
||||
else if (!options.keep_quoted && node instanceof AST_Sub) {
|
||||
else if (!options.keep_quoted && node instanceof AST.Sub) {
|
||||
node.property = mangleStrings(node.property);
|
||||
}
|
||||
else if (node instanceof AST_Call
|
||||
else if (node instanceof AST.Call
|
||||
&& node.expression.print_to_string() == "Object.defineProperty") {
|
||||
node.args[1] = mangleStrings(node.args[1]);
|
||||
}
|
||||
|
|
@ -235,14 +248,14 @@ function mangle_properties(ast, options) {
|
|||
|
||||
function mangleStrings(node) {
|
||||
return node.transform(new TreeTransformer(function(node) {
|
||||
if (node instanceof AST_Sequence) {
|
||||
if (node instanceof AST.Sequence) {
|
||||
var last = node.expressions.length - 1;
|
||||
node.expressions[last] = mangleStrings(node.expressions[last]);
|
||||
}
|
||||
else if (node instanceof AST_String) {
|
||||
else if (node instanceof AST.String) {
|
||||
node.value = mangle(node.value);
|
||||
}
|
||||
else if (node instanceof AST_Conditional) {
|
||||
else if (node instanceof AST.Conditional) {
|
||||
node.consequent = mangleStrings(node.consequent);
|
||||
node.alternative = mangleStrings(node.alternative);
|
||||
}
|
||||
|
|
@ -250,3 +263,10 @@ function mangle_properties(ast, options) {
|
|||
}));
|
||||
}
|
||||
}
|
||||
|
||||
merge(exports, {
|
||||
find_builtins : find_builtins,
|
||||
reserve_quoted_keys : reserve_quoted_keys,
|
||||
addStrings : addStrings,
|
||||
mangle_properties : mangle_properties,
|
||||
});
|
||||
|
|
|
|||
161
lib/scope.js
161
lib/scope.js
|
|
@ -43,6 +43,22 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var utils = require("./utils");
|
||||
var defaults = utils.defaults;
|
||||
var return_false = utils.return_false;
|
||||
var return_this = utils.return_this;
|
||||
var push_uniq = utils.push_uniq;
|
||||
var makePredicate = utils.makePredicate;
|
||||
var Dictionary = utils.Dictionary;
|
||||
var merge = utils.merge;
|
||||
|
||||
var AST = require("./ast");
|
||||
var TreeWalker = AST.TreeWalker;
|
||||
|
||||
var parse = require("./parse");
|
||||
var is_identifier = parse.is_identifier;
|
||||
var parse = parse.parse;
|
||||
|
||||
function SymbolDef(scope, orig, init) {
|
||||
this.name = orig.name;
|
||||
this.orig = [ orig ];
|
||||
|
|
@ -67,8 +83,8 @@ SymbolDef.prototype = {
|
|||
|| this.undeclared
|
||||
|| !options.eval && this.scope.pinned()
|
||||
|| options.keep_fnames
|
||||
&& (this.orig[0] instanceof AST_SymbolLambda
|
||||
|| this.orig[0] instanceof AST_SymbolDefun);
|
||||
&& (this.orig[0] instanceof AST.SymbolLambda
|
||||
|| this.orig[0] instanceof AST.SymbolDefun);
|
||||
},
|
||||
mangle: function(options) {
|
||||
var cache = options.cache && options.cache.props;
|
||||
|
|
@ -91,7 +107,7 @@ SymbolDef.prototype = {
|
|||
}
|
||||
};
|
||||
|
||||
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
AST.Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
||||
options = defaults(options, {
|
||||
cache: null,
|
||||
ie8: false,
|
||||
|
|
@ -102,15 +118,15 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||
var scope = self.parent_scope = null;
|
||||
var defun = null;
|
||||
var tw = new TreeWalker(function(node, descend) {
|
||||
if (node instanceof AST_Catch) {
|
||||
if (node instanceof AST.Catch) {
|
||||
var save_scope = scope;
|
||||
scope = new AST_Scope(node);
|
||||
scope = new AST.Scope(node);
|
||||
scope.init_scope_vars(save_scope);
|
||||
descend();
|
||||
scope = save_scope;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Scope) {
|
||||
if (node instanceof AST.Scope) {
|
||||
node.init_scope_vars(scope);
|
||||
var save_scope = scope;
|
||||
var save_defun = defun;
|
||||
|
|
@ -120,30 +136,30 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||
defun = save_defun;
|
||||
return true; // don't descend again in TreeWalker
|
||||
}
|
||||
if (node instanceof AST_With) {
|
||||
if (node instanceof AST.With) {
|
||||
for (var s = scope; s; s = s.parent_scope)
|
||||
s.uses_with = true;
|
||||
return;
|
||||
}
|
||||
if (node instanceof AST_Symbol) {
|
||||
if (node instanceof AST.Symbol) {
|
||||
node.scope = scope;
|
||||
}
|
||||
if (node instanceof AST_Label) {
|
||||
if (node instanceof AST.Label) {
|
||||
node.thedef = node;
|
||||
node.references = [];
|
||||
}
|
||||
if (node instanceof AST_SymbolLambda) {
|
||||
if (node instanceof AST.SymbolLambda) {
|
||||
defun.def_function(node, node.name == "arguments" ? undefined : defun);
|
||||
}
|
||||
else if (node instanceof AST_SymbolDefun) {
|
||||
else if (node instanceof AST.SymbolDefun) {
|
||||
// Careful here, the scope where this should be defined is
|
||||
// the parent scope. The reason is that we enter a new
|
||||
// scope when we encounter the AST_Defun node (which is
|
||||
// instanceof AST_Scope) but we get to the symbol a bit
|
||||
// scope when we encounter the AST.Defun node (which is
|
||||
// instanceof AST.Scope) but we get to the symbol a bit
|
||||
// later.
|
||||
(node.scope = defun.parent_scope).def_function(node, defun);
|
||||
}
|
||||
else if (node instanceof AST_SymbolVar) {
|
||||
else if (node instanceof AST.SymbolVar) {
|
||||
defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
|
||||
if (defun !== scope) {
|
||||
node.mark_enclosed(options);
|
||||
|
|
@ -154,7 +170,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||
node.reference(options);
|
||||
}
|
||||
}
|
||||
else if (node instanceof AST_SymbolCatch) {
|
||||
else if (node instanceof AST.SymbolCatch) {
|
||||
scope.def_variable(node).defun = defun;
|
||||
}
|
||||
});
|
||||
|
|
@ -163,13 +179,13 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||
// pass 2: find back references and eval
|
||||
self.globals = new Dictionary();
|
||||
var tw = new TreeWalker(function(node, descend) {
|
||||
if (node instanceof AST_LoopControl && node.label) {
|
||||
if (node instanceof AST.LoopControl && node.label) {
|
||||
node.label.thedef.references.push(node);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
if (node instanceof AST.SymbolRef) {
|
||||
var name = node.name;
|
||||
if (name == "eval" && tw.parent() instanceof AST_Call) {
|
||||
if (name == "eval" && tw.parent() instanceof AST.Call) {
|
||||
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
|
||||
s.uses_eval = true;
|
||||
}
|
||||
|
|
@ -177,7 +193,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||
var sym = node.scope.find_variable(name);
|
||||
if (!sym) {
|
||||
sym = self.def_global(node);
|
||||
} else if (sym.scope instanceof AST_Lambda && name == "arguments") {
|
||||
} else if (sym.scope instanceof AST.Lambda && name == "arguments") {
|
||||
sym.scope.uses_arguments = true;
|
||||
}
|
||||
node.thedef = sym;
|
||||
|
|
@ -186,7 +202,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||
}
|
||||
// ensure mangling works if catch reuses a scope variable
|
||||
var def;
|
||||
if (node instanceof AST_SymbolCatch && (def = node.definition().redefined())) {
|
||||
if (node instanceof AST.SymbolCatch && (def = node.definition().redefined())) {
|
||||
var s = node.scope;
|
||||
while (s) {
|
||||
push_uniq(s.enclosed, def);
|
||||
|
|
@ -200,7 +216,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||
// pass 3: fix up any scoping issue with IE8
|
||||
if (options.ie8) {
|
||||
self.walk(new TreeWalker(function(node, descend) {
|
||||
if (node instanceof AST_SymbolCatch) {
|
||||
if (node instanceof AST.SymbolCatch) {
|
||||
var name = node.name;
|
||||
var refs = node.thedef.references;
|
||||
var scope = node.thedef.defun;
|
||||
|
|
@ -217,7 +233,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||
}
|
||||
});
|
||||
|
||||
AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
||||
AST.Toplevel.DEFMETHOD("def_global", function(node) {
|
||||
var globals = this.globals, name = node.name;
|
||||
if (globals.has(name)) {
|
||||
return globals.get(name);
|
||||
|
|
@ -230,9 +246,9 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
|||
}
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
||||
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
||||
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||
AST.Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
||||
this.variables = new Dictionary(); // map name to AST.SymbolVar (variables defined in this scope; includes functions)
|
||||
this.functions = new Dictionary(); // map name to AST.SymbolDefun (functions defined in this scope)
|
||||
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
||||
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
|
||||
this.parent_scope = parent_scope; // the parent scope
|
||||
|
|
@ -240,17 +256,17 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
|
|||
this.cname = -1; // the current index for mangling functions/variables
|
||||
});
|
||||
|
||||
AST_Lambda.DEFMETHOD("init_scope_vars", function() {
|
||||
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
||||
AST.Lambda.DEFMETHOD("init_scope_vars", function() {
|
||||
AST.Scope.prototype.init_scope_vars.apply(this, arguments);
|
||||
this.uses_arguments = false;
|
||||
this.def_variable(new AST_SymbolFunarg({
|
||||
this.def_variable(new AST.SymbolFunarg({
|
||||
name: "arguments",
|
||||
start: this.start,
|
||||
end: this.end
|
||||
}));
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
|
||||
AST.Symbol.DEFMETHOD("mark_enclosed", function(options) {
|
||||
var def = this.definition();
|
||||
var s = this.scope;
|
||||
while (s) {
|
||||
|
|
@ -265,29 +281,29 @@ AST_Symbol.DEFMETHOD("mark_enclosed", function(options) {
|
|||
}
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("reference", function(options) {
|
||||
AST.Symbol.DEFMETHOD("reference", function(options) {
|
||||
this.definition().references.push(this);
|
||||
this.mark_enclosed(options);
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("find_variable", function(name) {
|
||||
if (name instanceof AST_Symbol) name = name.name;
|
||||
AST.Scope.DEFMETHOD("find_variable", function(name) {
|
||||
if (name instanceof AST.Symbol) name = name.name;
|
||||
return this.variables.get(name)
|
||||
|| (this.parent_scope && this.parent_scope.find_variable(name));
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("def_function", function(symbol, init) {
|
||||
AST.Scope.DEFMETHOD("def_function", function(symbol, init) {
|
||||
var def = this.def_variable(symbol, init);
|
||||
if (!def.init || def.init instanceof AST_Defun) def.init = init;
|
||||
if (!def.init || def.init instanceof AST.Defun) def.init = init;
|
||||
this.functions.set(symbol.name, def);
|
||||
return def;
|
||||
});
|
||||
|
||||
AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
||||
AST.Scope.DEFMETHOD("def_variable", function(symbol, init) {
|
||||
var def = this.variables.get(symbol.name);
|
||||
if (def) {
|
||||
def.orig.push(symbol);
|
||||
if (def.init && (def.scope !== symbol.scope || def.init instanceof AST_Function)) {
|
||||
if (def.init && (def.scope !== symbol.scope || def.init instanceof AST.Function)) {
|
||||
def.init = init;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -317,7 +333,7 @@ function next_mangled_name(scope, options, def) {
|
|||
// #179, #326
|
||||
// in Safari strict mode, something like (function x(x){...}) is a syntax error;
|
||||
// a function expression's argument cannot shadow the function expression's name
|
||||
if (scope instanceof AST_Function && scope.name && def.orig[0] instanceof AST_SymbolFunarg) {
|
||||
if (scope instanceof AST.Function && scope.name && def.orig[0] instanceof AST.SymbolFunarg) {
|
||||
var tricky_def = scope.name.definition();
|
||||
// the function's mangled_name is null when keep_fnames is true
|
||||
names[tricky_def.mangled_name || tricky_def.name] = true;
|
||||
|
|
@ -349,29 +365,29 @@ function next_mangled_name(scope, options, def) {
|
|||
holes.push(scope.cname);
|
||||
}
|
||||
scope.names_in_use[name] = true;
|
||||
if (options.ie8 && def.orig[0] instanceof AST_SymbolLambda) {
|
||||
if (options.ie8 && def.orig[0] instanceof AST.SymbolLambda) {
|
||||
names_in_use(scope.parent_scope, options)[name] = true;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
AST_Symbol.DEFMETHOD("unmangleable", function(options) {
|
||||
AST.Symbol.DEFMETHOD("unmangleable", function(options) {
|
||||
var def = this.definition();
|
||||
return !def || def.unmangleable(options);
|
||||
});
|
||||
|
||||
// labels are always mangleable
|
||||
AST_Label.DEFMETHOD("unmangleable", return_false);
|
||||
AST.Label.DEFMETHOD("unmangleable", return_false);
|
||||
|
||||
AST_Symbol.DEFMETHOD("unreferenced", function() {
|
||||
AST.Symbol.DEFMETHOD("unreferenced", function() {
|
||||
return !this.definition().references.length && !this.scope.pinned();
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("definition", function() {
|
||||
AST.Symbol.DEFMETHOD("definition", function() {
|
||||
return this.thedef;
|
||||
});
|
||||
|
||||
AST_Symbol.DEFMETHOD("global", function() {
|
||||
AST.Symbol.DEFMETHOD("global", function() {
|
||||
return this.definition().global;
|
||||
});
|
||||
|
||||
|
|
@ -390,13 +406,13 @@ function _default_mangler_options(options) {
|
|||
return options;
|
||||
}
|
||||
|
||||
AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
AST.Toplevel.DEFMETHOD("mangle_names", function(options) {
|
||||
options = _default_mangler_options(options);
|
||||
|
||||
// We only need to mangle declaration nodes. Special logic wired
|
||||
// into the code generator will display the mangled name if it's
|
||||
// present (and for AST_SymbolRef-s it'll use the mangled name of
|
||||
// the AST_SymbolDeclaration that it points to).
|
||||
// present (and for AST.SymbolRef-s it'll use the mangled name of
|
||||
// the AST.SymbolDeclaration that it points to).
|
||||
var lname = -1;
|
||||
|
||||
if (options.cache && options.cache.props) {
|
||||
|
|
@ -408,28 +424,28 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||
|
||||
var redefined = [];
|
||||
var tw = new TreeWalker(function(node, descend) {
|
||||
if (node instanceof AST_LabeledStatement) {
|
||||
// lname is incremented when we get to the AST_Label
|
||||
if (node instanceof AST.LabeledStatement) {
|
||||
// lname is incremented when we get to the AST.Label
|
||||
var save_nesting = lname;
|
||||
descend();
|
||||
lname = save_nesting;
|
||||
return true; // don't descend again in TreeWalker
|
||||
}
|
||||
if (node instanceof AST_Scope) {
|
||||
if (node instanceof AST.Scope) {
|
||||
descend();
|
||||
if (options.cache && node instanceof AST_Toplevel) {
|
||||
if (options.cache && node instanceof AST.Toplevel) {
|
||||
node.globals.each(mangle);
|
||||
}
|
||||
node.variables.each(mangle);
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Label) {
|
||||
if (node instanceof AST.Label) {
|
||||
var name;
|
||||
do name = base54(++lname); while (!is_identifier(name));
|
||||
node.mangled_name = name;
|
||||
return true;
|
||||
}
|
||||
if (!options.ie8 && node instanceof AST_Catch) {
|
||||
if (!options.ie8 && node instanceof AST.Catch) {
|
||||
var def = node.argname.definition();
|
||||
var redef = def.redefined();
|
||||
if (redef) {
|
||||
|
|
@ -457,14 +473,14 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||
}
|
||||
});
|
||||
|
||||
AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
|
||||
AST.Toplevel.DEFMETHOD("find_colliding_names", function(options) {
|
||||
var cache = options.cache && options.cache.props;
|
||||
var avoid = Object.create(null);
|
||||
options.reserved.forEach(to_avoid);
|
||||
this.globals.each(add_def);
|
||||
this.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Scope) node.variables.each(add_def);
|
||||
if (node instanceof AST_SymbolCatch) add_def(node.definition());
|
||||
if (node instanceof AST.Scope) node.variables.each(add_def);
|
||||
if (node instanceof AST.SymbolCatch) add_def(node.definition());
|
||||
}));
|
||||
return avoid;
|
||||
|
||||
|
|
@ -480,7 +496,7 @@ AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
|
|||
}
|
||||
});
|
||||
|
||||
AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
||||
AST.Toplevel.DEFMETHOD("expand_names", function(options) {
|
||||
base54.reset();
|
||||
base54.sort();
|
||||
options = _default_mangler_options(options);
|
||||
|
|
@ -488,8 +504,8 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
|||
var cname = 0;
|
||||
this.globals.each(rename);
|
||||
this.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Scope) node.variables.each(rename);
|
||||
if (node instanceof AST_SymbolCatch) rename(node.definition());
|
||||
if (node instanceof AST.Scope) node.variables.each(rename);
|
||||
if (node instanceof AST.SymbolCatch) rename(node.definition());
|
||||
}));
|
||||
|
||||
function next_name() {
|
||||
|
|
@ -515,40 +531,40 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
|
|||
}
|
||||
});
|
||||
|
||||
AST_Node.DEFMETHOD("tail_node", return_this);
|
||||
AST_Sequence.DEFMETHOD("tail_node", function() {
|
||||
AST.Node.DEFMETHOD("tail_node", return_this);
|
||||
AST.Sequence.DEFMETHOD("tail_node", function() {
|
||||
return this.expressions[this.expressions.length - 1];
|
||||
});
|
||||
|
||||
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
|
||||
AST.Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
|
||||
options = _default_mangler_options(options);
|
||||
base54.reset();
|
||||
try {
|
||||
AST_Node.prototype.print = function(stream, force_parens) {
|
||||
AST.Node.prototype.print = function(stream, force_parens) {
|
||||
this._print(stream, force_parens);
|
||||
if (this instanceof AST_Symbol && !this.unmangleable(options)) {
|
||||
if (this instanceof AST.Symbol && !this.unmangleable(options)) {
|
||||
base54.consider(this.name, -1);
|
||||
} else if (options.properties) {
|
||||
if (this instanceof AST_Dot) {
|
||||
if (this instanceof AST.Dot) {
|
||||
base54.consider(this.property, -1);
|
||||
} else if (this instanceof AST_Sub) {
|
||||
} else if (this instanceof AST.Sub) {
|
||||
skip_string(this.property);
|
||||
}
|
||||
}
|
||||
};
|
||||
base54.consider(this.print_to_string(), 1);
|
||||
} finally {
|
||||
AST_Node.prototype.print = AST_Node.prototype._print;
|
||||
AST.Node.prototype.print = AST.Node.prototype._print;
|
||||
}
|
||||
base54.sort();
|
||||
|
||||
function skip_string(node) {
|
||||
if (node instanceof AST_String) {
|
||||
if (node instanceof AST.String) {
|
||||
base54.consider(node.value, -1);
|
||||
} else if (node instanceof AST_Conditional) {
|
||||
} else if (node instanceof AST.Conditional) {
|
||||
skip_string(node.consequent);
|
||||
skip_string(node.alternative);
|
||||
} else if (node instanceof AST_Sequence) {
|
||||
} else if (node instanceof AST.Sequence) {
|
||||
skip_string(node.tail_node());
|
||||
}
|
||||
}
|
||||
|
|
@ -597,3 +613,10 @@ var base54 = (function() {
|
|||
}
|
||||
return base54;
|
||||
})();
|
||||
|
||||
merge(exports, {
|
||||
SymbolDef : SymbolDef,
|
||||
names_in_use : names_in_use,
|
||||
next_mangled_name : next_mangled_name,
|
||||
base54 : base54,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var MOZ_SourceMap = require("source-map");
|
||||
var utils = require("./utils");
|
||||
var defaults = utils.defaults;
|
||||
var merge = utils.merge;
|
||||
|
||||
// a small wrapper around fitzgen's source-map library
|
||||
function SourceMap(options) {
|
||||
options = defaults(options, {
|
||||
|
|
@ -102,3 +107,7 @@ function SourceMap(options) {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
merge(exports, {
|
||||
SourceMap : SourceMap,
|
||||
});
|
||||
|
|
|
|||
185
lib/transform.js
185
lib/transform.js
|
|
@ -1,185 +0,0 @@
|
|||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
function TreeTransformer(before, after) {
|
||||
TreeWalker.call(this);
|
||||
this.before = before;
|
||||
this.after = after;
|
||||
}
|
||||
TreeTransformer.prototype = new TreeWalker;
|
||||
|
||||
(function(DEF) {
|
||||
function do_list(list, tw) {
|
||||
return MAP(list, function(node) {
|
||||
return node.transform(tw, true);
|
||||
});
|
||||
}
|
||||
|
||||
DEF(AST_Node, noop);
|
||||
DEF(AST_LabeledStatement, function(self, tw) {
|
||||
self.label = self.label.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
DEF(AST_SimpleStatement, function(self, tw) {
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
DEF(AST_Block, function(self, tw) {
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
DEF(AST_Do, function(self, tw) {
|
||||
self.body = self.body.transform(tw);
|
||||
self.condition = self.condition.transform(tw);
|
||||
});
|
||||
DEF(AST_While, function(self, tw) {
|
||||
self.condition = self.condition.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
DEF(AST_For, function(self, tw) {
|
||||
if (self.init) self.init = self.init.transform(tw);
|
||||
if (self.condition) self.condition = self.condition.transform(tw);
|
||||
if (self.step) self.step = self.step.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
DEF(AST_ForIn, function(self, tw) {
|
||||
self.init = self.init.transform(tw);
|
||||
self.object = self.object.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
DEF(AST_With, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
DEF(AST_Exit, function(self, tw) {
|
||||
if (self.value) self.value = self.value.transform(tw);
|
||||
});
|
||||
DEF(AST_LoopControl, function(self, tw) {
|
||||
if (self.label) self.label = self.label.transform(tw);
|
||||
});
|
||||
DEF(AST_If, function(self, tw) {
|
||||
self.condition = self.condition.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
if (self.alternative) self.alternative = self.alternative.transform(tw);
|
||||
});
|
||||
DEF(AST_Switch, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
DEF(AST_Case, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
DEF(AST_Try, function(self, tw) {
|
||||
self.body = do_list(self.body, tw);
|
||||
if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
|
||||
if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
|
||||
});
|
||||
DEF(AST_Catch, function(self, tw) {
|
||||
self.argname = self.argname.transform(tw);
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
DEF(AST_Definitions, function(self, tw) {
|
||||
self.definitions = do_list(self.definitions, tw);
|
||||
});
|
||||
DEF(AST_VarDef, function(self, tw) {
|
||||
self.name = self.name.transform(tw);
|
||||
if (self.value) self.value = self.value.transform(tw);
|
||||
});
|
||||
DEF(AST_Lambda, function(self, tw) {
|
||||
if (self.name) self.name = self.name.transform(tw);
|
||||
self.argnames = do_list(self.argnames, tw);
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
DEF(AST_Call, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.args = do_list(self.args, tw);
|
||||
});
|
||||
DEF(AST_Sequence, function(self, tw) {
|
||||
self.expressions = do_list(self.expressions, tw);
|
||||
});
|
||||
DEF(AST_Dot, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
});
|
||||
DEF(AST_Sub, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.property = self.property.transform(tw);
|
||||
});
|
||||
DEF(AST_Unary, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
});
|
||||
DEF(AST_Binary, function(self, tw) {
|
||||
self.left = self.left.transform(tw);
|
||||
self.right = self.right.transform(tw);
|
||||
});
|
||||
DEF(AST_Conditional, function(self, tw) {
|
||||
self.condition = self.condition.transform(tw);
|
||||
self.consequent = self.consequent.transform(tw);
|
||||
self.alternative = self.alternative.transform(tw);
|
||||
});
|
||||
DEF(AST_Array, function(self, tw) {
|
||||
self.elements = do_list(self.elements, tw);
|
||||
});
|
||||
DEF(AST_Object, function(self, tw) {
|
||||
self.properties = do_list(self.properties, tw);
|
||||
});
|
||||
DEF(AST_ObjectProperty, function(self, tw) {
|
||||
self.value = self.value.transform(tw);
|
||||
});
|
||||
})(function(node, descend) {
|
||||
node.DEFMETHOD("transform", function(tw, in_list) {
|
||||
var x, y;
|
||||
tw.push(this);
|
||||
if (tw.before) x = tw.before(this, descend, in_list);
|
||||
if (typeof x === "undefined") {
|
||||
x = this;
|
||||
descend(x, tw);
|
||||
if (tw.after) {
|
||||
y = tw.after(x, in_list);
|
||||
if (typeof y !== "undefined") x = y;
|
||||
}
|
||||
}
|
||||
tw.pop();
|
||||
return x;
|
||||
});
|
||||
});
|
||||
47
lib/utils.js
47
lib/utils.js
|
|
@ -255,27 +255,26 @@ function HOP(obj, prop) {
|
|||
return Object.prototype.hasOwnProperty.call(obj, prop);
|
||||
}
|
||||
|
||||
// return true if the node at the top of the stack (that means the
|
||||
// innermost node in the current output) is lexically the first in
|
||||
// a statement.
|
||||
function first_in_statement(stack) {
|
||||
var node = stack.parent(-1);
|
||||
for (var i = 0, p; p = stack.parent(i++); node = p) {
|
||||
if (p.TYPE == "Call") {
|
||||
if (p.expression === node) continue;
|
||||
} else if (p instanceof AST_Binary) {
|
||||
if (p.left === node) continue;
|
||||
} else if (p instanceof AST_Conditional) {
|
||||
if (p.condition === node) continue;
|
||||
} else if (p instanceof AST_PropAccess) {
|
||||
if (p.expression === node) continue;
|
||||
} else if (p instanceof AST_Sequence) {
|
||||
if (p.expressions[0] === node) continue;
|
||||
} else if (p instanceof AST_Statement) {
|
||||
return p.body === node;
|
||||
} else if (p instanceof AST_UnaryPostfix) {
|
||||
if (p.expression === node) continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
merge(exports, {
|
||||
characters : characters,
|
||||
member : member,
|
||||
find_if : find_if,
|
||||
repeat_string : repeat_string,
|
||||
configure_error_stack : configure_error_stack,
|
||||
DefaultsError : DefaultsError,
|
||||
defaults : defaults,
|
||||
merge : merge,
|
||||
noop : noop,
|
||||
return_false : return_false,
|
||||
return_true : return_true,
|
||||
return_this : return_this,
|
||||
return_null : return_null,
|
||||
MAP : MAP,
|
||||
push_uniq : push_uniq,
|
||||
string_template : string_template,
|
||||
remove : remove,
|
||||
makePredicate : makePredicate,
|
||||
all : all,
|
||||
Dictionary : Dictionary,
|
||||
HOP : HOP,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
exports["Compressor"] = Compressor;
|
||||
exports["JS_Parse_Error"] = JS_Parse_Error;
|
||||
exports["OutputStream"] = OutputStream;
|
||||
exports["SourceMap"] = SourceMap;
|
||||
exports["TreeWalker"] = TreeWalker;
|
||||
exports["base54"] = base54;
|
||||
exports["defaults"] = defaults;
|
||||
exports["mangle_properties"] = mangle_properties;
|
||||
exports["minify"] = minify;
|
||||
exports["parse"] = parse;
|
||||
exports["reserve_quoted_keys"] = reserve_quoted_keys;
|
||||
exports["string_template"] = string_template;
|
||||
exports["tokenizer"] = tokenizer;
|
||||
exports["is_identifier"] = is_identifier;
|
||||
|
|
@ -22,6 +22,7 @@ it = function(title, fn) {
|
|||
tasks.push(fn);
|
||||
};
|
||||
|
||||
|
||||
fs.readdirSync("test/mocha").filter(function(file) {
|
||||
return /\.js$/.test(file);
|
||||
}).forEach(function(file) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ describe("bin/uglifyjs", function() {
|
|||
it("should produce a functional build when using --self", function(done) {
|
||||
this.timeout(30000);
|
||||
var command = uglifyjscmd + ' --self -cm --wrap WrappedUglifyJS';
|
||||
exec(command, function(err, stdout) {
|
||||
exec(command, {maxBuffer: 1024 * 300}, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
eval(stdout);
|
||||
assert.strictEqual(typeof WrappedUglifyJS, "object");
|
||||
|
|
@ -594,7 +594,7 @@ describe("bin/uglifyjs", function() {
|
|||
exec(command, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
var ast = JSON.parse(stdout);
|
||||
assert.strictEqual(ast._class, "AST_Toplevel");
|
||||
assert.strictEqual(ast._class, "AST.Toplevel");
|
||||
assert.ok(Array.isArray(ast.body));
|
||||
done();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ describe("spidermonkey export/import sanity test", function() {
|
|||
var command = uglifyjs + " --self -cm --wrap SpiderUglify -o spidermonkey | " +
|
||||
uglifyjs + " -p spidermonkey -cm";
|
||||
|
||||
exec(command, function(err, stdout) {
|
||||
exec(command, {maxBuffer: 1024 * 300}, function(err, stdout) {
|
||||
if (err) throw err;
|
||||
|
||||
eval(stdout);
|
||||
|
|
|
|||
16
test/node.js
16
test/node.js
|
|
@ -1,6 +1,10 @@
|
|||
var fs = require("fs");
|
||||
|
||||
new Function("MOZ_SourceMap", "exports", require("../tools/node").FILES.map(function(file) {
|
||||
if (/exports\.js$/.test(file)) file = require.resolve("./exports");
|
||||
return fs.readFileSync(file, "utf8");
|
||||
}).join("\n\n"))(require("source-map"), exports);
|
||||
var orig = require("../tools/node");
|
||||
orig.SourceMap = require("../lib/sourcemap").SourceMap;
|
||||
orig.base54 = orig.utils.base54;
|
||||
orig.defaults = orig.utils.defaults;
|
||||
orig.mangle_properties = orig.propmangle.mangle_properties;
|
||||
orig.reserve_quoted_keys = orig.propmangle.reserve_quoted_keys;
|
||||
orig.JS_Parse_Error = orig.parser.JS_Parse_Error;
|
||||
orig.tokenizer = orig.parser.tokenizer;
|
||||
orig.is_identifier = orig.parser.is_identifier;
|
||||
module.exports = orig;
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
exports["Compressor"] = Compressor;
|
||||
exports["Dictionary"] = Dictionary;
|
||||
exports["TreeWalker"] = TreeWalker;
|
||||
exports["TreeTransformer"] = TreeTransformer;
|
||||
exports["minify"] = minify;
|
||||
exports["parse"] = parse;
|
||||
exports["_push_uniq"] = push_uniq;
|
||||
exports["string_template"] = string_template;
|
||||
|
|
|
|||
61
tools/generate-exports.js
Normal file
61
tools/generate-exports.js
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
"use strict";
|
||||
|
||||
var UglifyJS = require("../tools/node");
|
||||
var fs = require("fs");
|
||||
|
||||
console.log = function (d) {
|
||||
process.stdout.write(d + '\n');
|
||||
};
|
||||
|
||||
UglifyJS.FILES.forEach(function(filepath){
|
||||
var code = fs.readFileSync(filepath, "utf8");
|
||||
var filename = filepath.replace(/^.*?([-a-z]+)\.js$/g, "$1");
|
||||
|
||||
var AST = UglifyJS.parse(code, {filename: filepath});
|
||||
|
||||
var exportNames = [];
|
||||
var walker = new UglifyJS.TreeWalker(function(node){
|
||||
if (node instanceof UglifyJS.ast.AST_Defun) {
|
||||
exportNames.push(node.name.name);
|
||||
}
|
||||
if (node instanceof UglifyJS.ast.AST_Var) {
|
||||
var def = node.definitions[0];
|
||||
var name = def.name.name;
|
||||
var value = def.value;
|
||||
// Skip <var> = foo.<var>
|
||||
if (value instanceof UglifyJS.ast.AST_Dot && value.property == name)
|
||||
return true;
|
||||
// Skip <var> = require(...)
|
||||
if (value instanceof UglifyJS.ast.AST_Call && value.expression instanceof UglifyJS.ast.AST_SymbolRef && value.expression.name == "require")
|
||||
return true;
|
||||
exportNames.push(name);
|
||||
}
|
||||
return !(node instanceof UglifyJS.ast.AST_Toplevel);
|
||||
});
|
||||
AST.walk(walker);
|
||||
// Don't export identifiers starting with underscore
|
||||
exportNames = exportNames.filter(name => name[0] != "_");
|
||||
if (exportNames.length == 0)
|
||||
return;
|
||||
// Use (utils.)merge instead of Object.assign for (very) old node
|
||||
var exports = "merge(exports, {\n" + exportNames.map(
|
||||
name => UglifyJS.string_template(' {name} : {name},', { name: name })
|
||||
).concat(exportNames.filter(name => name.indexOf("AST_") == 0).map(
|
||||
name => UglifyJS.string_template(' {expName} : {name},', { expName: name.substr(4), name: name })
|
||||
)).join("\n") + "\n});";
|
||||
var imports = exportNames.map(function(name){
|
||||
return UglifyJS.string_template(UglifyJS.string_template('var {name} = {fn}.{name};', { name: name, fn: filename}));
|
||||
});
|
||||
|
||||
console.log("\n// Exports for " + filename);
|
||||
console.log(exports);
|
||||
console.log("\n\n// Usage:")
|
||||
console.log(UglifyJS.string_template('var {fn} = require("../lib/{fn}");', { fn: filename}));
|
||||
console.log(imports.join("\n"));
|
||||
|
||||
var result = code.replace(/\n+(exports\.\w+ = \w+;\n+)+$/, "");
|
||||
result = result.replace(/\n+Object\.assign\(exports, \{[\s\S]*?\}\);\n*$/, "");
|
||||
result = result.replace(/\n+merge\(exports, \{[\s\S]*?\}\);\n*$/, "");
|
||||
result += "\n\n" + exports + "\n";
|
||||
fs.writeFileSync(filepath, result, "utf8");
|
||||
});
|
||||
|
|
@ -5,7 +5,6 @@ var FILES = UglifyJS.FILES = [
|
|||
"../lib/utils.js",
|
||||
"../lib/ast.js",
|
||||
"../lib/parse.js",
|
||||
"../lib/transform.js",
|
||||
"../lib/scope.js",
|
||||
"../lib/output.js",
|
||||
"../lib/compress.js",
|
||||
|
|
@ -18,21 +17,42 @@ var FILES = UglifyJS.FILES = [
|
|||
return require.resolve(file);
|
||||
});
|
||||
|
||||
new Function("MOZ_SourceMap", "exports", function() {
|
||||
var code = FILES.map(function(file) {
|
||||
return fs.readFileSync(file, "utf8");
|
||||
});
|
||||
code.push("exports.describe_ast = " + describe_ast.toString());
|
||||
return code.join("\n\n");
|
||||
}())(
|
||||
require("source-map"),
|
||||
UglifyJS
|
||||
);
|
||||
var utils = require("../lib/utils");
|
||||
var output = require("../lib/output");
|
||||
var OutputStream = output.OutputStream;
|
||||
var minify = require("../lib/minify").minify;
|
||||
var AST = require("../lib/ast");
|
||||
var compress = require("../lib/compress");
|
||||
var parse = require("../lib/parse");
|
||||
var propmangle = require("../lib/propmangle");
|
||||
require("../lib/mozilla-ast");
|
||||
|
||||
|
||||
exports.utils = utils;
|
||||
exports.OutputStream = OutputStream;
|
||||
exports.minify = minify;
|
||||
exports.AST = AST;
|
||||
exports.parser = parse;
|
||||
exports.parse = parse.parse;
|
||||
exports.Compressor = compress.Compressor;
|
||||
exports.Dictionary = utils.Dictionary;
|
||||
exports.TreeWalker = AST.TreeWalker;
|
||||
exports.TreeTransformer = AST.TreeTransformer;
|
||||
exports.push_uniq = utils.push_uniq;
|
||||
exports.string_template = utils.string_template;
|
||||
exports.describe_ast = describe_ast;
|
||||
exports.propmangle = propmangle;
|
||||
|
||||
// Backwards compatibility: Add all AST_
|
||||
for (var name in AST) if (utils.HOP(AST, name)) {
|
||||
if (name.indexOf("AST_") == 0)
|
||||
exports[name] = AST[name];
|
||||
}
|
||||
|
||||
function describe_ast() {
|
||||
var out = OutputStream({ beautify: true });
|
||||
function doitem(ctor) {
|
||||
out.print("AST_" + ctor.TYPE);
|
||||
out.print("AST." + ctor.TYPE);
|
||||
var props = ctor.SELF_PROPS.filter(function(prop) {
|
||||
return !/^\$/.test(prop);
|
||||
});
|
||||
|
|
@ -60,7 +80,7 @@ function describe_ast() {
|
|||
});
|
||||
}
|
||||
};
|
||||
doitem(AST_Node);
|
||||
doitem(AST.Node);
|
||||
return out + "\n";
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user