diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ast.js | 20 | ||||
-rw-r--r-- | lib/output.js | 16 | ||||
-rw-r--r-- | lib/scope.js | 53 |
3 files changed, 58 insertions, 31 deletions
@@ -156,16 +156,7 @@ var AST_With = DEFNODE("With", "expression", { /* -----[ scope and functions ]----- */ var AST_Scope = DEFNODE("Scope", null, { - $documentation: "Base class for all statements introducing a lexical scope", - initialize: function() { - this.variables = {}; // map name to AST_SymbolVar (variables defined in this scope; includes functions) - this.functions = {}; // 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 = null; // the parent scope - this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes - this.cname = -1; // the current index for mangling functions/variables - } + $documentation: "Base class for all statements introducing a lexical scope" }, AST_BlockStatement); var AST_Toplevel = DEFNODE("Toplevel", null, { @@ -174,10 +165,6 @@ var AST_Toplevel = DEFNODE("Toplevel", null, { var AST_Lambda = DEFNODE("Lambda", "name argnames", { $documentation: "Base class for functions", - initialize: function() { - AST_Scope.prototype.initialize.call(this); - this.uses_arguments = false; - }, _walk: function(visitor) { return visitor._visit(this, function(){ if (this.name) this.name._walk(visitor); @@ -479,10 +466,7 @@ var AST_ObjectGetter = DEFNODE("ObjectGetter", null, { var AST_Symbol = DEFNODE("Symbol", "scope name", { }); -var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "references", { - initialize: function() { - this.references = []; - } +var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", null, { }, AST_Symbol); var AST_SymbolVar = DEFNODE("SymbolVar", null, { diff --git a/lib/output.js b/lib/output.js index 0d6518df..bd38f9d5 100644 --- a/lib/output.js +++ b/lib/output.js @@ -4,12 +4,11 @@ function OutputStream(options) { indent_start : 0, indent_level : 4, quote_keys : false, - space_colon : false, + space_colon : true, ascii_only : false, inline_script : false, width : 80, - beautify : true, - scope_style : "negate" + beautify : true }); var indentation = 0; @@ -184,7 +183,7 @@ function OutputStream(options) { function colon() { print(":"); - space(); + if (options.space_colon) space(); }; var stack = []; @@ -204,7 +203,7 @@ function OutputStream(options) { with_block : with_block, with_parens : with_parens, with_square : with_square, - options : function(opt) { return options[opt] }, + option : function(opt) { return options[opt] }, line : function() { return current_line }, col : function() { return current_col }, pos : function() { return current_pos }, @@ -228,7 +227,6 @@ function OutputStream(options) { nodetype.DEFMETHOD("print", function(stream){ var self = this; stream.push_node(self); - //stream.print("«" + self.TYPE + ":" + self.start.line + ":" + self.start.col + "»"); if (self.needs_parens(stream)) { stream.with_parens(function(){ generator(self, stream); @@ -777,10 +775,10 @@ function OutputStream(options) { }); DEFPRINT(AST_ObjectKeyVal, function(self, output){ var key = self.key; - if (output.options("quote_keys")) { + if (output.option("quote_keys")) { output.print_string(key); } else if ((typeof key == "number" - || !output.options("beautify") + || !output.option("beautify") && +key + "" == key) && parseFloat(key) >= 0) { output.print(make_num(key)); @@ -863,7 +861,7 @@ function OutputStream(options) { // self should be AST_New. decide if we want to show parens or not. function no_constructor_parens(self, output) { - return self.args.length == 0 && !output.options("beautify"); + return self.args.length == 0 && !output.option("beautify"); }; function best_of(a) { diff --git a/lib/scope.js b/lib/scope.js index a5719bf3..0ac797e0 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -11,6 +11,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){ var labels = {}; var tw = new TreeWalker(function(node, descend){ if (node instanceof AST_Scope) { + node.init_scope_vars(); var save_scope = node.parent_scope = scope; scope = node; descend(); @@ -31,6 +32,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){ delete labels[l.name]; return true; // no descend again } + if (node instanceof AST_SymbolDeclaration) { + node.init_scope_vars(); + } if (node instanceof AST_SymbolLambda) { scope.def_function(node); } @@ -65,15 +69,27 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){ }); this.walk(tw); - // pass 2: find back references and eval/with - var tw = new TreeWalker(function(node){ + // pass 2: find back references and eval + var func = null; + var tw = new TreeWalker(function(node, descend){ + if (node instanceof AST_Lambda) { + var prev_func = func; + func = node; + descend(); + func = prev_func; + return true; + } if (node instanceof AST_SymbolRef) { var sym = node.scope.find_variable(node); node.reference(sym); if (!sym) { if (node.name == "eval") { - for (var s = node.scope; s; s = s.parent_scope) - s.uses_eval = true; + for (var s = node.scope; + s && !s.uses_eval; + s = s.parent_scope) s.uses_eval = true; + } + if (node.name == "arguments") { + func.uses_arguments = true; } } } @@ -81,11 +97,31 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){ this.walk(tw); }); +AST_Scope.DEFMETHOD("init_scope_vars", function(){ + this.variables = {}; // map name to AST_SymbolVar (variables defined in this scope; includes functions) + this.functions = {}; // 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 = null; // the parent scope + this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes + this.cname = -1; // the current index for mangling functions/variables +}); + +AST_Lambda.DEFMETHOD("init_scope_vars", function(){ + AST_Scope.prototype.init_scope_vars.call(this); + this.uses_arguments = false; +}); + +AST_SymbolDeclaration.DEFMETHOD("init_scope_vars", function(){ + this.references = []; +}); + AST_Toplevel.DEFMETHOD("scope_warnings", function(options){ options = defaults(options, { undeclared : false, // this makes a lot of noise unreferenced : true, assign_to_global : true, + func_arguments : true, eval : true }); var tw = new TreeWalker(function(node){ @@ -132,6 +168,15 @@ AST_Toplevel.DEFMETHOD("scope_warnings", function(options){ col: node.start.col }); } + if (options.func_arguments + && node instanceof AST_Lambda + && node.uses_arguments) { + AST_Node.warn("arguments used in function {name} [{line},{col}]", { + name: node.name ? node.name.name : "anonymous", + line: node.start.line, + col: node.start.col + }); + } }); this.walk(tw); }); |