diff --git a/bin/js_features.js b/bin/js_features.js index 178492fc..95a0c7cf 100755 --- a/bin/js_features.js +++ b/bin/js_features.js @@ -80,12 +80,12 @@ function processFile(file, print_ast, features, json_formatting, skip_minified) try { var output = UglifyJS.extractFeatures(code, file, print_ast, features, skip_minified); } catch (ex){ - if (ex instanceof UglifyJS.JS_Parse_Error){ - sys.error("ERROR: ".red + "cannot parse file '" + file + "'"); - } else if (ex instanceof UglifyJS.JS_Minified_Error){ + if (ex instanceof UglifyJS.Parse_Error){ + sys.error("ERROR: ".red + "cannot parse file '" + file + "': " + ex.message); + } else if (ex instanceof UglifyJS.Minified_Error){ //sys.error("WARN: ".yellow + "skipping minified file '" + file + "'"); } else { - sys.error("ERROR: ".red + "'" + file + "'" + ex); + sys.error("ERROR: ".red + "'" + file + "': " + ex); } return; diff --git a/lib/feature_extractor.js b/lib/feature_extractor.js index a181fc33..4aa2467f 100644 --- a/lib/feature_extractor.js +++ b/lib/feature_extractor.js @@ -58,14 +58,22 @@ function replaceMangled(code, file) { return stream.toString(); } -function JS_Minified_Error(message) { +function Minified_Error(message) { this.message = message; } +function Parse_Error(ex) { + this.message = ex.toString(); +} + function extractFeatures(code, file, print_ast, features, skip_minified) { var toplevel; - toplevel = parseFile(code, file); + try { + toplevel = parseFile(code, file); + } catch (ex){ + throw new Parse_Error(ex); + } extendAst(toplevel); @@ -74,7 +82,7 @@ function extractFeatures(code, file, print_ast, features, skip_minified) { } if (skip_minified && isMinified(toplevel, code, file)){ - throw new JS_Minified_Error("Skipping minified file"); + throw new Minified_Error("Skipping minified file"); //console.warn("Skipping minified file: '%s'", file); //return null; } @@ -82,7 +90,7 @@ function extractFeatures(code, file, print_ast, features, skip_minified) { var feature_outputter = new FeatureJsonOutputter(); feature_outputter.openElem(); feature_outputter.openArray("query"); - + if (features.indexOf("ASTREL") != -1) { generateAstFeatures(toplevel, feature_outputter); } @@ -104,8 +112,8 @@ function extractFeatures(code, file, print_ast, features, skip_minified) { /* -----[ functions ]----- */ -function nodeToString(node) { - if (node == null) return null; +function nodeToString(node, parent) { + if (node == null) return null; if (node instanceof AST_Symbol){ if (node instanceof AST_This ){ @@ -120,31 +128,37 @@ function nodeToString(node) { return GIVEN + "!" + nodeType(node) + "!" + String(node.value).slice(0,64); } else if (node instanceof AST_Sub){ //x[1], x -> expression, 1 -> property - return nodeToString(node.expression) + "[]"; + return (nodeToString(node.expression, node) != null) ? nodeToString(node.expression, node) + "[]" : null; } else if (node instanceof AST_PropAccess){ return GIVEN + node.property; } else if (node instanceof AST_Defun) { //function foo(...) { ... } - return nodeToString(node.name); + return nodeToString(node.name, node); } else if (node instanceof AST_VarDef){ // var x = function () { ... } - return nodeToString(node.name); + return nodeToString(node.name, node); } else if (node instanceof AST_Assign){ //x = function () { ... } - return nodeToString(node.left); + return nodeToString(node.left, node); } else if (node instanceof AST_ObjectProperty){ // { "x" : function () { ... } } return GIVEN + node.key; } else if (node instanceof AST_Call){ //x.foo( function () { ... } ) //foo( function () { ... } ) - return nodeToString(node.expression); + return nodeToString(node.expression, node); } else if (node instanceof AST_Lambda) { if (node.parent instanceof AST_Call){ //'node.parent.expression != node' as lambda can call itself - return (node.parent.expression == node) ? null : nodeToString(node.parent.expression) + "(" + node.child_id + ")"; - } - return nodeToString(node.parent); + if (node.parent.expression == node) { + return null; + } + + return (nodeToString(node.parent.expression, node) != null) ? nodeToString(node.parent.expression, node) + "(" + node.child_id + ")" : null; + } + if (node.parent != parent) { + return nodeToString(node.parent, node); + } } return null; @@ -543,8 +557,10 @@ StringMap.prototype.getId = function(input){ /* ------------------------ */ -function escapeString(input){ - return encodeURIComponent(input); +function escapeString(input){ + //escape method escapes certain characters that encodeURIComponent cannot process + //unescape is used to make the resulting string smaller + return unescape(encodeURIComponent(escape(input))); } function parseFile(code, file) { diff --git a/lib/parse.js b/lib/parse.js index 35ce7ef2..1486e763 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -196,7 +196,7 @@ function JS_Parse_Error(message, line, col, pos) { }; JS_Parse_Error.prototype.toString = function() { - return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack; + return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")";// + "\n\n" + this.stack; }; function js_error(message, filename, line, col, pos) {