Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't locate variable within named function's scope when function assigned to other variable #125

Open
lainverse opened this issue Nov 6, 2017 · 4 comments

Comments

@lainverse
Copy link

Here is an example code:

let escope = require('escope');
let esprima = require('esprima');
let estraverse = require('estraverse');

let ast = esprima.parse(`
    var a = function a() {
        var b = 1;
    }, c = function () {
        var d = 2
    };
    function x() {
        var z = 3;
    }
`);

let scopeman = escope.analyze(ast);
let scope = scopeman.acquire(ast);
let fname = void 0;

estraverse.traverse(ast, {
    enter: (n, p) => {
        if (n.type === 'VariableDeclarator') {
            console.log(fname, n.id.name, !!scope.set.get(n.id.name));
            if (fname && scope.childScopes.length === 1)
                console.log('!!!subscope:', !!scope.childScopes[0].set.get(n.id.name));
        }
        if (/Function/.test(n.type)) {
            fname = n.id ? n.id.name : void 0;
            scope = scopeman.acquire(n);
        }
    },
    leave: (n, p) => {
        if (/Function/.test(n.type)) {
            fname = void 0;
            scope = scope.upper
        }
    }
});

Expected result:
undefined 'a' true
a b true
undefined 'c' true
undefined 'd' true
x z true

Actual result (notice second and third rows):
undefined 'a' true
a b false
!!!subscope: true
undefined 'c' true
undefined 'd' true
x z true

Why is it like that?

Also, the only variable available in the scope of function 'a' is 'a' which points to function itself.

@michaelficarra
Copy link
Member

Named function expressions create an extra scope object which only contain the function name binding. It should have a child scope which contains all of the bindings in the function body and parameter list.

@lainverse
Copy link
Author

lainverse commented Nov 7, 2017

To be honest such behaviour doesn't makes much sense from my point of view, but if this is what actually happening when it runs then ok. However, why does 'acquire' points to this particular scope? It's rather inconvenient and inconsistent in combination with traverse. It makes more sense to point to actual function's scope. That one would remain available through .upper anyway in case anyone ever needs it.

@michaelficarra
Copy link
Member

I disagree. The nearest scope object to the function expression's AST node is the one containing the function name. I would be okay with associating the inner scope object with the FunctionBody node, if that's not how it's already done today.

@lainverse
Copy link
Author

Ah, I see there is scope.functionExpressionScope marker there to know when to go one step further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants