Skip to content

Commit

Permalink
Support AssignmentPattern
Browse files Browse the repository at this point in the history
This is used for default values.
After that, we need to drop default parameter support.
CAUTION: There's no fully supported TDZ scope yet.
  • Loading branch information
Constellation committed Mar 11, 2015
1 parent dcb3231 commit b713c53
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 47 deletions.
96 changes: 49 additions & 47 deletions src/referencer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,64 +21,69 @@
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import estraverse from 'estraverse';
import { Syntax } from 'estraverse';
import esrecurse from 'esrecurse';
import Reference from './reference';
import Variable from './variable';
import { ParameterDefinition, Definition } from './definition';
import assert from 'assert';

const Syntax = estraverse.Syntax;
class PatternVisitor extends esrecurse.Visitor {
constructor(rootPattern, referencer, callback) {
super(this);
this.referencer = referencer;
this.callback = callback;
}

function traverseIdentifierInPattern(rootPattern, callback) {
estraverse.traverse(rootPattern, {
enter(pattern, parent) {
var i, iz, element, property;
perform(pattern) {
if (pattern.type === Syntax.Identifier) {
this.callback(pattern, true);
return;
}
this.visit(pattern);
}

switch (pattern.type) {
case Syntax.Identifier:
// Toplevel identifier.
if (parent === null) {
callback(pattern, true);
}
break;
Identifier(pattern) {
this.callback(pattern, false);
}

case Syntax.SpreadElement:
if (pattern.argument.type === Syntax.Identifier) {
callback(pattern.argument, false);
}
break;

case Syntax.ObjectPattern:
for (i = 0, iz = pattern.properties.length; i < iz; ++i) {
property = pattern.properties[i];
if (property.shorthand) {
callback(property.key, false);
continue;
}
if (property.value.type === Syntax.Identifier) {
callback(property.value, false);
continue;
}
}
break;

case Syntax.ArrayPattern:
for (i = 0, iz = pattern.elements.length; i < iz; ++i) {
element = pattern.elements[i];
if (element && element.type === Syntax.Identifier) {
callback(element, false);
}
}
break;
ObjectPattern(pattern) {
var i, iz, property;
for (i = 0, iz = pattern.properties.length; i < iz; ++i) {
property = pattern.properties[i];
if (property.shorthand) {
this.visit(property.key);
continue;
}
this.visit(property.value);
}
}

ArrayPattern(pattern) {
var i, iz, element;
for (i = 0, iz = pattern.elements.length; i < iz; ++i) {
element = pattern.elements[i];
if (element) {
this.visit(element);
}
}
});
}

AssignmentPattern(pattern) {
this.visit(pattern.left);
// FIXME: Condier TDZ scope.
this.referencer.visit(pattern.right);
}
}

function traverseIdentifierInPattern(rootPattern, referencer, callback) {
var visitor = new PatternVisitor(rootPattern, referencer, callback);
visitor.perform(rootPattern);
}

function isPattern(node) {
var nodeType = node.type;
return nodeType === Syntax.Identifier || nodeType === Syntax.ObjectPattern || nodeType === Syntax.ArrayPattern || nodeType === Syntax.SpreadElement;
return nodeType === Syntax.Identifier || nodeType === Syntax.ObjectPattern || nodeType === Syntax.ArrayPattern || nodeType === Syntax.SpreadElement || nodeType === Syntax.RestElement || nodeType === Syntax.AssignmentPattern;
}

// Importing ImportDeclaration.
Expand Down Expand Up @@ -178,7 +183,7 @@ export default class Referencer extends esrecurse.Visitor {
}

visitPattern(node, callback) {
traverseIdentifierInPattern(node, callback);
traverseIdentifierInPattern(node, this, callback);
}

visitFunction(node) {
Expand Down Expand Up @@ -332,9 +337,6 @@ export default class Referencer extends esrecurse.Visitor {

decl = node.declarations[index];
init = decl.init;
// FIXME: Don't consider initializer with complex patterns.
// Such as,
// var [a, b, c = 20] = array;
this.visitPattern(decl.id, (pattern, toplevel) => {
variableTargetScope.__define(pattern,
new Definition(
Expand Down
76 changes: 76 additions & 0 deletions test/es6-destructuring-assignments.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

expect = require('chai').expect
harmony = require '../third_party/esprima'
espree = require '../third_party/espree'
escope = require '..'

describe 'ES6 destructuring assignments', ->
Expand Down Expand Up @@ -703,4 +704,79 @@ describe 'ES6 destructuring assignments', ->
expect(scope.variables[index].name).to.be.equal name
expect(scope.references).to.have.length 0

it 'default values and patterns in var', ->
ast = espree """
(function () {
var [a, b, c, d = 20 ] = array;
}());
"""

scopeManager = escope.analyze ast, ecmaVersion: 6
expect(scopeManager.scopes).to.have.length 2

scope = scopeManager.scopes[0]
globalScope = scope
expect(scope.type).to.be.equal 'global'
expect(scope.variables).to.have.length 0
expect(scope.references).to.have.length 0

scope = scopeManager.scopes[1]
expect(scope.type).to.be.equal 'function'
expect(scope.variables).to.have.length 5
for name, index in [
'arguments'
'a'
'b'
'c'
'd'
]
expect(scope.variables[index].name).to.be.equal name
expect(scope.references).to.have.length 5
for name, index in [
'a'
'b'
'c'
'd'
'array'
]
expect(scope.references[index].identifier.name).to.be.equal name

it 'default values containing references and patterns in var', ->
ast = espree """
(function () {
var [a, b, c, d = e ] = array;
}());
"""

scopeManager = escope.analyze ast, ecmaVersion: 6
expect(scopeManager.scopes).to.have.length 2

scope = scopeManager.scopes[0]
globalScope = scope
expect(scope.type).to.be.equal 'global'
expect(scope.variables).to.have.length 0
expect(scope.references).to.have.length 0

scope = scopeManager.scopes[1]
expect(scope.type).to.be.equal 'function'
expect(scope.variables).to.have.length 5
for name, index in [
'arguments'
'a'
'b'
'c'
'd'
]
expect(scope.variables[index].name).to.be.equal name
expect(scope.references).to.have.length 6
for name, index in [
'a'
'b'
'c'
'd'
'e'
'array'
]
expect(scope.references[index].identifier.name).to.be.equal name

# vim: set sw=4 ts=4 et tw=80 :

0 comments on commit b713c53

Please sign in to comment.