CommonCompoundLiteralObject.java
package edu.udel.cis.vsl.abc.analysis.entity;
import java.util.ArrayList;
import java.util.NoSuchElementException;
import edu.udel.cis.vsl.abc.ast.node.IF.ASTNode;
import edu.udel.cis.vsl.abc.ast.node.IF.compound.CompoundLiteralObject;
import edu.udel.cis.vsl.abc.ast.node.IF.compound.LiteralObject;
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;
/**
* Implementation of CompoundLiteral that provides additional functionality for
* modifications.
*
* While reads that go beyond the bounds of the inferred type will throw an
* exception (as specified in CompoundLiteral), write that go beyond the bounds
* of the inferred type will either throw an exception (if the write violates a
* bound in the declared type) or succeed and extend the bounds of the inffered
* type (otherwise).
*
* In any case, the inferred type will be kept in sync with the writes.
*
* This class maintains the following invariant: the inferred type will be
* consistent with the inferred types of the members. I.e., if the inferred type
* is an array type with element type T, all of the (non-null) members will have
* inferred type T. If the inferred type is a struct or union type with member
* types (T_i), the i-th member (if not null) will have inferred type T_i.
* Similar remarks hold for the declared type.
*
* @author siegel
*
*/
public class CommonCompoundLiteralObject extends CommonLiteralObject implements
CompoundLiteralObject {
/**
* The members of this compound object. Entires may be null.
*/
private ArrayList<LiteralObject> elements = new ArrayList<>();
public CommonCompoundLiteralObject(LiteralTypeNode ltNode,
ASTNode sourceNode) {
super(ltNode, sourceNode);
}
@Override
public int size() {
return elements.size();
}
@Override
public LiteralObject get(int index) {
return index >= elements.size() ? null : elements.get(index);
}
@Override
public String toString() {
return elements.toString();
}
/**
* Assumes navigator respects all bounds.
*
* @param navigator
* @return
*/
public LiteralObject get(Designation designation) {
int length = designation.length();
LiteralObject result = this;
for (int i = 0; i < length; i++) {
Navigator navigator = designation.get(i);
int index = navigator.getIndex();
assert result != null;
if (result instanceof CommonCompoundLiteralObject) {
result = ((CommonCompoundLiteralObject) result).get(index);
if (result == null)
break;
} else
throw new NoSuchElementException();
}
return result;
}
public void setElement(Source source, int index, LiteralObject value)
throws SyntaxException {
LiteralTypeNode typeNode = getTypeNode();
int length = typeNode.length();
if (typeNode.hasFixedLength() && index >= length)
throw new SyntaxException("Exceeded object bound: index=" + index
+ ", length=" + length, source);
while (index >= elements.size())
elements.add(null);
elements.set(index, value);
// the literal value was created using the same type nodes
// as those in this literal, therefore those nodes are already
// up to date. so it is only this length that has to be updated
if (elements.size() > length)
((LiteralArrayTypeNode) typeNode).setLength(elements.size());
}
private void set(Source source, Designation designation, int desStart,
LiteralObject value) throws SyntaxException {
int deslen = designation.length() - desStart;
int index0 = designation.get(desStart).getIndex();
assert deslen > 0;
if (deslen == 1) {
setElement(source, index0, value);
} else {
CommonCompoundLiteralObject r = (CommonCompoundLiteralObject) get(index0);
if (r == null) {
r = new CommonCompoundLiteralObject(getTypeNode().getChild(
index0), getSourceNode());
setElement(source, index0, r);
}
r.set(source, designation, desStart + 1, value);
}
}
/**
* Sets the sub-object at the designated position to value. Updates type
* nodes as necessary.
*
* @param designation
* @param value
* @throws SyntaxException
*/
public void set(Source source, Designation designation, LiteralObject value)
throws SyntaxException {
if (designation.length() == 0)
throw new ABCRuntimeException("saw empty designation in set");
set(source, designation, 0, value);
}
}