From: Mihai Bazon Date: Wed, 3 Oct 2012 17:03:17 +0000 (+0300) Subject: define AST_Node.from_mozilla_ast(ast) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=2bd8a118c273853848e4231c98f833757dda18b0;p=UglifyJS.git define AST_Node.from_mozilla_ast(ast) returns an UglifyJS2 AST given a Mozilla AST. Still needs some work to do (need to create specific nodes like AST_SymbolRef, AST_SymbolLambda etc. instead of base AST_Symbol, in order for the mangler/compressor to work properly) --- diff --git a/lib/mozilla-ast.js b/lib/mozilla-ast.js new file mode 100644 index 00000000..34f3fa5f --- /dev/null +++ b/lib/mozilla-ast.js @@ -0,0 +1,245 @@ +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + 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(){ + + var MOZ_TO_ME = {}; + var ME_TO_MOZ = {}; + + function my_start_token(moznode) { + return new AST_Token({ + file : moznode.loc.start.source, + line : moznode.loc.start.line, + col : moznode.loc.start.column, + pos : moznode.start, + endpos : moznode.start + }); + }; + + function my_end_token(moznode) { + return new AST_Token({ + file : moznode.loc.end.source, + line : moznode.loc.end.line, + col : moznode.loc.end.column, + pos : moznode.end, + endpos : moznode.end + }); + }; + + function map(moztype, mytype, propmap) { + var moz_to_me = "function From_Moz_" + moztype + "(M){\n"; + moz_to_me += "return new mytype({\n" + + "start: my_start_token(M),\n" + + "end: my_end_token(M)"; + + if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){ + var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop); + if (!m) throw new Error("Can't understand property map: " + prop); + var moz = "M." + m[1], how = m[2], my = m[3]; + moz_to_me += ",\n" + my + ": "; + if (how == "@") { + moz_to_me += moz + ".map(from_moz)"; + } else if (how == ">") { + moz_to_me += "from_moz(" + moz + ")"; + } else if (how == "=") { + moz_to_me += moz; + } else if (how == "%") { + moz_to_me += "from_moz(" + moz + ").body"; + } else if (how == "@>") { + moz_to_me += "from_moz(" + moz + "[0])"; + } else throw new Error("Can't understand operator in propmap: " + prop); + }); + moz_to_me += "\n})}"; + + // moz_to_me = parse(moz_to_me).print_to_string({ beautify: true }); + // console.log(moz_to_me); + + moz_to_me = new Function("mytype", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")( + mytype, my_start_token, my_end_token, from_moz + ); + return MOZ_TO_ME[moztype] = moz_to_me; + }; + + map("Node", AST_Node); + map("Program", AST_Toplevel, "body@body"); + map("Function", AST_Function, "id>name, params@argnames, body%body"); + map("EmptyStatement", AST_EmptyStatement); + map("BlockStatement", AST_BlockStatement, "body@body"); + map("ExpressionStatement", AST_SimpleStatement, "expression>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("FunctionDeclaration", AST_Defun, "id>name, params@argnames, body%body"); + map("VariableDeclaration", AST_Var, "declarations@definitions"); + map("VariableDeclarator", AST_VarDef, "id>name, init>value"); + + map("ThisExpression", AST_This); + map("ArrayExpression", AST_Array, "elements@elements"); + map("FunctionExpression", AST_Function, "id>name, params@argnames, body%body"); + map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right"); + map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right"); + map("LogicalExpression", AST_Binary, "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("Identifier", AST_Symbol, "name=name"); + + /* -----[ stuff our little macro cannot handle ]----- */ + + MOZ_TO_ME.TryStatement = function(M) { + return new AST_Try({ + start : my_start_token(M), + end : my_end_token(M), + body : from_moz(M.block).body, + bcatch : from_moz(M.handlers[0]), + bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null + }); + }; + + MOZ_TO_ME.CatchClause = function(M) { + return new AST_Catch({ + start : my_start_token(M), + end : my_start_token(M), + argname : from_moz(M.param), + body : from_moz(M.body).body + }); + }; + + MOZ_TO_ME.ObjectExpression = function(M) { + return new AST_Object({ + start : my_start_token(M), + end : my_end_token(M), + properties : M.properties.map(function(prop){ + var key = prop.key; + var args = { + start : my_start_token(key), + end : my_end_token(prop.value), + key : key.type == "Identifier" ? key.name : key.value, + value : from_moz(prop.value) + }; + switch (prop.kind) { + case "init": + return new AST_ObjectKeyVal(args); + case "set": + return new AST_ObjectSetter(args); + case "get": + return new AST_ObjectGetter(args); + } + }) + }); + }; + + MOZ_TO_ME.SequenceExpression = function(M) { + return AST_Seq.from_array(M.expressions.map(from_moz)); + }; + + MOZ_TO_ME.UnaryExpression = MOZ_TO_ME.UpdateExpression = function(M) { + return new (M.prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({ + start : my_start_token(M), + end : my_end_token(M), + operator : M.operator, + expression : from_moz(M.argument) + }) + }; + + MOZ_TO_ME.MemberExpression = function(M) { + return new (M.computed ? AST_Sub : AST_Dot)({ + start : my_start_token(M), + end : my_start_token(M), + property : M.computed ? from_moz(M.property) : M.property.name, + expression : from_moz(M.object) + }); + }; + + MOZ_TO_ME.SwitchCase = function(M) { + return new (M.test ? AST_Case : AST_Default)({ + start : my_start_token(M), + end : my_start_token(M), + expression : from_moz(M.test), + body : M.consequent.map(from_moz) + }); + }; + + MOZ_TO_ME.Literal = function(M) { + var val = M.value, args = { + start : my_start_token(M), + end : my_end_token(M) + }; + if (val === null) return new AST_Null(args); + switch (typeof val) { + case "string": + args.value = val; + return new AST_String(args); + case "number": + args.value = val; + return new AST_Number(args); + case "boolean": + return new (val ? AST_True : AST_False)(args); + default: + args.value = val; + var m = /\/(.*)\/(.*)/.exec(val+""); + args.pattern = m[1]; + args.mods = m[2]; + return new AST_RegExp(args); + } + }; + + function from_moz(node) { + return node != null ? MOZ_TO_ME[node.type](node) : null; + }; + + AST_Node.from_mozilla_ast = from_moz; + +})(); diff --git a/tools/node.js b/tools/node.js index 3d743640..4abfa34a 100644 --- a/tools/node.js +++ b/tools/node.js @@ -43,6 +43,7 @@ load_global("../lib/scope.js"); load_global("../lib/output.js"); load_global("../lib/compress.js"); load_global("../lib/sourcemap.js"); +load_global("../lib/mozilla-ast.js"); UglifyJS.AST_Node.warn_function = function(txt) { sys.error("WARN: " + txt);