/*
* 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.compiler.ws.util;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import polyglot.ast.Block;
import polyglot.ast.Expr;
import polyglot.ast.Local;
import polyglot.ast.Node;
import polyglot.ast.NodeFactory;
import polyglot.ast.Stmt;
import polyglot.frontend.Job;
import polyglot.visit.ContextVisitor;
import polyglot.visit.NodeVisitor;
import polyglot.util.CollectionUtil;
import x10.types.TypeParamSubst;
import x10.util.CollectionFactory;
import x10.visit.NodeTransformingVisitor;
import x10.visit.Reinstantiator;
/**
* For inner class frames, each frame should have indirect references
* to access upper frames' fields(transformed from locals).
*
* And these indirect references should be added as local declarations in front of
* each fast/slow/back method, which is the goal of this visitor.
*
* It process the code block, and add the local declares
*
* @author Haichuan
*/
public class AddIndirectLocalDeclareVisitor extends ContextVisitor {
Block targetBlock;
Map<Expr, Stmt> refToDeclMap;
public AddIndirectLocalDeclareVisitor(Job job, Map<Expr, Stmt> refToDeclMap) {
super(job, job.extensionInfo().typeSystem(), job.extensionInfo().nodeFactory());
this.refToDeclMap = refToDeclMap;
}
public Node override(Node parent, Node child) {
//in the first step, we need decide the target block
if (child instanceof Block && targetBlock == null) {
targetBlock = (Block) child; //the outer block
}
return null;
}
public Node leaveCall(Node parent, Node old, Node n, NodeVisitor v) {
if (old == targetBlock && refToDeclMap != null) { //only process the target block
Block block = (Block)n;
Reinstantiator reinstantiator = new Reinstantiator(TypeParamSubst.IDENTITY);
ContextVisitor visitor = new NodeTransformingVisitor(job, ts, nf, reinstantiator).context(context());
block = (Block) block.visit(visitor); // reinstantiate locals in the body
//first detect all locals;
LocalExprFinder lef = new LocalExprFinder();
block.visit(lef);//no replacement, just detect
Set<Stmt> localDecls = CollectionFactory.newHashSet(); //we need use set to only add one time
for(Local local : lef.getLocalList()){
Stmt s = refToDeclMap.get(local);
if(s != null){
localDecls.add(s);
}
}
//finally, add all these into the block
if (localDecls.size() > 0) {
ArrayList<Stmt> nStmts = new ArrayList<Stmt>();
nStmts.addAll(localDecls);
nStmts.addAll(block.statements());
block = block.statements(nStmts);
}
return block;
}
return n;
}
/**
* @author Haichuan
* Find out all local var usages, and stored them into localList;
*/
static class LocalExprFinder extends NodeVisitor {
private ArrayList<Local> localList;
public LocalExprFinder(){
localList = new ArrayList<Local>();
}
protected List<Local> getLocalList() {
return localList;
}
public Node leave(Node parent, Node old, Node n, NodeVisitor v) {
if (n instanceof Local) {
localList.add((Local) n);
}
return n;
}
}
}