/*
* Copyright 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.engine.ast;
import com.google.dart.engine.element.ConstructorElement;
import com.google.dart.engine.scanner.Token;
import java.util.List;
/**
* Instances of the class {@code ConstructorDeclaration} represent a constructor declaration.
*
* <pre>
* constructorDeclaration ::=
* constructorSignature {@link FunctionBody body}?
* | constructorName formalParameterList ':' 'this' ('.' {@link SimpleIdentifier name})? arguments
*
* constructorSignature ::=
* 'external'? constructorName formalParameterList initializerList?
* | 'external'? 'factory' factoryName formalParameterList initializerList?
* | 'external'? 'const' constructorName formalParameterList initializerList?
*
* constructorName ::=
* {@link SimpleIdentifier returnType} ('.' {@link SimpleIdentifier name})?
*
* factoryName ::=
* {@link Identifier returnType} ('.' {@link SimpleIdentifier name})?
*
* initializerList ::=
* ':' {@link ConstructorInitializer initializer} (',' {@link ConstructorInitializer initializer})*
* </pre>
*
* @coverage dart.engine.ast
*/
public class ConstructorDeclaration extends ClassMember {
/**
* The token for the 'external' keyword, or {@code null} if the constructor is not external.
*/
private Token externalKeyword;
/**
* The token for the 'const' keyword, or {@code null} if the constructor is not a const
* constructor.
*/
private Token constKeyword;
/**
* The token for the 'factory' keyword, or {@code null} if the constructor is not a factory
* constructor.
*/
private Token factoryKeyword;
/**
* The type of object being created. This can be different than the type in which the constructor
* is being declared if the constructor is the implementation of a factory constructor.
*/
private Identifier returnType;
/**
* The token for the period before the constructor name, or {@code null} if the constructor being
* declared is unnamed.
*/
private Token period;
/**
* The name of the constructor, or {@code null} if the constructor being declared is unnamed.
*/
private SimpleIdentifier name;
/**
* The parameters associated with the constructor.
*/
private FormalParameterList parameters;
/**
* The token for the separator (colon or equals) before the initializer list or redirection, or
* {@code null} if there are no initializers.
*/
private Token separator;
/**
* The initializers associated with the constructor.
*/
private NodeList<ConstructorInitializer> initializers = new NodeList<ConstructorInitializer>(this);
/**
* The name of the constructor to which this constructor will be redirected, or {@code null} if
* this is not a redirecting factory constructor.
*/
private ConstructorName redirectedConstructor;
/**
* The body of the constructor, or {@code null} if the constructor does not have a body.
*/
private FunctionBody body;
/**
* The element associated with this constructor, or {@code null} if the AST structure has not been
* resolved or if this constructor could not be resolved.
*/
private ConstructorElement element;
/**
* Initialize a newly created constructor declaration.
*
* @param externalKeyword the token for the 'external' keyword
* @param comment the documentation comment associated with this constructor
* @param metadata the annotations associated with this constructor
* @param constKeyword the token for the 'const' keyword
* @param factoryKeyword the token for the 'factory' keyword
* @param returnType the return type of the constructor
* @param period the token for the period before the constructor name
* @param name the name of the constructor
* @param parameters the parameters associated with the constructor
* @param separator the token for the colon or equals before the initializers
* @param initializers the initializers associated with the constructor
* @param redirectedConstructor the name of the constructor to which this constructor will be
* redirected
* @param body the body of the constructor
*/
public ConstructorDeclaration(Comment comment, List<Annotation> metadata, Token externalKeyword,
Token constKeyword, Token factoryKeyword, Identifier returnType, Token period,
SimpleIdentifier name, FormalParameterList parameters, Token separator,
List<ConstructorInitializer> initializers, ConstructorName redirectedConstructor,
FunctionBody body) {
super(comment, metadata);
this.externalKeyword = externalKeyword;
this.constKeyword = constKeyword;
this.factoryKeyword = factoryKeyword;
this.returnType = becomeParentOf(returnType);
this.period = period;
this.name = becomeParentOf(name);
this.parameters = becomeParentOf(parameters);
this.separator = separator;
this.initializers.addAll(initializers);
this.redirectedConstructor = becomeParentOf(redirectedConstructor);
this.body = becomeParentOf(body);
}
@Override
public <R> R accept(AstVisitor<R> visitor) {
return visitor.visitConstructorDeclaration(this);
}
/**
* Return the body of the constructor, or {@code null} if the constructor does not have a body.
*
* @return the body of the constructor
*/
public FunctionBody getBody() {
return body;
}
/**
* Return the token for the 'const' keyword.
*
* @return the token for the 'const' keyword
*/
public Token getConstKeyword() {
return constKeyword;
}
@Override
public ConstructorElement getElement() {
return element;
}
@Override
public Token getEndToken() {
if (body != null) {
return body.getEndToken();
} else if (!initializers.isEmpty()) {
return initializers.getEndToken();
}
return parameters.getEndToken();
}
/**
* Return the token for the 'external' keyword, or {@code null} if the constructor is not
* external.
*
* @return the token for the 'external' keyword
*/
public Token getExternalKeyword() {
return externalKeyword;
}
/**
* Return the token for the 'factory' keyword.
*
* @return the token for the 'factory' keyword
*/
public Token getFactoryKeyword() {
return factoryKeyword;
}
/**
* Return the initializers associated with the constructor.
*
* @return the initializers associated with the constructor
*/
public NodeList<ConstructorInitializer> getInitializers() {
return initializers;
}
/**
* Return the name of the constructor, or {@code null} if the constructor being declared is
* unnamed.
*
* @return the name of the constructor
*/
public SimpleIdentifier getName() {
return name;
}
/**
* Return the parameters associated with the constructor.
*
* @return the parameters associated with the constructor
*/
public FormalParameterList getParameters() {
return parameters;
}
/**
* Return the token for the period before the constructor name, or {@code null} if the constructor
* being declared is unnamed.
*
* @return the token for the period before the constructor name
*/
public Token getPeriod() {
return period;
}
/**
* Return the name of the constructor to which this constructor will be redirected, or
* {@code null} if this is not a redirecting factory constructor.
*
* @return the name of the constructor to which this constructor will be redirected
*/
public ConstructorName getRedirectedConstructor() {
return redirectedConstructor;
}
/**
* Return the type of object being created. This can be different than the type in which the
* constructor is being declared if the constructor is the implementation of a factory
* constructor.
*
* @return the type of object being created
*/
public Identifier getReturnType() {
return returnType;
}
/**
* Return the token for the separator (colon or equals) before the initializer list or
* redirection, or {@code null} if there are no initializers.
*
* @return the token for the separator before the initializer list or redirection
*/
public Token getSeparator() {
return separator;
}
/**
* Set the body of the constructor to the given function body.
*
* @param functionBody the body of the constructor
*/
public void setBody(FunctionBody functionBody) {
body = becomeParentOf(functionBody);
}
/**
* Set the token for the 'const' keyword to the given token.
*
* @param constKeyword the token for the 'const' keyword
*/
public void setConstKeyword(Token constKeyword) {
this.constKeyword = constKeyword;
}
/**
* Set the element associated with this constructor to the given element.
*
* @param element the element associated with this constructor
*/
public void setElement(ConstructorElement element) {
this.element = element;
}
/**
* Set the token for the 'external' keyword to the given token.
*
* @param externalKeyword the token for the 'external' keyword
*/
public void setExternalKeyword(Token externalKeyword) {
this.externalKeyword = externalKeyword;
}
/**
* Set the token for the 'factory' keyword to the given token.
*
* @param factoryKeyword the token for the 'factory' keyword
*/
public void setFactoryKeyword(Token factoryKeyword) {
this.factoryKeyword = factoryKeyword;
}
/**
* Set the name of the constructor to the given identifier.
*
* @param identifier the name of the constructor
*/
public void setName(SimpleIdentifier identifier) {
name = becomeParentOf(identifier);
}
/**
* Set the parameters associated with the constructor to the given list of parameters.
*
* @param parameters the parameters associated with the constructor
*/
public void setParameters(FormalParameterList parameters) {
this.parameters = becomeParentOf(parameters);
}
/**
* Set the token for the period before the constructor name to the given token.
*
* @param period the token for the period before the constructor name
*/
public void setPeriod(Token period) {
this.period = period;
}
/**
* Set the name of the constructor to which this constructor will be redirected to the given
* constructor name.
*
* @param redirectedConstructor the name of the constructor to which this constructor will be
* redirected
*/
public void setRedirectedConstructor(ConstructorName redirectedConstructor) {
this.redirectedConstructor = becomeParentOf(redirectedConstructor);
}
/**
* Set the type of object being created to the given type name.
*
* @param typeName the type of object being created
*/
public void setReturnType(Identifier typeName) {
returnType = becomeParentOf(typeName);
}
/**
* Set the token for the separator (colon or equals) before the initializers to the given token.
*
* @param separator the token for the separator (colon or equals) before the initializers
*/
public void setSeparator(Token separator) {
this.separator = separator;
}
@Override
public void visitChildren(AstVisitor<?> visitor) {
super.visitChildren(visitor);
safelyVisitChild(returnType, visitor);
safelyVisitChild(name, visitor);
safelyVisitChild(parameters, visitor);
initializers.accept(visitor);
safelyVisitChild(redirectedConstructor, visitor);
safelyVisitChild(body, visitor);
}
@Override
protected Token getFirstTokenAfterCommentAndMetadata() {
Token leftMost = leftMost(externalKeyword, constKeyword, factoryKeyword);
if (leftMost != null) {
return leftMost;
}
return returnType.getBeginToken();
}
/**
* Return the left-most of the given tokens, or {@code null} if there are no tokens given or if
* all of the given tokens are {@code null}.
*
* @param tokens the tokens being compared to find the left-most token
* @return the left-most of the given tokens
*/
private Token leftMost(Token... tokens) {
Token leftMost = null;
int offset = Integer.MAX_VALUE;
for (Token token : tokens) {
if (token != null && token.getOffset() < offset) {
leftMost = token;
}
}
return leftMost;
}
}