package polyglot.visit;
import polyglot.ast.*;
import polyglot.types.*;
import java.util.*;
/**
* The FlattenVisitor flattens the AST,
*/
public class FlattenVisitor extends NodeVisitor
{
protected TypeSystem ts;
protected NodeFactory nf;
protected LinkedList stack;
public FlattenVisitor(TypeSystem ts, NodeFactory nf) {
this.ts = ts;
this.nf = nf;
stack = new LinkedList();
}
public Node override(Node n) {
if (n instanceof FieldDecl || n instanceof ConstructorCall) {
return n;
}
return null;
}
static int count = 0;
protected static String newID() {
return "flat$$$" + count++;
}
protected Node noFlatten = null;
/**
* When entering a BlockStatement, place a new StatementList
* onto the stack
*/
public NodeVisitor enter(Node n) {
if (n instanceof Block) {
stack.addFirst(new LinkedList());
}
if (n instanceof Eval) {
// Don't flatten the expression contained in the statement, but
// flatten its subexpressions.
Eval s = (Eval) n;
noFlatten = s.expr();
}
return this;
}
/**
* Flatten complex expressions within the AST
*/
public Node leave(Node old, Node n, NodeVisitor v) {
if (n == noFlatten) {
noFlatten = null;
return n;
}
if (n instanceof Block) {
List l = (List) stack.removeFirst();
return ((Block) n).statements(l);
}
else if (n instanceof Stmt && ! (n instanceof LocalDecl)) {
List l = (List) stack.getFirst();
l.add(n);
return n;
}
else if (n instanceof Expr && ! (n instanceof Lit) &&
! (n instanceof Special) && ! (n instanceof Local)) {
Expr e = (Expr) n;
if (e instanceof Assign) {
return n;
}
// create a local temp, initialized to the value of the complex
// expression
String name = newID();
LocalDecl def = nf.LocalDecl(e.position(), Flags.FINAL,
nf.CanonicalTypeNode(e.position(),
e.type()),
name, e);
def = def.localInstance(ts.localInstance(e.position(), Flags.FINAL,
e.type(), name));
List l = (List) stack.getFirst();
l.add(def);
// return the local temp instead of the complex expression
Local use = nf.Local(e.position(), name);
use = (Local) use.type(e.type());
use = use.localInstance(ts.localInstance(e.position(), Flags.FINAL,
e.type(), name));
return use;
}
return n;
}
}