/*
* This file is part of the X10 project (http://x10-lang.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* (C) Copyright IBM Corporation 2006-2010.
*/
package x10.util.synthesizer;
import java.util.ArrayList;
import java.util.List;
import polyglot.ast.Block;
import polyglot.ast.Expr;
import polyglot.ast.FlagsNode;
import polyglot.ast.Formal;
import polyglot.ast.NodeFactory;
import polyglot.ast.TypeNode;
import polyglot.types.ClassDef;
import polyglot.types.ClassType;
import polyglot.types.Flags;
import polyglot.types.LocalDef;
import polyglot.types.Name;
import polyglot.types.Ref;
import polyglot.types.SemanticException;
import polyglot.types.Type;
import polyglot.types.Types;
import polyglot.util.Position;
import x10.ast.AnnotationNode;
import x10.ast.TypeParamNode;
import x10.ast.X10ConstructorDecl;
import x10.ast.X10MethodDecl;
import x10.extension.X10Del;
import x10.types.ParameterType;
import x10.types.X10ConstructorDef;
import polyglot.types.Context;
import polyglot.types.TypeSystem;
/**
* Synthesizer to construct a method
*/
public class ConstructorSynth extends AbstractStateSynth implements IClassMemberSynth {
// ClassDef classDef;
// List<Type> throwTypes;
// Flags flag;
List<Formal> formals;
List<AnnotationNode> annotations; // annotations of the new instance
List<ParameterType.Variance> variances; //type parameters' variances
CodeBlockSynth codeBlockSynth;
X10ConstructorDef conDef; // only be created once;
X10ConstructorDecl conDecl; // only be created once;
ClassDef classDef;
public ConstructorSynth(NodeFactory xnf, Context xct, Position pos, ClassDef classDef, Flags flags,
List<Formal> formals, List<Type> throwTypes) {
super(xnf, xct, pos);
this.formals = formals;
this.classDef = classDef;
ClassType classType = classDef.asType();
// reference to formal
annotations = new ArrayList<AnnotationNode>();
variances = new ArrayList<ParameterType.Variance>(); //type parameters' variances
List<Ref<? extends Type>> formalTypeRefs = new ArrayList<Ref<? extends Type>>();
List<Ref<? extends Type>> throwTypeRefs = new ArrayList<Ref<? extends Type>>();
for (Formal f : formals) {
formalTypeRefs.add(f.type().typeRef());
}
for (Type t : throwTypes) {
throwTypeRefs.add(Types.ref(t));
}
conDef = (X10ConstructorDef) xts.constructorDef(pos, pos, Types.ref(classType), flags, formalTypeRefs, throwTypeRefs); // formal
// types
classDef.addConstructor(conDef);
}
public ConstructorSynth(NodeFactory xnf, Context xct, Position pos, ClassDef classDef) {
this(xnf, xct, pos, classDef, Flags.NONE, new ArrayList<Formal>(), new ArrayList<Type>());
}
public ConstructorSynth(NodeFactory xnf, Context xct, ClassDef classDef) {
this(xnf, xct, compilerPos, classDef);
}
public void addAnnotation(AnnotationNode annotation){
annotations.add(annotation);
}
public void setFlags(Flags flags) {
try {
checkClose();
conDef.setFlags(flags);
} catch (StateSynthClosedException e) {
e.printStackTrace();
}
}
/**
* Add a formal to this method, and return a ref to this formal. Flag is
* None
*
* @param pos
* @param type
* @param name
* @return
*/
public Expr addFormal(Position pos, Type type, String name) {
return addFormal(pos, Flags.NONE, type, Name.make(name));
}
/**
* Add a formal to this method, and return a ref to this formal.
*
* @param pos
* @param flags
* @param type
* @param name
* @return
*/
public Expr addFormal(Position pos, Flags flags, Type type, String name) {
return addFormal(pos, flags, type, Name.make(name));
}
/**
* Add a formal to this method, and return a ref to this formal
*
* @param pos
* @param flags
* @param type
* @param name
* @return
*/
public Expr addFormal(Position pos, Flags flags, Type type, Name name) {
TypeSystem xts = (TypeSystem) xct.typeSystem();
LocalDef lDef = xts.localDef(pos, flags, Types.ref(type), name);
Formal f = xnf.Formal(pos, xnf.FlagsNode(pos, flags), xnf.CanonicalTypeNode(pos, type), xnf.Id(pos, name))
.localDef(lDef);
return addFormal(f);
}
public Expr addFormal(Formal formal) {
try {
checkClose();
ArrayList<LocalDef> formalNames = new ArrayList<LocalDef>(conDef.formalNames());
ArrayList<Ref<? extends Type>> formalRefs = new ArrayList<Ref<? extends Type>>(conDef.formalTypes());
formalNames.add(formal.localDef());
formalRefs.add(formal.type().typeRef());
conDef.setFormalNames(formalNames);
conDef.setFormalTypes(formalRefs);
formals.add(formal);
// now prepare the local ref
Name name = formal.name().id();
LocalDef lDef = formal.localDef();
Type type = formal.type().type();
return xnf.Local(pos, xnf.Id(pos, name)).localInstance(lDef.asInstance()).type(type);
} catch (StateSynthClosedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public void setTypeParameters(List<ParameterType> paramTypes, List<ParameterType.Variance> variances){
try {
checkClose();
//conDef.setTypeParameters(paramTypes);
//cannot set it. Please check the X10ConstructorDef_c.java
this.variances = variances;
} catch (StateSynthClosedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public CodeBlockSynth createConstructorBody(Position pos) {
if(codeBlockSynth == null){
codeBlockSynth = new CodeBlockSynth(xnf, xct, this, pos);
}
return codeBlockSynth;
}
public X10ConstructorDef getDef() {
return conDef;
}
public X10ConstructorDecl close() throws SemanticException {
if (conDecl != null) return conDecl;
closed = true;
// Method Decl
FlagsNode flagNode = xnf.FlagsNode(pos, conDef.flags());
Block block;
if (codeBlockSynth == null) {
block = xnf.Block(pos);
} else {
block = codeBlockSynth.close();
}
// constructor
conDecl = (X10ConstructorDecl) xnf.ConstructorDecl(pos, flagNode, xnf.Id(pos, classDef.name()), formals, // formal
// types
block);
//process the type parameters
int typeParamsSize = variances.size();
if(typeParamsSize> 0 ){
//construct type param node
List<ParameterType> params = conDef.typeParameters();
List<TypeParamNode> tpNodes = new ArrayList<TypeParamNode>();
for(int i = 0; i < typeParamsSize; i++){
TypeParamNode tNode = xnf.TypeParamNode(compilerPos, xnf.Id(compilerPos, params.get(i).name()), variances.get(i));
tpNodes.add(tNode.type(params.get(i)));
}
conDecl = conDecl.typeParameters(tpNodes);
}
conDecl = conDecl.returnType(xnf.CanonicalTypeNode(pos, conDef.returnType()));
if(annotations.size() > 0){
conDecl = (X10ConstructorDecl) ((X10Del)conDecl.del()).annotations(annotations);
List<Ref<? extends Type>> ats = new ArrayList<Ref<? extends Type>>(annotations.size());
for (AnnotationNode an : annotations) {
ats.add(an.annotationType().typeRef());
}
conDef.setDefAnnotations(ats);
}
conDecl = (X10ConstructorDecl) conDecl.constructorDef(conDef);
return conDecl;
}
}