/*
* 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.HashSet;
import java.util.Set;
import polyglot.ast.Expr;
import polyglot.ast.FieldAssign;
import polyglot.ast.Formal;
import polyglot.ast.Local;
import polyglot.ast.LocalAssign;
import polyglot.ast.LocalDecl;
import polyglot.ast.Node;
import polyglot.types.Name;
import polyglot.types.SemanticException;
import polyglot.visit.NodeVisitor;
import polyglot.types.Context;
import polyglot.util.CollectionUtil; import x10.util.CollectionFactory;
import x10.util.Synthesizer;
/**
* @author Haichuan
*
* This class is used to replace local var access by field access.
* In WS code gen, the original code may contain local access.
* e.g.
* static def fib(n:Int):Int {
* var t1:Int;
* t1 = async fib(n-1);
* }
* After transformation, n/t1 are added as fields in a inner class.
* Suppose tmp points to one instance, then we need change the last statement to
* tmp.t1 = async fib(t1.n - 1);
* This work is done by the LocalAccessToFieldAccessReplacer
*
*
*/
public class AdvLocalAccessToFieldAccessReplacer extends NodeVisitor {
protected ILocalToFieldContainerMap refMap;
protected Synthesizer synth;
protected Context context;
private boolean replaceError; //record weather there are some replacing errors;
protected Set<Name> localDeclaredVar; //all locals with these names will not be replaced
public AdvLocalAccessToFieldAccessReplacer(ILocalToFieldContainerMap refMap, Synthesizer synth, Context context,
Set<Name> declaredNames){
this.refMap = refMap;
this.synth = synth;
this.context = context;
localDeclaredVar = CollectionFactory.newHashSet(declaredNames);
}
public Node leave(Node parent, Node old, Node n, NodeVisitor v) {
Node ret = n;
if(n instanceof LocalDecl){
LocalDecl ld = (LocalDecl)n;
localDeclaredVar.add(ld.name().id());
//System.out.println("local added:" + ld.name().id());
}
if(n instanceof Formal){
Formal f = (Formal)n;
localDeclaredVar.add(f.name().id());
//System.out.println("formal local added:" + f.name().id());
}
if(n instanceof Local && !localDeclaredVar.contains(((Local)n).name().id())
&& /*two conditions below, be very careful */
(!(parent instanceof LocalAssign) || (((LocalAssign)parent).local() != n))
){
Local l = (Local)n;
Name name = l.name().id();
try {
Expr instanceRef = refMap.getFieldContainerRef(name, l.type());
if(instanceRef != null){
ret = synth.makeFieldAccess(n.position(), instanceRef, name, context);
}
else{
replaceError = true;
System.err.println("[WSCodeGen_Info] Ingore replacing local variable with field access:" + name );
}
} catch (SemanticException e) {
replaceError = true;
System.err.println("[WSCodeGen_ERR]:cannot replace local access with field access");
e.printStackTrace();
}
}
if(n instanceof LocalAssign && !localDeclaredVar.contains(((LocalAssign)n).local().name().id())){
LocalAssign ls = ((LocalAssign)n);
Local l = ls.local();
Name name = l.name().id();
try {
Expr instanceRef = refMap.getFieldContainerRef(name, l.type());
if(instanceRef != null){
FieldAssign fa = (FieldAssign) synth.makeFieldAssign(n.position(), instanceRef, name, ls.right(), context);
ret = fa.operator(ls.operator());
}
else{
replaceError = true;
System.err.println("[WSCodeGen_Info] Ingore replacing local variable with field access:" + name);
}
}
catch (SemanticException e) {
replaceError = true;
System.err.println("[WSCodeGen_ERR]:cannot replace local access with field access");
e.printStackTrace();
}
}
return ret;
}
public boolean isReplaceError() {
return replaceError;
}
}