lib/js/scope.js
function process(ast, scope){
  ast.scope = scope;
  ast.names = [];
  ast.scopes = [];

  var varWalker = function(token, scope){
    scope.declarations.push({
      type: 'var',
      name: token.id.name,
      parent: this.top(1),
      loc: token.loc.start
    });

    scope.put(token.id.name, {
      type: 'var',
      token: token.init,
      loc: token.loc.start
    });
  };

  return walker.walk(ast, {
    VariableDeclarator: varWalker,
    FunctionDeclaration: fnWalker,
    FunctionExpression: fnWalker,
    ArrowFunctionExpression: fnWalker,
    ExpressionStatement: function(token){
      if (token.directive && token.directive.toLowerCase() === 'use strict')
        scope.strict = true;
    },

    CatchClause: function(token, scope){
      var newScope = new Scope('catch', scope);

      scope.put(token.param.name, {
        type: 'catch',
        token: null
      });
      token.body.scope = newScope;

      this.scopes.push(scope);
    },

    Identifier: function(token, scope){
      var parent = this.top(1);

      // let insane begin!
      // todo implement more efficient solution in a future version
      var isLabel = parent.type === 'LabeledStatement' || parent.type === 'ContinueStatement' || parent.type === 'BreakStatement';
      var isFunctionName = parent.type === 'FunctionDeclaration' || parent.type === 'FunctionExpression' || parent.type === 'ClassDeclaration' || parent.type === 'ClassExpression';
      var isProperty = parent.type === 'Property';
      var isMemberExpression = parent.type === 'MemberExpression';
      var isAssignmentExpression = parent.type === 'AssignmentExpression';
      var isVariableDeclarator = parent.type === 'VariableDeclarator';

      if (isLabel || isFunctionName || isProperty || isMemberExpression || isAssignmentExpression || isVariableDeclarator)
      {
        var isObjectKey = isProperty && parent.key === token && parent.computed;
        var isObjectValue = isProperty && parent.value === token;
        var isMemberExpressionProperty = isMemberExpression && parent.property === token && parent.computed;
        var isMemberExpressionObject = isMemberExpression&& parent.object === token;
        var isVariableInit = isVariableDeclarator && parent.init === token;
        var isLeftOfAssignment = isAssignmentExpression && parent.left === token && parent.operator !== '=';
        var isRightOfAssignment = isAssignmentExpression && parent.right === token;
        // is it for..in variable? (mark its name as used)
        var isVarInForIn = false;
        if (isVariableDeclarator)
        {
          var declarationParent = this.top(3);
          isVarInForIn = declarationParent && declarationParent.type === 'ForInStatement';
        }

        if (isFunctionName || isLabel ||
          !isObjectKey && !isObjectValue &&
          !isMemberExpressionProperty && !isMemberExpressionObject &&
          !isLeftOfAssignment && !isRightOfAssignment &&
          !isVariableInit && !isVarInForIn)
          return;
      }

      this.names.push({
        scope: scope,
        token: token
      });
    }
  }, {
    names: ast.names,
    scopes: ast.scopes
  });
}
function process(ast, scope){
  ast.scope = scope;
  ast.names = [];
  ast.scopes = [];

  var varWalker = function(token, scope){
    scope.declarations.push({
      type: 'var',
      name: token.id.name,
      parent: this.top(1),
      loc: token.loc.start
    });

    scope.put(token.id.name, {
      type: 'var',
      token: token.init,
      loc: token.loc.start
    });
  };

  return walker.walk(ast, {
    VariableDeclarator: varWalker,
    FunctionDeclaration: fnWalker,
    FunctionExpression: fnWalker,
    ArrowFunctionExpression: fnWalker,
    ExpressionStatement: function(token){
      if (token.directive && token.directive.toLowerCase() === 'use strict')
        scope.strict = true;
    },

    CatchClause: function(token, scope){
      var newScope = new Scope('catch', scope);

      scope.put(token.param.name, {
        type: 'catch',
        token: null
      });
      token.body.scope = newScope;

      this.scopes.push(scope);
    },

    Identifier: function(token, scope){
      var parent = this.top(1);

      // let insane begin!
      // todo implement more efficient solution in a future version
      var isLabel = parent.type === 'LabeledStatement' || parent.type === 'ContinueStatement' || parent.type === 'BreakStatement';
      var isFunctionName = parent.type === 'FunctionDeclaration' || parent.type === 'FunctionExpression' || parent.type === 'ClassDeclaration' || parent.type === 'ClassExpression';
      var isProperty = parent.type === 'Property';
      var isMemberExpression = parent.type === 'MemberExpression';
      var isAssignmentExpression = parent.type === 'AssignmentExpression';
      var isVariableDeclarator = parent.type === 'VariableDeclarator';

      if (isLabel || isFunctionName || isProperty || isMemberExpression || isAssignmentExpression || isVariableDeclarator)
      {
        var isObjectKey = isProperty && parent.key === token && parent.computed;
        var isObjectValue = isProperty && parent.value === token;
        var isMemberExpressionProperty = isMemberExpression && parent.property === token && parent.computed;
        var isMemberExpressionObject = isMemberExpression&& parent.object === token;
        var isVariableInit = isVariableDeclarator && parent.init === token;
        var isLeftOfAssignment = isAssignmentExpression && parent.left === token && parent.operator !== '=';
        var isRightOfAssignment = isAssignmentExpression && parent.right === token;
        // is it for..in variable? (mark its name as used)
        var isVarInForIn = false;
        if (isVariableDeclarator)
        {
          var declarationParent = this.top(3);
          isVarInForIn = declarationParent && declarationParent.type === 'ForInStatement';
        }

        if (isFunctionName || isLabel ||
          !isObjectKey && !isObjectValue &&
          !isMemberExpressionProperty && !isMemberExpressionObject &&
          !isLeftOfAssignment && !isRightOfAssignment &&
          !isVariableInit && !isVarInForIn)
          return;
      }

      this.names.push({
        scope: scope,
        token: token
      });
    }
  }, {
    names: ast.names,
    scopes: ast.scopes
  });
}
main function