From b0412a6ae888d17cfec929ca1dccefd3e80b263f Mon Sep 17 00:00:00 2001 From: Pavol Bielik Date: Sun, 25 Jan 2015 00:11:19 +0100 Subject: [PATCH] Add generating scope constraints --- bin/js_features.js | 9 +++-- lib/feature_extractor.js | 65 +++++++++++++++++++++++++++++++ test/feature_extraction/fnames.js | 37 +++++++++++++++++- 3 files changed, 106 insertions(+), 5 deletions(-) diff --git a/bin/js_features.js b/bin/js_features.js index 50fcbbeb..2b361bd9 100755 --- a/bin/js_features.js +++ b/bin/js_features.js @@ -15,9 +15,10 @@ var ARGS = yargs .describe("skip_minified", "Whether to skip processing minified files") .describe("features", "Comma separated list of features: \n" + "ASTREL - relations in AST, \n" + - "FNAMES - function names to internal calls") + "FNAMES - function names to internal calls,\n" + + "FSCOPE - add variable scope constraints.") .demand(1) - .default('features', 'ASTREL,FNAMES') + .default('features', 'ASTREL,FNAMES,FSCOPE') .boolean("print_ast") .boolean("skip_minified") .boolean("json_formatting") @@ -45,8 +46,8 @@ if (ARGS.features === true) { var features = ARGS.features.split(","); for (var i = 0; i < features.length; i++) { - if (features[i] != "FNAMES" && features[i] != "ASTREL") { - sys.error("WARNING: ignoring not suppored feature '" + features[i] + "'."); + if (features[i] != "FNAMES" && features[i] != "ASTREL" && features[i] != "FSCOPE") { + sys.error("WARNING: ignoring not supported feature '" + features[i] + "'."); }; }; diff --git a/lib/feature_extractor.js b/lib/feature_extractor.js index cea2db00..c4bef4f5 100644 --- a/lib/feature_extractor.js +++ b/lib/feature_extractor.js @@ -89,6 +89,10 @@ function extractFeatures(code, file, print_ast, features, skip_minified) { generateFnamesFeatures(toplevel, feature_outputter); } + if (features.indexOf("FSCOPE") != -1) { + generateFscopeConstraints(toplevel, feature_outputter); + } + feature_outputter.closeArray(); feature_outputter.dumpSymbols(); feature_outputter.closeElem(); @@ -247,6 +251,37 @@ function addFeatures(lhss, lhs_label, rhs, rhs_label, feature_outputter){ } } +function addScopeConstraints(node, toplevel, feature_outputter){ + feature_outputter.beginScope(); + var name = nodeToString(node); + if (name != null) + feature_outputter.addToScope(name); + + for (var i = 0; i < node.enclosed.length; i++){ + feature_outputter.addToScope(nodeToString(node.enclosed[i].orig[0])); + } + + node.variables.each(function(symbol){ + feature_outputter.addToScope(nodeToString(symbol.orig[0])); + }); + + toplevel.globals.each(function(symbol){ + feature_outputter.addToScope(nodeToString(symbol.orig[0])); + }); + + feature_outputter.endScope(); +} + + +function generateFscopeConstraints(toplevel, feature_outputter){ + addScopeConstraints(toplevel, toplevel, feature_outputter); + toplevel.walk(new TreeWalker(function(node) { + if (node instanceof AST_Defun || node instanceof AST_Lambda) { + addScopeConstraints(node, toplevel, feature_outputter); + } + })); +} + function generateFnamesFeatures(toplevel, feature_outputter){ var outer_funcs = []; @@ -321,6 +356,7 @@ function FeatureJsonOutputter() { this.output = ""; this.depth = 0; this.pairs = {}; + this.cur_scope = {}; } FeatureJsonOutputter.prototype.indent = function() { @@ -428,6 +464,35 @@ FeatureJsonOutputter.prototype.dumpSymbols = function(){ this.closeArray(); }; +FeatureJsonOutputter.prototype.beginScope = function(){ + this.cur_scope = {}; +}; + +FeatureJsonOutputter.prototype.addToScope = function(a){ + var a_id = this.string_map.getId(a); + this.cur_scope[a_id] = true; +}; + +FeatureJsonOutputter.prototype.endScope = function(){ + //{"cn":"!=","n":[14,366,370,372,108,40,356]} + var keys = Object.keys(this.cur_scope); + if (keys.length <= 1) { + return; + } + + this.openElem(); + this.output += '"cn":"!=", "n":['; + + this.output += keys[0]; + for(var i = 1,length = keys.length; i < length; i++ ) { + this.output += ','; + this.output += keys[i]; + } + + this.output += "]"; + this.closeElem(); +}; + /* -----[ StringMap ]----- */ function StringMap(nice_names) { diff --git a/test/feature_extraction/fnames.js b/test/feature_extraction/fnames.js index fc7b9be1..40f5dbc3 100644 --- a/test/feature_extraction/fnames.js +++ b/test/feature_extraction/fnames.js @@ -243,4 +243,39 @@ func_return: { ] }' } -} \ No newline at end of file +} + +func_scopes: { + options = { + features : "FNAMES, FSCOPE" + }; + input: { + function foo(x,b){ + var a = x + y + 1; + (function(r) { + return r + x; + })(2); + } + } + expect: { + '{ + "query":[ + {"a": 0, "b": 1, "f2": "FNPAR"}, + {"a": 0, "b": 2, "f2": "FNPAR"}, + {"a": 0, "b": 3, "f2": "FNDECL"}, + {"cn":"!=", "n":[0,4]}, + {"cn":"!=", "n":[0,1,2,3,4]}, + {"cn":"!=", "n":[1,4,5]} + ], + "assign":[ + {"v": 0, "giv": "foo"}, + {"v": 1, "inf": "x"}, + {"v": 2, "inf": "b"}, + {"v": 3, "inf": "a"}, + {"v": 4, "giv": "y"}, + {"v": 5, "inf": "r"} + ] + }' + } +} +