package com.redhat.ceylon.compiler.java.codegen;
import static com.sun.tools.javac.code.Flags.PRIVATE;
import static com.sun.tools.javac.code.Flags.PROTECTED;
import static com.sun.tools.javac.code.Flags.PUBLIC;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.MemberOrTypeExpression;
import com.redhat.ceylon.model.typechecker.model.Constructor;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCThrow;
import com.sun.tools.javac.tree.TreeCopier;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
public class InitializerBuilder implements ParameterizedBuilder<InitializerBuilder> {
private final AbstractTransformer gen;
private long modifiers = 0;
// TODO remove this field
private JCStatement delegateCall;
private final ListBuffer<ParameterDefinitionBuilder> params = ListBuffer.lb();
/**
* For classes with parameter lists this is a {@code List<JCStatement>}.
* For classes with constructors it's a
* {@code List<JCStatement|Tree.Constructor>} and this we know which
* statements need to be prepended to each transformed constructor body
* and which need to be appended.
*/
private final java.util.List<Object/* JCStatement|Constructor*/> init = new java.util.ArrayList<Object>();
private final ListBuffer<JCAnnotation> userAnnos = ListBuffer.lb();
public InitializerBuilder(AbstractTransformer gen) {
this.gen = gen;
}
/** Only called for classes with parameter lists */
JCMethodDecl build() {
if (delegateCall != null/* && !isAlias*/) {
init.add(0, delegateCall);
}
List<JCStatement> body = statementsBetween(null, null);
int index = 0;
for (JCStatement stmt : body) {
if (stmt instanceof JCThrow) {
ListBuffer<JCStatement> filtered = ListBuffer.<JCStatement>lb();
filtered.addAll(body.subList(0, index+1));
body = filtered.toList();
break;
}
index++;
}
MethodDefinitionBuilder constructor = MethodDefinitionBuilder.constructor(gen);
constructor.modifiers(modifiers)
.userAnnotations(userAnnos.toList())
.parameters(params.toList())
.body(body);
return constructor.build();
}
public InitializerBuilder modifiers(long mods) {
if ((mods & ~(PUBLIC|PRIVATE|PROTECTED)) != 0) {
throw new BugException("illegal modifier for constructor " + Flags.toString(mods));
}
this.modifiers = mods;
return this;
}
public InitializerBuilder userAnnotations(List<JCAnnotation> annos) {
this.userAnnos.addAll(annos);
return this;
}
// Create a parameter for the constructor
public InitializerBuilder parameter(ParameterDefinitionBuilder pdb) {
params.append(pdb);
return this;
}
public InitializerBuilder init(JCStatement statement) {
if (statement != null) {
this.init.add(statement);
}
return this;
}
public InitializerBuilder init(List<JCStatement> init) {
if (init != null) {
this.init.addAll(init);
}
return this;
}
public InitializerBuilder constructor(
com.redhat.ceylon.compiler.typechecker.tree.Tree.Constructor ctor) {
if (ctor != null) {
this.init.add(ctor.getConstructor());
}
return this;
}
public InitializerBuilder singleton(
com.redhat.ceylon.compiler.typechecker.tree.Tree.Enumerated ctor) {
if (ctor != null) {
this.init.add(ctor.getEnumerated());
}
return this;
}
/**
* Set the expression used to invoke {@code super()} or {@code this()}.
* (i.e. delegate to another constructor).
*/
public InitializerBuilder delegateCall(JCStatement delegateCall) {
// TODO remove this method
this.delegateCall = delegateCall;
return this;
}
public boolean isEmptyInit() {
return init.isEmpty();
}
private List<JCStatement> statementsBetween(Constructor first, Constructor second) {
ListBuffer<JCStatement> buffer = ListBuffer.lb();
boolean found = first == null;
for (Object o : this.init) {
if (found && o instanceof JCStatement) {
buffer.add((JCStatement)o);
} else if (first != null && first.equals(o)){
found = true;
} else if (second != null && second.equals(o)){
break;
}
}
return buffer.toList();
}
private <T extends JCTree> List<T> copyOf(List<T> list) {
TreeCopier<?> copier = new TreeCopier(gen.make());
return copier.copy(list);
}
List<JCStatement> copyStatementsBetween(Constructor first, Constructor second) {
return copyOf(statementsBetween(first, second));
}
public List<ParameterDefinitionBuilder> getParameterList() {
return params.toList();
}
}