Designation.java
package edu.udel.cis.vsl.abc.analysis.entity;
import java.util.ArrayList;
import edu.udel.cis.vsl.abc.ast.type.IF.ArrayType;
import edu.udel.cis.vsl.abc.ast.type.IF.ObjectType;
import edu.udel.cis.vsl.abc.ast.type.IF.StructureOrUnionType;
import edu.udel.cis.vsl.abc.err.IF.ABCRuntimeException;
import edu.udel.cis.vsl.abc.token.IF.Source;
import edu.udel.cis.vsl.abc.token.IF.SyntaxException;
/**
* A designation is specifies (or "designates") a point in a compound literal
* object. It consists of a sequence of Navigators.
*
* The points in a compound literal object form a rooted tree. The root is a
* reference to the whole object. The children of the root are references to the
* immediate sub-objects, and so on. The leaves in this are references to simple
* literals which wrap expressions. The edges in the tree correspond to
* Navigators. A Designation specifies a path in the tree starting from the
* root.
*
* @see {@link Navigator}
*
* @author siegel
*
*/
public class Designation {
private LiteralTypeNode rootType;
private ArrayList<Navigator> navigators;
Designation(LiteralTypeNode rootType, ArrayList<Navigator> navigators) {
this.rootType = rootType;
this.navigators = navigators;
}
public Designation(LiteralTypeNode rootType) {
this(rootType, new ArrayList<Navigator>());
}
/**
* Returns the number of naviagators in the sequence which comprises this
* designation.
*
* @return the number of navigators
*/
public int length() {
return navigators.size();
}
public Navigator get(int index) {
return navigators.get(index);
}
public void add(Navigator navigator) {
navigators.add(navigator);
}
public void removeLast() {
navigators.remove(navigators.size() - 1);
}
public void append(Designation that) {
navigators.addAll(that.navigators);
}
/**
* Modifies this designation so that it refers to the next point in the
* compound literal tree in depth-first-search order.
*
* @throws SyntaxException
*/
public void increment(LiteralTypeNode typeNode) throws SyntaxException {
LiteralTypeNode subType = getDesignatedType().parent();
int length = navigators.size();
while (true) {
Navigator last = navigators.get(length - 1);
int newIndex = last.getIndex() + 1;
if (subType.hasFixedLength() && newIndex >= subType.length()) {
// backtrack
length--;
if (length == 0) {
// no more next, over-write the current:
return;
} else {
removeLast();
subType = subType.parent();
}
} else {
navigators.set(length - 1,
new Navigator(newIndex, last.getSource()));
return;
}
}
}
@Override
public String toString() {
String result = "";
for (Navigator n : navigators)
result += n;
return result;
}
public LiteralTypeNode getRootType() {
return rootType;
}
public LiteralTypeNode getDesignatedType() throws SyntaxException {
LiteralTypeNode result = rootType;
for (Navigator navigator : navigators) {
int index = navigator.getIndex();
if (result instanceof LiteralArrayTypeNode) {
result = ((LiteralArrayTypeNode) result).getElementNode();
} else if (result instanceof LiteralStructOrUnionTypeNode) {
LiteralStructOrUnionTypeNode sunode = (LiteralStructOrUnionTypeNode) result;
int length = sunode.length();
if (index < 0 || index >= length)
throw new SyntaxException(
"Member index out of range for struct or union",
navigator.getSource());
result = sunode.getMemberNode(index);
} else {
throw new SyntaxException(
"Navigator in compound literal/initializer is incompatible with type",
navigator.getSource());
}
}
return result;
}
private int distanceToScalar(ObjectType type) {
int result = 0;
while (true) {
switch (type.kind()) {
case ARRAY :
result++;
type = ((ArrayType) type).getElementType();
break;
case STRUCTURE_OR_UNION :
result++;
type = ((StructureOrUnionType) type).getField(0).getType();
break;
default :
return result;
}
}
}
public void descendToType(ObjectType type, Source source)
throws SyntaxException {
LiteralTypeNode subtype = getDesignatedType();
int upperDistance = distanceToScalar(subtype.getType());
int lowerDistance = distanceToScalar(type);
int difference = upperDistance - lowerDistance;
if (difference < 0)
throw new SyntaxException("Literal member has incompatible type",
source);
for (int i = 0; i < difference; i++) {
if (subtype instanceof LiteralArrayTypeNode) {
subtype = ((LiteralArrayTypeNode) subtype).getElementNode();
navigators.add(new Navigator(0, source));
} else if (subtype instanceof LiteralStructOrUnionTypeNode) {
subtype = ((LiteralStructOrUnionTypeNode) subtype)
.getMemberNode(0);
navigators.add(new Navigator(0, source));
} else
throw new ABCRuntimeException(
"Unreachable: subtype not array or struct/union: "
+ subtype);
}
}
}