This commit is contained in:
Alexander Grund 2018-06-13 20:08:54 +00:00 committed by GitHub
commit 364af7fa0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 2225 additions and 1764 deletions

View File

@ -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

View File

@ -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
});
}

View File

@ -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,
});

File diff suppressed because it is too large Load Diff

View File

@ -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,
});

View File

@ -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,

View File

@ -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,
});

View File

@ -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,
});

View File

@ -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,
});

View File

@ -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,
});

View File

@ -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,
});

View File

@ -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;
});
});

View File

@ -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,
});

View File

@ -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;

View File

@ -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) {

View 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();
});

View File

@ -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);

View File

@ -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;

View File

@ -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
View 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");
});

View File

@ -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";
}