// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz)
// All rights reserved.
//
// This software may be modified and distributed under the terms
// of the BSD license. See the LICENSE file for details.
package wyil.lang;
import java.util.ArrayList;
import java.util.List;
import wybs.lang.Attribute;
import wybs.lang.SyntacticElement;
/**
* A SyntaxTree representation of the Whiley Intermediate Language (WyIL).
* Specifically, bytecodes in WyIL are "flat" rather than being nested trees,
* etc. This makes them easier to work with for performing optimisation, amongst
* other things. This also means they are close to their byte-level
* representation on disk. However, the tree-like nature of a typically abstract
* syntax tree is convenient in many ways, and this class provides a "wrapper"
* for bytecodes which makes them appear as a tree-like structure.
*
* @author David J. Pearce
*
*/
public class SyntaxTree {
/**
* The enclosing declaration for this tree
*/
private final WyilFile.Declaration parent;
/**
* The set of locations making up this tree. Each location is some kind of
* component of the tree. For example, an expression or statement.
*/
private final List<Location<?>> locations;
public SyntaxTree(WyilFile.Declaration enclosingDeclaration) {
this.parent = enclosingDeclaration;
this.locations = new ArrayList<Location<?>>();
}
/**
* Returns the number of locations in this syntax tree.
*
* @return
*/
public int size() {
return locations.size();
}
/**
* Get the location at a given index in this syntax tree.
*
* @param index
* --- index of location to return
* @return
*/
public Location<?> getLocation(int index) {
return locations.get(index);
}
/**
* Get the location at a given index in this syntax tree.
*
* @param index
* --- index of location to return
* @return
*/
public Location<?>[] getLocations(int... indices) {
Location<?>[] locs = new Location<?>[indices.length];
for(int i=0;i!=indices.length;++i) {
locs[i] = getLocation(indices[i]);
}
return locs;
}
public List<Location<?>> getLocations() {
return locations;
}
/**
* Get the index of a given location in this tree.
*
* @param location
* @return
*/
public int getIndexOf(Location<?> location) {
return locations.indexOf(location);
}
/**
* Get the enclosing declaration of this syntax tree.
*
* @return
*/
public WyilFile.Declaration getEnclosingDeclaration() {
return parent;
}
// ============================================================
// Location
// ============================================================
public static class Location<T extends Bytecode> extends SyntacticElement.Impl {
private final SyntaxTree parent;
private final Type[] types;
private final T bytecode;
public Location(SyntaxTree parent, T bytecode, Attribute...attributes) {
super(attributes);
this.parent = parent;
this.types = new Type[0];
this.bytecode = bytecode;
}
public Location(SyntaxTree parent, T bytecode, List<Attribute> attributes) {
super(attributes);
this.parent = parent;
this.types = new Type[0];
this.bytecode = bytecode;
}
public Location(SyntaxTree parent, Type type, T bytecode, Attribute...attributes) {
super(attributes);
this.parent = parent;
this.types = new Type[] {type};
this.bytecode = bytecode;
}
public Location(SyntaxTree parent, Type type, T bytecode, List<Attribute> attributes) {
super(attributes);
this.parent = parent;
this.types = new Type[] {type};
this.bytecode = bytecode;
}
public Location(SyntaxTree parent, Type[] types, T bytecode, Attribute...attributes) {
super(attributes);
this.parent = parent;
this.types = types;
this.bytecode = bytecode;
}
public Location(SyntaxTree parent, Type[] types, T bytecode, List<Attribute> attributes) {
super(attributes);
this.parent = parent;
this.types = types;
this.bytecode = bytecode;
}
/**
* Get the index of this location in the enclosing syntax tree. Every
* location has a unique index.
*
* @return
*/
public int getIndex() {
return parent.getIndexOf(this);
}
/**
* Get the enclosing syntax tree of this location.
*
* @return
*/
public SyntaxTree getEnclosingTree() {
return parent;
}
/**
* Get the declared type of this location. This is a convenience method
* since, in most cases, we are working on locations that have exactly
* one type.
*
* @return
*/
public Type getType() {
if(types.length > 1) {
throw new IllegalArgumentException("ambiguous request for type");
} else if(types.length == 0) {
throw new IllegalArgumentException("no types available for access");
} else {
return types[0];
}
}
/**
* Get a specific type of this location.
*
* @return
*/
public Type getType(int i) {
return types[i];
}
/**
* Get the types for this location.
*
* @return
*/
public Type[] getTypes() {
return types;
}
/**
* Get the number of types declared by this location.
*
* @return
*/
public int numberOfTypes() {
return types.length;
}
/**
* Get the bytecode associated with this location
*
* @return
*/
public T getBytecode() {
return bytecode;
}
/**
* Get the underlying opcode for this location
*
* @return
*/
public int getOpcode() {
return bytecode.getOpcode();
}
/**
* Get the number of operand groups in this location.
*
* @return
*/
public int numberOfOperands() {
return bytecode.numberOfOperands();
}
/**
* Return the ith operand associated with this location.
*
* @param i
* @return
*/
public Location<?> getOperand(int i) {
return parent.getLocation(bytecode.getOperand(i));
}
/**
* Return the ith operand associated with this location.
*
* @param i
* @return
*/
public Location<?>[] getOperands() {
return parent.getLocations(bytecode.getOperands());
}
/**
* Get the number of operand groups in this location.
*
* @return
*/
public int numberOfOperandGroups() {
return bytecode.numberOfOperandGroups();
}
/**
* Get the ith operand group in this location.
*
* @param i
* @return
*/
public Location<?>[] getOperandGroup(int i) {
int[] group = bytecode.getOperandGroup(i);
return parent.getLocations(group);
}
/**
* Get the number of blocks contained in this statement. This includes
* only those which are immediate children of this statement, but not
* those which are transitively contained.
*
* @return
*/
public int numberOfBlocks() {
if(bytecode instanceof Bytecode.Stmt) {
Bytecode.Stmt stmt = (Bytecode.Stmt) bytecode;
return stmt.numberOfBlocks();
} else {
return 0;
}
}
/**
* Get the ith block contained in this statement.
*
* @param i
* @return
*/
public Location<Bytecode.Block> getBlock(int i) {
Bytecode.Stmt stmt = (Bytecode.Stmt) bytecode;
return (Location<Bytecode.Block>) parent.getLocation(stmt.getBlock(i));
}
@Override
public String toString() {
int index = getIndex();
String ts = "";
for(int i=0;i!=types.length;++i) {
if(i!=0) {
ts += ",";
}
ts += types[i];
}
return index + ":" + ts + ":" + bytecode;
}
}
/**
* Some helpful context to make reading the code using syntax trees simpler.
*/
public static final int CONDITION = 0;
public static final int BODY = 0;
public static final int VARIABLE = 0;
public static final int TRUEBRANCH = 0;
public static final int PARAMETERS = 0;
public static final int ARGUMENTS = 0;
public static final int LEFTHANDSIDE = 0;
//
public static final int START = 1;
public static final int FALSEBRANCH = 1;
public static final int RIGHTHANDSIDE = 1;
public static final int ENVIRONMENT = 0;
//
public static final int END = 2;
}