package com.oracle.js.parser.ir;
import java.util.Collections;
import java.util.List;
import com.oracle.js.parser.ir.visitor.NodeVisitor;
import com.oracle.js.parser.ir.visitor.TranslatorNodeVisitor;
public class ClassNode extends LexicalContextExpression implements LexicalContextScope {
private final IdentNode ident;
private final Expression classHeritage;
private final PropertyNode constructor;
private final List<PropertyNode> classElements;
private final Scope scope;
private final int instanceFieldCount;
private final int staticFieldCount;
private final boolean hasPrivateMethods;
private final boolean hasPrivateInstanceMethods;
public static final String PRIVATE_CONSTRUCTOR_BINDING_NAME = "#constructor";
public ClassNode(final long token, final int finish, final IdentNode ident, final Expression classHeritage, final PropertyNode constructor, final List<PropertyNode> classElements,
final Scope scope, final int instanceFieldCount, final int staticFieldCount, final boolean hasPrivateMethods, final boolean hasPrivateInstanceMethods) {
super(token, finish);
this.ident = ident;
this.classHeritage = classHeritage;
this.constructor = constructor;
this.classElements = classElements;
this.scope = scope;
this.instanceFieldCount = instanceFieldCount;
this.staticFieldCount = staticFieldCount;
this.hasPrivateMethods = hasPrivateMethods;
this.hasPrivateInstanceMethods = hasPrivateInstanceMethods;
assert instanceFieldCount == fieldCount(classElements, false);
assert staticFieldCount == fieldCount(classElements, true);
}
private ClassNode(final ClassNode classNode, final IdentNode ident, final Expression classHeritage, final PropertyNode constructor, final List<PropertyNode> classElements) {
super(classNode);
this.ident = ident;
this.classHeritage = classHeritage;
this.constructor = constructor;
this.classElements = classElements;
this.scope = classNode.scope;
this.instanceFieldCount = fieldCount(classElements, false);
this.staticFieldCount = fieldCount(classElements, true);
this.hasPrivateMethods = classNode.hasPrivateMethods;
this.hasPrivateInstanceMethods = classNode.hasPrivateInstanceMethods;
}
private static int fieldCount(List<PropertyNode> classElements, boolean isStatic) {
int count = 0;
for (PropertyNode classElement : classElements) {
if (classElement.isClassField() && classElement.isStatic() == isStatic) {
count++;
}
}
return count;
}
public IdentNode getIdent() {
return ident;
}
private ClassNode setIdent(final IdentNode ident) {
if (this.ident == ident) {
return this;
}
return new ClassNode(this, ident, classHeritage, constructor, classElements);
}
public Expression getClassHeritage() {
return classHeritage;
}
private ClassNode setClassHeritage(final Expression classHeritage) {
if (this.classHeritage == classHeritage) {
return this;
}
return new ClassNode(this, ident, classHeritage, constructor, classElements);
}
public PropertyNode getConstructor() {
return constructor;
}
public ClassNode setConstructor(final PropertyNode constructor) {
if (this.constructor == constructor) {
return this;
}
return new ClassNode(this, ident, classHeritage, constructor, classElements);
}
public List<PropertyNode> getClassElements() {
return Collections.unmodifiableList(classElements);
}
public ClassNode setClassElements(final List<PropertyNode> classElements) {
if (this.classElements == classElements) {
return this;
}
return new ClassNode(this, ident, classHeritage, constructor, classElements);
}
@Override
public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterClassNode(this)) {
IdentNode newIdent = ident == null ? null : (IdentNode) ident.accept(visitor);
Expression newClassHeritage = classHeritage == null ? null : (Expression) classHeritage.accept(visitor);
PropertyNode newConstructor = constructor == null ? null : (PropertyNode) constructor.accept(visitor);
List<PropertyNode> newClassElements = Node.accept(visitor, classElements);
return visitor.leaveClassNode(setIdent(newIdent).setClassHeritage(newClassHeritage).setConstructor(newConstructor).setClassElements(newClassElements));
}
return this;
}
@Override
public <R> R accept(final LexicalContext lc, TranslatorNodeVisitor<? extends LexicalContext, R> visitor) {
return visitor.enterClassNode(this);
}
@Override
public Scope getScope() {
return scope;
}
public boolean hasInstanceFields() {
return instanceFieldCount != 0;
}
public int getInstanceFieldCount() {
return instanceFieldCount;
}
public boolean hasStaticFields() {
return staticFieldCount != 0;
}
public int getStaticFieldCount() {
return staticFieldCount;
}
public boolean hasPrivateMethods() {
return hasPrivateMethods;
}
public boolean hasPrivateInstanceMethods() {
return hasPrivateInstanceMethods;
}
public boolean isAnonymous() {
return getIdent() == null;
}
@Override
public void toString(StringBuilder sb, boolean printType) {
sb.append("class");
if (ident != null) {
sb.append(' ');
ident.toString(sb, printType);
}
if (classHeritage != null) {
sb.append(" extends");
classHeritage.toString(sb, printType);
}
sb.append(" {");
if (constructor != null) {
constructor.toString(sb, printType);
}
for (PropertyNode classElement : getClassElements()) {
sb.append(", ");
classElement.toString(sb, printType);
}
sb.append("}");
}
}