/*
* 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.ClassBody;
import polyglot.ast.ClassMember;
import polyglot.ast.Expr;
import polyglot.ast.FlagsNode;
import polyglot.ast.Formal;
import polyglot.ast.Local;
import polyglot.ast.NodeFactory;
import polyglot.ast.TypeNode;
import polyglot.types.ClassDef;
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.X10ClassDecl;
import x10.ast.X10MethodDecl;
import x10.ast.X10MethodDecl_c;
import x10.constraint.XTerm;
import x10.extension.X10Del;
import x10.types.X10ClassDef;
import polyglot.types.Context;
import x10.types.ParameterType;
import x10.types.X10MethodDef;
import polyglot.types.TypeSystem;
import x10.types.checker.PlaceChecker;
/**
* Method synthesizer to construct a method
*
*/
public class MethodSynth extends AbstractStateSynth implements IClassMemberSynth{
List<AnnotationNode> annotations; // annotations of the new method
List<ParameterType.Variance> variances; //type parameters' variances
CodeBlockSynth codeBlockSynth;
List<Formal> formals;
X10MethodDef methodDef; //only be created once;
X10MethodDecl methodDecl; //only be created once;
public MethodSynth(NodeFactory xnf, Context xct, Position pos, ClassDef classDef, Name methodName,
Flags flags, List<Formal> formals, List<Type> throwTypes, Type returnType){
super(xnf, xct, pos);
this.formals = formals;
annotations = new ArrayList<AnnotationNode>();
variances = new ArrayList<ParameterType.Variance>(); //type parameters' variances
List<Ref<? extends Type>> formalTypeRefs = new ArrayList<Ref<? extends Type>>();
List<LocalDef> formalNames = new ArrayList<LocalDef>();
List<Ref<? extends Type>> throwTypeRefs = new ArrayList<Ref<? extends Type>>();
for (Formal f : formals) {
formalTypeRefs.add(f.type().typeRef());
formalNames.add(f.localDef());
}
for (Type t : throwTypes) {
throwTypeRefs.add(Types.ref(t));
}
methodDef = (X10MethodDef) xts.methodDef(pos, pos,
Types.ref(classDef.asType()),
flags,
Types.ref(returnType),
methodName,
formalTypeRefs,
throwTypeRefs
);//this constructor will not set formal names
methodDef.setThisDef(((X10ClassDef) classDef).thisDef());
methodDef.setFormalNames(formalNames);
classDef.addMethod(methodDef);
codeBlockSynth = new CodeBlockSynth(xnf, xct, this, pos);
}
public MethodSynth(NodeFactory xnf, Context xct, Position pos, ClassDef classDef, String methodName){
this(xnf, xct, pos, classDef, Name.make(methodName),
Flags.NONE, new ArrayList<Formal>(), new ArrayList<Type>(), xct.typeSystem().Void());
}
public void setFlag(Flags flags) {
try {
checkClose();
methodDef.setFlags(flags);
} catch (StateSynthClosedException e) {
e.printStackTrace();
}
}
public void setReturnType(Type returnType){
try {
checkClose();
methodDef.setReturnType(Types.ref(returnType));
} catch (StateSynthClosedException e) {
e.printStackTrace();
}
}
public void addAnnotation(AnnotationNode annotation){
annotations.add(annotation);
}
public void addTypeParameter(ParameterType p, ParameterType.Variance v){
try {
checkClose();
List<ParameterType> params = new ArrayList<ParameterType>(methodDef.typeParameters());
params.add(p);
methodDef.setTypeParameters(params);
variances.add(v);
} 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 Local 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 Local addFormal(Formal formal) {
try {
checkClose();
ArrayList<LocalDef> formalNames = new ArrayList<LocalDef>(methodDef.formalNames());
ArrayList<Ref<? extends Type>> formalRefs =
new ArrayList<Ref<? extends Type>>(methodDef.formalTypes());
formalNames.add(formal.localDef());
formalRefs.add(formal.type().typeRef());
methodDef.setFormalNames(formalNames);
methodDef.setFormalTypes(formalRefs);
formals.add(formal);
//now prepare the local ref
Name name = formal.name().id();
LocalDef lDef = formal.localDef();
Type type = formal.type().type();
Local formalRef = (Local) xnf.Local(pos, xnf.Id(pos, name)).localInstance(lDef.asInstance()).type(type);
codeBlockSynth.addLocal(formalRef);
return formalRef;
} catch (StateSynthClosedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public void setMethodBodySynth(CodeBlockSynth codeBlockSynth) {
try {
checkClose();
codeBlockSynth.setContainerSynth(this);
this.codeBlockSynth = codeBlockSynth;
} catch (StateSynthClosedException e) {
e.printStackTrace();
}
}
public CodeBlockSynth getMethodBodySynth(Position pos) {
return codeBlockSynth;
}
public X10MethodDef getDef(){
return methodDef;
}
public X10MethodDecl close() throws SemanticException{
if (closed) {
return methodDecl; // just return the field
}
closed = true;
//processing
// Method Decl
FlagsNode flagNode = xnf.FlagsNode(pos, methodDef.flags());
TypeNode returnTypeNode = xnf.CanonicalTypeNode(pos, methodDef.returnType());
Block block;
if (methodDef.flags().isAbstract()) {
block = null;
} else {
block = codeBlockSynth.close();
}
methodDecl = (X10MethodDecl) xnf.MethodDecl(pos, flagNode, returnTypeNode, xnf.Id(pos, methodDef.name()),
formals, block);
if(annotations.size() > 0){
methodDecl = (X10MethodDecl) ((X10Del)methodDecl.del()).annotations(annotations);
List<Ref<? extends Type>> ats = new ArrayList<Ref<? extends Type>>(annotations.size());
for (AnnotationNode an : annotations) {
ats.add(an.annotationType().typeRef());
}
methodDef.setDefAnnotations(ats);
}
int typeParamsSize = variances.size();
if(typeParamsSize> 0 ){
//construct type param node
List<ParameterType> params = methodDef.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)));
}
methodDecl = methodDecl.typeParameters(tpNodes);
}
methodDecl = (X10MethodDecl) methodDecl.methodDef(methodDef); //Need set the method def to the method instance
return methodDecl;
}
@Deprecated
public X10ClassDecl insertMethodIntoClass(X10ClassDecl classDecl) throws SemanticException{
List<ClassMember> cm = new ArrayList<ClassMember>();
cm.addAll(classDecl.body().members());
cm.add(close());
ClassBody cb = classDecl.body();
return (X10ClassDecl) classDecl.body(cb.members(cm));
}
}