diff options
author | Mihai Bazon <mihai@bazon.net> | 2012-08-19 15:57:50 +0300 |
---|---|---|
committer | Mihai Bazon <mihai@bazon.net> | 2012-08-19 15:57:50 +0300 |
commit | 6c35135ace95bb90c33cadeb8c16a43415eef454 (patch) | |
tree | e0458c73d79bf7bbb360b8ada938d794d683331f /lib/scope.js | |
parent | 4488758d485b0b624d4858f764bdf08b10365d3b (diff) | |
download | tracifyjs-6c35135ace95bb90c33cadeb8c16a43415eef454.tar.gz tracifyjs-6c35135ace95bb90c33cadeb8c16a43415eef454.zip |
simple visitor API and code to figure out scope and references
Diffstat (limited to 'lib/scope.js')
-rw-r--r-- | lib/scope.js | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/lib/scope.js b/lib/scope.js new file mode 100644 index 00000000..f8bdb2e8 --- /dev/null +++ b/lib/scope.js @@ -0,0 +1,88 @@ +AST_Scope.DEFMETHOD("figure_out_scope", function(){ + // step 1: handle definitions + var scope = null; + var tw = new TreeWalker(function(node, descend){ + if (node instanceof AST_Scope) { + var save_scope = node.parent_scope = scope; + scope = node; + descend.call(node); + scope = save_scope; + return true; // don't descend again in TreeWalker + } + if (node instanceof AST_With) { + for (var s = scope; s; s = s.parent_scope) + s.uses_with = true; + return; + } + if (node instanceof AST_SymbolDeclaration && !scope.parent_scope) { + node.global = true; + } + if (node instanceof AST_SymbolVar) { + scope.def_variable(node); + } + else if (node instanceof AST_SymbolLambda) { + scope.def_function(node); + } + else if (node instanceof AST_SymbolDefun) { + scope.parent_scope.def_function(node); + } + else if (node instanceof AST_Label) { + scope.def_label(node); + } + else if (node instanceof AST_SymbolCatch) { + // XXX: this is wrong according to ECMA-262 (12.4). the + // `catch` argument name should be visible only inside the + // catch block. For a quick fix AST_Catch should inherit + // from AST_Scope. + scope.def_variable(node); + } + else if (node instanceof AST_SymbolRef) { + node.scope = scope; + } + }); + this.walk(tw); + // step 2: find back references and eval/with + var tw = new TreeWalker(function(node){ + if (node instanceof AST_LabelRef) { + var sym = node.scope.find_label(node); + if (!sym) throw new Error("Undefined label " + node.name); + node.reference(sym); + } + else if (node instanceof AST_SymbolRef) { + var sym = node.scope.find_variable(node); + if (!sym) { + if (node.name == "eval") { + for (var s = scope; s; s = s.parent_scope) + s.uses_eval = true; + } + } else { + node.reference(sym); + } + } + }); + this.walk(tw); +}); +AST_Scope.DEFMETHOD("find_variable", function(name){ + if (name instanceof AST_Symbol) name = name.name; + return this.variables[name] || + (this.name && this.name.name == name && this.name) || + (this.parent_scope && this.parent_scope.find_variable(name)); +}); +AST_Scope.DEFMETHOD("find_label", function(name){ + if (name instanceof AST_Symbol) name = name.name; + return this.labels[name]; +}); +AST_Scope.DEFMETHOD("def_function", function(symbol){ + this.def_variable(symbol); + this.functions[symbol.name] = symbol; + symbol.scope = this; +}); +AST_Scope.DEFMETHOD("def_variable", function(symbol){ + this.variables[symbol.name] = symbol; + delete this.functions[symbol.name]; + symbol.scope = this; +}); +AST_Scope.DEFMETHOD("def_label", function(symbol){ + this.labels[symbol.name] = symbol; + symbol.scope = this; +}); |