So due to the current class/interface structure of the parser API, it is kind of difficult (I think?) to determine what is a variable reference. For example, let's say we are trying to write a function that determines all the globals in a program. To do this we need to note all the references to variables, then remove the ones declared. For the first theoretically trivial task of just noting all variable references, I can't do something like:
enter: function(aNode) { if (aNode.type === "Identifier") { vars.push(aNode.name) }
because Identifiers show in other places such as labels and (non-computed) properties. This is because Identifiers seem to have "multiple" inheritance paths: sometimes its Identifier>Node, sometimes Identifier>Expression. As such, it is unclear when an Identifier is behaving like an Expression (in which case I believe it for sure counts as a variable reference), or whether its behaving as something else (either a label or a property name such as a.*b*). What's left is to comb the entire parser API and special case every node (CallExpression's callee field expects an Expression, thus treat Identifiers in the callee field as if they were Identifier > Expression, in MemberExpression, if computed === true treat Identifier's in the property position as if they were Identifier > Expression, BUT if computed === false, treat identifiers in the property position as if they were Identifier > Node, etc etc etc).
Perhaps (hopefully :) ) I am missing some obvious way to handle this that isn't as error prone as noting what type(s) each field can contain to determine this, but I haven't thought of any specific way yet. This becomes more difficult of course with new syntax additions where there isn't a clear place to find these subtle definitions. Just hyphothetically, if you had something like Identifier > Node, and IdentifierExpression > Expression { identifier: Identifier }, regardless of what new syntax was introduced you'd know that IdentifierExpressions encountered anywhere are variable references (for example in CallExpression you could drop the computed bool which seems to only exist because you can't tell if an Identifier property is an Expression or not. With this system I just outlined you'd either have an Identifier or an IdentifierExpression, no ambiguity).