/**
* 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.ast;
import java.util.List;
import com.github.anba.es6draft.ast.scope.FunctionScope;
/**
* <h1>14 ECMAScript Language: Functions and Classes</h1>
* <ul>
* <li>14.3 Method Definitions
* </ul>
*/
public final class MethodDefinition extends PropertyDefinition implements FunctionNode {
private final FunctionScope scope;
private final MethodType type;
private final MethodAllocation allocation;
private final List<Expression> decorators;
private final PropertyName propertyName;
private final FormalParameterList parameters;
private List<StatementListItem> statements;
private final String headerSource, bodySource;
private String className;
private StrictMode strictMode;
public enum MethodType {
AsyncFunction, AsyncGenerator, BaseConstructor, DerivedConstructor, CallConstructor, Function, Generator,
ConstructorGenerator, Getter, Setter
}
public enum MethodAllocation {
Object, Prototype, Class
}
public MethodDefinition(long beginPosition, long endPosition, FunctionScope scope, MethodType type,
MethodAllocation allocation, List<Expression> decorators, PropertyName propertyName,
FormalParameterList parameters, List<StatementListItem> statements, String headerSource,
String bodySource) {
super(beginPosition, endPosition);
this.scope = scope;
this.type = type;
this.allocation = allocation;
this.decorators = decorators;
this.propertyName = propertyName;
this.parameters = parameters;
this.statements = statements;
this.headerSource = headerSource;
this.bodySource = bodySource;
}
@Override
public FunctionScope getScope() {
return scope;
}
@Override
public BindingIdentifier getIdentifier() {
return null;
}
/**
* Returns the method's type.
*
* @return the method's type
*/
public MethodType getType() {
return type;
}
/**
* Returns the method's allocation kind.
*
* @return the method's allocation kind
*/
public MethodAllocation getAllocation() {
return allocation;
}
/**
* Returns {@code true} if this method is a <code>static</code> class method definition.
*
* @return {@code true} if this method is a <code>static</code> method definition
*/
public boolean isStatic() {
return allocation == MethodAllocation.Class;
}
/**
* Returns {@code true} if this method is a <code>class constructor</code> method definition.
*
* @return {@code true} if this method is a <code>class constructor</code> method definition
*/
public boolean isClassConstructor() {
switch (type) {
case BaseConstructor:
case DerivedConstructor:
return true;
default:
return false;
}
}
/**
* Returns {@code true} if this method is a <code>call constructor</code> method definition.
*
* @return {@code true} if this method is a <code>call constructor</code> method definition
*/
public boolean isCallConstructor() {
return type == MethodType.CallConstructor;
}
/**
* Returns the list of method decorators.
*
* @return the list of decorators
*/
public List<Expression> getDecorators() {
return decorators;
}
@Override
public PropertyName getPropertyName() {
return propertyName;
}
/**
* Returns the optional class name.
*
* @return the class name or {@code null} if not available
*/
public String getClassName() {
return className;
}
/**
* Set the class name property.
*
* @param className
* the class name
*/
public void setClassName(String className) {
assert allocation != MethodAllocation.Object;
this.className = className;
}
@Override
public String getMethodName() {
// Give methods a better name for stacktraces
final String fname;
String pname = propertyName.getName();
if (pname != null) {
if (allocation == MethodAllocation.Prototype && className != null) {
if (isClassConstructor()) {
fname = className;
} else if (isCallConstructor()) {
assert "constructor".equals(pname);
fname = className + '.' + "call constructor";
} else {
fname = className + '.' + pname;
}
} else if (isCallConstructor()) {
assert "constructor".equals(pname);
fname = "call constructor";
} else {
fname = pname;
}
} else {
assert propertyName instanceof ComputedPropertyName;
String cname = ((ComputedPropertyName) propertyName).toString();
if (allocation == MethodAllocation.Prototype && className != null) {
fname = className + cname;
} else {
fname = cname;
}
}
switch (type) {
case Getter:
return "get " + fname;
case Setter:
return "set " + fname;
default:
return fname;
}
}
@Override
public void setMethodName(String methodName) {
throw new AssertionError();
}
@Override
public String getFunctionName() {
final String fname;
String pname = propertyName.getName();
if (pname != null) {
fname = pname;
} else {
assert propertyName instanceof ComputedPropertyName;
fname = ((ComputedPropertyName) propertyName).toString();
}
switch (type) {
case Getter:
return "get " + fname;
case Setter:
return "set " + fname;
default:
return fname;
}
}
@Override
public void setFunctionName(String functionName) {
throw new AssertionError();
}
@Override
public FormalParameterList getParameters() {
return parameters;
}
@Override
public List<StatementListItem> getStatements() {
return statements;
}
@Override
public void setStatements(List<StatementListItem> statements) {
this.statements = statements;
}
@Override
public StrictMode getStrictMode() {
return strictMode;
}
@Override
public void setStrictMode(StrictMode strictMode) {
this.strictMode = strictMode;
}
@Override
public String getHeaderSource() {
return headerSource;
}
@Override
public String getBodySource() {
return bodySource;
}
@Override
public ThisMode getThisMode() {
return strictMode == StrictMode.NonStrict ? ThisMode.Global : ThisMode.Strict;
}
@Override
public boolean isGenerator() {
switch (type) {
case AsyncGenerator:
case Generator:
case ConstructorGenerator:
return true;
default:
return false;
}
}
@Override
public boolean isAsync() {
switch (type) {
case AsyncFunction:
case AsyncGenerator:
return true;
default:
return false;
}
}
@Override
public boolean isConstructor() {
switch (type) {
case BaseConstructor:
case DerivedConstructor:
case ConstructorGenerator:
return true;
default:
return false;
}
}
@Override
public <R, V> R accept(NodeVisitor<R, V> visitor, V value) {
return visitor.visit(this, value);
}
@Override
public <V> int accept(IntNodeVisitor<V> visitor, V value) {
return visitor.visit(this, value);
}
@Override
public <V> void accept(VoidNodeVisitor<V> visitor, V value) {
visitor.visit(this, value);
}
}