Last active
December 17, 2015 00:49
-
-
Save michaelficarra/5523730 to your computer and use it in GitHub Desktop.
identifier-only scope colouring levels
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fs = require 'fs' | |
esprima = require 'esprima' | |
escope = require 'escope' | |
eslevels = require 'eslevels' | |
js = (fs.readFileSync './input.js').toString() | |
ast = esprima.parse js, {range: yes} | |
scopes = (escope.analyze ast).scopes | |
scopeLevel = (scope) -> | |
return 0 unless scope? | |
level = 0 | |
while scope = scope.upper | |
++level unless scope.functionExpressionScope | |
level | |
levels = [] | |
for scope in scopes | |
level = scopeLevel scope | |
for variable in scope.variables | |
# parameters and NFE names and catch variables and uninitialised variable declarations | |
if variable.identifiers[0] and (not variable.defs[0].node.init or variable.defs[0].type in ['Parameter', 'CatchClause', 'FunctionName']) | |
levels.push [level, variable.identifiers[0].range[0], variable.identifiers[0].range[1] - 1] | |
# references to the variables declared in this scope | |
for reference in variable.references when reference.identifier | |
levels.push [level, reference.identifier.range[0], reference.identifier.range[1] - 1] | |
switch scope.type | |
when 'global' | |
# unresolved globals | |
for reference in scope.through | |
levels.push [0, reference.identifier.range[0], reference.identifier.range[1] - 1] | |
when 'function' | |
# `function` keyword | |
unless scope.functionExpressionScope | |
levels.push [level, scope.block.range[0], scope.block.range[0] + 8 - 1] | |
when 'with' | |
# `with` keyword | |
levels.push [level, scope.block.range[0], scope.block.range[0] + 4 - 1] | |
when 'catch' | |
# `catch` keyword | |
levels.push [level, scope.block.range[0], scope.block.range[0] + 5 - 1] | |
levels.sort (a, b) -> if a[1] < b[1] then -1 else 1 | |
console.dir levels |
You are theoretician ๐ In practice, how many people use redeclaration of exception variable? (I think it also a bad coding style).
(function () {
var a="OUTSIDE";
try {throw new Error();} catch(a) { var a = "IN"; console.log(a);}
console.log(a);
}())
This code will output "IN" and "OUTSIDE", and I see that the reference to the catch variable takes precedence, so the current escope library and new escope-demo page handled it in the right way.
(function () {
var a="OUTSIDE";
try {throw new Error();} catch(a) { var a; console.log(a);}
console.log(a);
}())
will output "Error{}" and "OUTSIDE". And "var a" in "Highlight only important constructions" mode is not highlighted on escope-demo page. I think it is a correct visualization.
Or I miss something?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TODO: the position of the
a
in the following program is not handled properly because it is both an unreferenced variable declaration and a reference to the catch variable.I guess JavaScript can have overlapping scope levels. In other words, a single character can be simultaneously affecting more than one scope. /cc @mazurov and @Constellation since they'd probably be interested.
I'm thinking maybe unreferenced variable declarations should not be highlighted.
edit: fixed by changing the rule from "declarations of unreferenced variables" to "uninitialised variable declarations". Now the reference to the catch variable takes precedence ๐. That character should still technically be highlighted with both colours.