/**
* Copyright (c) 2012-2016 André Bargull
* Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms.
*
* <https://github.com/anba/es6draft>
*/
package com.github.anba.es6draft.semantics;
import java.util.List;
import com.github.anba.es6draft.ast.*;
import com.github.anba.es6draft.ast.scope.Name;
/**
* Static Semantics: BoundNames
*/
final class BoundNames extends DefaultNodeVisitor<List<Name>, List<Name>> {
static final BoundNames INSTANCE = new BoundNames();
@Override
protected List<Name> visit(Node node, List<Name> names) {
throw new IllegalStateException();
}
private List<Name> forEach(Iterable<? extends Node> list, List<Name> names) {
for (Node node : list) {
node.accept(this, names);
}
return names;
}
/**
* <pre>
* LexicalDeclaration : LetOrConst BindingList ;
* BindingList : BindingList , LexicalBinding
* </pre>
*/
@Override
public List<Name> visit(LexicalDeclaration node, List<Name> names) {
return forEach(node.getElements(), names);
}
/**
* <pre>
* LexicalBinding : BindingIdentifier Initializer<span><sub>opt</sub></span>
* LexicalBinding: BindingPattern Initializer
* </pre>
*/
@Override
public List<Name> visit(LexicalBinding node, List<Name> names) {
return node.getBinding().accept(this, names);
}
/**
* <pre>
* BindingIdentifier : Identifier
* </pre>
*/
@Override
public List<Name> visit(BindingIdentifier node, List<Name> names) {
names.add(node.getName());
return names;
}
/**
* <pre>
* VariableDeclarationList : VariableDeclarationList , VariableDeclaration
* </pre>
*/
@Override
public List<Name> visit(VariableStatement node, List<Name> names) {
return forEach(node.getElements(), names);
}
/**
* <pre>
* VariableDeclaration : BindingIdentifier Initializer<span><sub>opt</sub></span>
* VariableDeclaration: BindingPattern Initializer
* </pre>
*/
@Override
public List<Name> visit(VariableDeclaration node, List<Name> names) {
return node.getBinding().accept(this, names);
}
/**
* <pre>
* ArrayBindingPattern : [ Elision<span><sub>opt</sub></span> ]
* ArrayBindingPattern : [ Elision<span><sub>opt</sub></span> BindingRestElement ]
* ArrayBindingPattern : [ BindingElementList , Elision<span><sub>opt</sub></span> ]
* ArrayBindingPattern : [ BindingElementList , Elision<span><sub>opt</sub></span> BindingRestElement ]
* BindingElementList : Elision<span><sub>opt</sub></span> BindingElement
* BindingElementList : BindingElementList , Elision<span><sub>opt</sub></span> BindingElement
* </pre>
*/
@Override
public List<Name> visit(ArrayBindingPattern node, List<Name> names) {
return forEach(node.getElements(), names);
}
/**
* <pre>
* ObjectBindingPattern: { }
* BindingPropertyList : BindingPropertyList , BindingProperty
* </pre>
*/
@Override
public List<Name> visit(ObjectBindingPattern node, List<Name> names) {
forEach(node.getProperties(), names);
if (node.getRest() != null) {
node.getRest().accept(this, names);
}
return names;
}
/**
* <pre>
* BindingProperty : SingleNameBinding
* BindingProperty : PropertyName : BindingElement
* </pre>
*/
@Override
public List<Name> visit(BindingProperty node, List<Name> names) {
return node.getBinding().accept(this, names);
}
/**
* <pre>
* BindingRestProperty : ... BindingIdentifier
* </pre>
*/
@Override
public List<Name> visit(BindingRestProperty node, List<Name> names) {
return node.getBindingIdentifier().accept(this, names);
}
/**
* <pre>
* BindingElement : SingleNameBinding
* BindingElement : BindingPattern Initializer<span><sub>opt</sub></span>
* SingleNameBinding : BindingIdentifier Initializer<span><sub>opt</sub></span>
* </pre>
*/
@Override
public List<Name> visit(BindingElement node, List<Name> names) {
return node.getBinding().accept(this, names);
}
/**
* <pre>
* BindingRestElement : ... BindingIdentifier
* </pre>
*/
@Override
public List<Name> visit(BindingRestElement node, List<Name> names) {
return node.getBinding().accept(this, names);
}
/**
* <pre>
* Elision : ,
* Elision : Elision ,
* </pre>
*/
@Override
public List<Name> visit(BindingElision node, List<Name> names) {
return names;
}
/**
* <pre>
* for each (ForDeclaration in Expression ) Statement
* ForDeclaration : LetOrConst ForBinding
* </pre>
*/
@Override
public List<Name> visit(ForEachStatement node, List<Name> names) {
if (node.getHead() instanceof LexicalDeclaration) {
return node.getHead().accept(this, names);
}
return names;
}
/**
* <pre>
* for (ForDeclaration in Expression ) Statement
* ForDeclaration : LetOrConst ForBinding
* </pre>
*/
@Override
public List<Name> visit(ForInStatement node, List<Name> names) {
if (node.getHead() instanceof LexicalDeclaration) {
return node.getHead().accept(this, names);
}
return names;
}
/**
* <pre>
* for (ForDeclaration of Expression ) Statement
* ForDeclaration : LetOrConst ForBinding
* </pre>
*/
@Override
public List<Name> visit(ForOfStatement node, List<Name> names) {
if (node.getHead() instanceof LexicalDeclaration) {
return node.getHead().accept(this, names);
}
return names;
}
/**
* <pre>
* FunctionDeclaration : function BindingIdentifier ( FormalParameterList ) { FunctionBody }
* FunctionDeclaration : function ( FormalParameters ) { FunctionBody }
* </pre>
*/
@Override
public List<Name> visit(FunctionDeclaration node, List<Name> names) {
names.add(node.getName());
return names;
}
/**
* <pre>
* GeneratorDeclaration : function * BindingIdentifier ( FormalParameterList ) { FunctionBody }
* GeneratorDeclaration : function * ( FormalParameters ) { GeneratorBody }
* </pre>
*/
@Override
public List<Name> visit(GeneratorDeclaration node, List<Name> names) {
names.add(node.getName());
return names;
}
/**
* <pre>
* GeneratorDeclaration : function * BindingIdentifier ( FormalParameterList ) { FunctionBody }
* </pre>
*/
@Override
public List<Name> visit(LegacyGeneratorDeclaration node, List<Name> names) {
names.add(node.getName());
return names;
}
/**
* <pre>
* ClassDeclaration : class BindingIdentifier ClassTail
* ClassDeclaration : class ClassTail
* </pre>
*/
@Override
public List<Name> visit(ClassDeclaration node, List<Name> names) {
names.add(node.getName());
return names;
}
/**
* <pre>
* AsyncFunctionDeclaration : async function BindingIdentifier ( FormalParameterList ) { FunctionBody }
* AsyncFunctionDeclaration : async function ( FormalParameterList ) { FunctionBody }
* </pre>
*/
@Override
public List<Name> visit(AsyncFunctionDeclaration node, List<Name> names) {
names.add(node.getName());
return names;
}
@Override
public List<Name> visit(FormalParameter node, List<Name> names) {
return node.getElement().accept(this, names);
}
/**
* <pre>
* StrictFormalParameters :
* FormalParameters
* FormalParameters :
* [empty]
* FormalParameterList
* FormalParameterList :
* FunctionRestParameter
* FormalsList
* FormalsList , FunctionRestParameter
* FormalsList :
* FormalParameter
* FormalsList , FormalParameter
* </pre>
*/
@Override
public List<Name> visit(FormalParameterList node, List<Name> names) {
return forEach(node.getFormals(), names);
}
/**
* <pre>
* ImportDeclaration : ModuleImport
* ImportDeclaration : import ImportClause FromClause ;
* ImportDeclaration : import ModuleSpecifier ;
* </pre>
*/
@Override
public List<Name> visit(ImportDeclaration node, List<Name> names) {
switch (node.getType()) {
case ImportFrom:
return node.getImportClause().accept(this, names);
case ImportModule:
return names;
default:
throw new AssertionError();
}
}
/**
* <pre>
* ImportClause : ImportedBinding , NamedImports
* ImportsList : ImportsList , ImportSpecifier
* </pre>
*/
@Override
public List<Name> visit(ImportClause node, List<Name> names) {
if (node.getDefaultEntry() != null) {
node.getDefaultEntry().accept(this, names);
}
if (node.getNameSpace() != null) {
node.getNameSpace().accept(this, names);
}
return forEach(node.getNamedImports(), names);
}
/**
* <pre>
* ImportSpecifier : IdentifierName as ImportedBinding
* </pre>
*/
@Override
public List<Name> visit(ImportSpecifier node, List<Name> names) {
return node.getLocalName().accept(this, names);
}
/**
* <pre>
* ExportDeclaration :
* export * FromClause ;
* export ExportClause FromClause ;
* export ExportClause ;
* export VariableStatement
* export Declaration
* export default HoistableDeclaration
* export default ClassDeclaration
* export default AssignmentExpression ;
* </pre>
*/
@Override
public List<Name> visit(ExportDeclaration node, List<Name> names) {
switch (node.getType()) {
case All:
case External:
case Local:
return names;
case Variable:
return node.getVariableStatement().accept(this, names);
case Declaration:
return node.getDeclaration().accept(this, names);
case DefaultHoistableDeclaration:
if (node.getHoistableDeclaration().getIdentifier() != null) {
names.add(new Name(Name.DEFAULT_EXPORT));
}
return node.getHoistableDeclaration().accept(this, names);
case DefaultClassDeclaration:
if (node.getClassDeclaration().getIdentifier() != null) {
names.add(new Name(Name.DEFAULT_EXPORT));
}
return node.getClassDeclaration().accept(this, names);
case DefaultExpression:
return node.getExpression().accept(this, names);
default:
throw new AssertionError();
}
}
/**
* <pre>
* ExportDeclaration :
* export default AssignmentExpression ;
* </pre>
*/
@Override
public List<Name> visit(ExportDefaultExpression node, List<Name> names) {
return node.getBinding().accept(this, names);
}
}