/*
* 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
*
* This file was originally derived from the Polyglot extensible compiler framework.
*
* (C) Copyright 2000-2007 Polyglot project group, Cornell University
* (C) Copyright IBM Corporation 2007-2012.
*/
package polyglot.visit;
import java.util.*;
import polyglot.ast.*;
import polyglot.types.*;
import polyglot.util.CollectionUtil; import x10.util.CollectionFactory;
/**
* The FlattenVisitor flattens the AST,
*/
public class FlattenVisitor extends NodeVisitor
{
protected TypeSystem ts;
protected NodeFactory nf;
protected LinkedList<List<Node>> stack;
public FlattenVisitor(TypeSystem ts, NodeFactory nf) {
this.ts = ts;
this.nf = nf;
stack = new LinkedList<List<Node>>();
}
public Node override(Node parent, Node n) {
// Insert Blocks when needed to allow local decls to be inserted.
if (parent instanceof Stmt && n instanceof Stmt) {
Stmt s1 = (Stmt) n;
if (! (s1 instanceof Block)) {
Stmt s2 = nf.Block(s1.position(), s1);
return visitEdgeNoOverride(parent, s2);
}
}
if (n instanceof FieldDecl || n instanceof ConstructorCall) {
if (! stack.isEmpty()) {
List<Node> l = stack.getFirst();
l.add(n);
}
return n;
}
// punt on switch statement
if (n instanceof Switch) {
return n;
}
if (neverFlatten.contains(n)) {
return n;
}
if (n instanceof ArrayInit) {
return n;
}
return null;
}
protected static int count = 0;
protected static Name newID() {
return Name.makeFresh("tmp");
}
protected Set<Node> noFlatten = CollectionFactory.newHashSet();
protected Set<Node> neverFlatten = CollectionFactory.newHashSet();
/**
* When entering a BlockStatement, place a new StatementList
* onto the stack
*/
public NodeVisitor enter(Node parent, Node n) {
if (n instanceof Block) {
stack.addLast(new LinkedList<Node>());
}
// Don't flatten the expression contained in the statement, but
// flatten its subexpressions.
if (parent instanceof Stmt && n instanceof Expr) {
noFlatten.add(n);
}
if (parent instanceof Assign) {
noFlatten.add(n);
}
return this;
}
/**
* Flatten complex expressions within the AST
*/
public Node leave(Node parent, Node old, Node n, NodeVisitor v) {
if (noFlatten.contains(old)) {
noFlatten.remove(old);
return n;
}
if (n instanceof Block) {
List<Node> l = stack.removeFirst();
Block block = ((Block) n).statements((List<Stmt>)(List) l);
if (parent instanceof Block && !stack.isEmpty()) {
l = stack.getFirst();
l.add(block);
}
return block;
}
else if (n instanceof Stmt) {
List<Node> l = 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;
}
/*
if (e.isTypeChecked() && e.type().isVoid()) {
return n;
}
*/
// create a local temp, initialized to the value of the complex
// expression
Name name = newID();
LocalDecl def = nf.LocalDecl(e.position(), nf.FlagsNode(e.position(), Flags.FINAL),
nf.CanonicalTypeNode(e.position(),
Types.<Type>ref(e.type())),
nf.Id(e.position(), name), e);
LocalDef li = ts.localDef(e.position(), Flags.FINAL,
Types.<Type>ref(e.type()), name);
def = def.localDef(li);
List<Node> l = stack.getFirst();
l.add(def);
// return the local temp instead of the complex expression
Local use = nf.Local(e.position(), nf.Id(e.position(), name));
use = (Local) use.type(e.type());
use = use.localInstance(li.asInstance());
return use;
}
return n;
}
}