Search code examples
javascriptscopeabstract-syntax-treeesprima

How can I know when the scope changes within an abstract syntax tree?


Can someone help me with figuring out how to know when the scope changing while traversing the ast tree? I am using the esprima parser and I know that babel does this but I want to create my own to understand how it works and help increase my knowledge with using asts.

So how would I go about to knowing the scopes of each node?


var global = "I am in the global scope";

function scopeOne() {
  var one = "I am in the scope created by `scopeOne()`";

  function scopeTwo() {
    var two = "I am in the scope created by `scopeTwo()`";
  }
}


Solution

  • The base idea is to determine how many scopes is upper then current node. For this purpose we need to check:

    • is current node is Program, the upper most node in AST;
    • is current node is BlockStatements that is used by all kinds of functions and statements (like IfConditionStatement, loops etc);

    Then we just increase counter of scopes, this way we can distinguish them in the similar to Babel way.

    Here is how it can look like written in 🐊Putout, tool I'm working on:

    export const traverse = () => {
        let uid = 0;
        return {
            'BlockStatement|Program'(path) {
                console.log('babel scope', path.scope.uid);
                console.log('our scope', ++uid);
            },
        }
    };
    

    For code like this:

    var global = "I am in the global scope";
    
    function scopeOne() {
      var one = "I am in the scope created by `scopeOne()`";
    
      function scopeTwo() {
        var two = "I am in the scope created by `scopeTwo()`";
      }
    }
    
    if (a > 3) {
        console.log('hello');
    }
    

    It outputs:

    Scopes

    Playground: https://putout.cloudcmd.io/#/gist/06b547b6cd6f132b5300dd9d4473177e/b2a193c5c7233c309c46222cbb9ea8a46bd99a92