/* * 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 x10c.visit; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import polyglot.ast.Block; import polyglot.ast.ClassBody; import polyglot.ast.ClassDecl; import polyglot.ast.ClassMember; import polyglot.ast.Expr; import polyglot.ast.Formal; import polyglot.ast.Local; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.TypeNode; import polyglot.frontend.Job; import polyglot.types.ClassType; import polyglot.types.CodeDef; import polyglot.types.Flags; import polyglot.types.Name; import polyglot.types.Ref; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.TypeSystem; import polyglot.types.Types; import polyglot.util.Position; import polyglot.util.CollectionUtil; import x10.util.CollectionFactory; import polyglot.visit.ContextVisitor; import polyglot.visit.NodeVisitor; import x10.ast.Closure; import x10.ast.ClosureCall; import x10.ast.ParExpr; import x10.ast.TypeParamNode; import x10.ast.X10Call; import x10.ast.X10MethodDecl; import x10.ast.X10Special; import x10.types.ParameterType; import x10.types.X10ClassDef; import x10.types.X10MethodDef; import x10.types.X10ParsedClassType; import polyglot.types.TypeSystem; public class ClosuresToStaticMethods extends ContextVisitor { private static final String STATIC_METHOD_BASE_NAME = "__$closure$apply$__"; private final TypeSystem xts; private final NodeFactory xnf; private final Map<CodeDef,List<ParameterType>> closureDefToTypePrams = CollectionFactory.newHashMap(); public ClosuresToStaticMethods(Job job, TypeSystem ts, NodeFactory nf) { super(job, ts, nf); xts = (TypeSystem) ts; xnf = (NodeFactory) nf; } @Override protected Node leaveCall(Node parent, Node old, Node n, NodeVisitor v) throws SemanticException { if (parent instanceof Closure && ((Closure) parent).body() == old) { class ClosureCapChecker extends ContextVisitor { private ClosureCapChecker(Job job, TypeSystem ts, NodeFactory nf) {super(job, ts, nf);} public boolean isCap = false; @Override public Node leaveCall(Node parent, Node old, Node n, NodeVisitor v) { if (n instanceof Local) { if (!context.isLocal(((Local) n).name().id())) { isCap = true; finish(); } } if (n instanceof X10Special && !((X10Special) n).isSelf()) { isCap = true; finish(); } return n; } } ClosureCapChecker cc = (ClosureCapChecker) new ClosureCapChecker(job, ts, nf).context(context); n.visitChildren(cc); List<ParameterType> mtps = null; CodeDef ci = context.pop().currentCode(); if (ci instanceof X10MethodDef) { mtps = ((X10MethodDef) ci).typeParameters(); } X10ClassDef cd = (X10ClassDef) context.currentClassDef(); if (!cd.typeParameters().isEmpty()) { if (mtps != null) { mtps = new ArrayList<ParameterType>(mtps); } else { mtps = new ArrayList<ParameterType>(); } mtps.addAll(cd.typeParameters()); } if (!cc.isCap && !context.inStaticContext()) { closureDefToTypePrams.put(((Closure) parent).codeDef(), mtps); } } if (n instanceof ClassDecl) { ClassDecl cd = (ClassDecl) n; final ClassType ct = cd.classDef().asType(); final List<ClassMember> nmembers = new ArrayList<ClassMember>(); cd = (ClassDecl) cd.visit( new NodeVisitor() { @Override public Node leave(Node parent, Node old, Node n, NodeVisitor v) { if (n instanceof ClosureCall) { ClosureCall cc = (ClosureCall) n; Expr target = cc.target(); // TODO data flow analysis if (target instanceof ParExpr) { target = ((ParExpr) target).expr(); } if (target instanceof Closure) { Closure closure = (Closure) target; if (!closureDefToTypePrams.containsKey(closure.codeDef())) { return n; } Block body = closure.body(); Position cg = Position.COMPILER_GENERATED; Flags flags = Flags.STATIC.Final().Private(); Name name = Name.makeFresh(STATIC_METHOD_BASE_NAME); X10MethodDecl mdcl = xnf.MethodDecl(cg, xnf.FlagsNode(cg, flags), closure.returnType(), xnf.Id(cg, name), closure.formals(), body); List<Ref<? extends Type>> argTypes = new ArrayList<Ref<? extends Type>>(closure.formals().size()); for (Formal f : closure.formals()) { Type t = f.type().type(); argTypes.add(f.type().typeRef()); } List<ParameterType> rts = new ArrayList<ParameterType>(); List<TypeNode> tns = new ArrayList<TypeNode>(); List<TypeParamNode> tps = new ArrayList<TypeParamNode>(); List<ParameterType> mtps = closureDefToTypePrams.get(closure.codeDef()); if (mtps != null) { for (ParameterType t : mtps) { ParameterType pt = (ParameterType) t; tps.add(xnf.TypeParamNode(cg, xnf.Id(cg, pt.name())).type(pt)); tns.add(xnf.X10CanonicalTypeNode(cg, pt)); rts.add(pt); } } X10MethodDef md = (X10MethodDef) xts.methodDef(cg, cg, Types.ref(ct), flags, closure.returnType().typeRef(), name, argTypes, Collections.<Ref<? extends Type>>emptyList()); mdcl = mdcl.typeParameters(tps); nmembers.add(mdcl.methodDef(md)); md.setTypeParameters(rts); X10Call x10call = (X10Call) xnf.Call(n.position(), xnf.CanonicalTypeNode(n.position(), ct), xnf.Id(n.position(), name), cc.arguments()).methodInstance(md.asInstance()).type(ct); x10call = x10call.typeArguments(tns); return x10call; } } return n; } } ); ClassBody body = cd.body(); nmembers.addAll(0, body.members()); return ((ClassDecl) n).body(body.members(nmembers)); } return n; } }