aboutsummaryrefslogtreecommitdiff
path: root/lib/scope.js
diff options
context:
space:
mode:
authorMihai Bazon <mihai@bazon.net>2012-08-19 15:57:50 +0300
committerMihai Bazon <mihai@bazon.net>2012-08-19 15:57:50 +0300
commit6c35135ace95bb90c33cadeb8c16a43415eef454 (patch)
treee0458c73d79bf7bbb360b8ada938d794d683331f /lib/scope.js
parent4488758d485b0b624d4858f764bdf08b10365d3b (diff)
downloadtracifyjs-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.js88
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;
+});