ReadWriteDataStructureImpl.java
package dev.civl.mc.transform.analysis.common;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import dev.civl.abc.analysis.pointsTo.IF.AssignExprIF;
import dev.civl.abc.analysis.pointsTo.IF.AssignOffsetIF;
import dev.civl.abc.ast.node.IF.ASTNode;
import dev.civl.abc.ast.node.IF.expression.ExpressionNode;
import dev.civl.abc.ast.type.IF.ArrayType;
import dev.civl.abc.ast.type.IF.Field;
import dev.civl.abc.ast.type.IF.ObjectType;
import dev.civl.abc.ast.type.IF.Type;
import dev.civl.mc.transform.analysisIF.ReadWriteDataStructures;
public class ReadWriteDataStructureImpl implements ReadWriteDataStructures {
/* ******************* RWSetElement implementations **********************/
public static abstract class CommonRWSetElement implements RWSetElement {
protected Type type;
private ASTNode source;
CommonRWSetElement(ASTNode source, Type type) {
this.source = source;
this.type = type;
}
@Override
public ASTNode source() {
return source;
}
@Override
public Type type() {
return type;
}
}
public static class CommonRWSetArbitraryElement extends CommonRWSetElement
implements
RWSetArbitraryElement {
CommonRWSetArbitraryElement(ASTNode source, Type type) {
super(source, type);
}
@Override
public RWSetElementKind kind() {
return RWSetElementKind.ARBITRARY;
}
@Override
public String toString() {
return "arbitrary(" + type + ")";
}
@Override
public boolean equals(Object o) {
if (o instanceof RWSetArbitraryElement) {
return ((RWSetArbitraryElement) o).type().equals(type());
}
return false;
}
@Override
public int hashCode() {
return kind().hashCode() ^ 31 * type().hashCode();
}
@Override
public AssignExprIF root() {
return null;
}
@Override
public int depth() {
return 0; // unreachable
}
}
public static class CommonRWSetBaseElement extends CommonRWSetElement
implements
RWSetBaseElement {
private AssignExprIF base;
CommonRWSetBaseElement(ASTNode source, Type type, AssignExprIF base) {
super(source, type);
this.base = base;
}
@Override
public RWSetElementKind kind() {
return RWSetElementKind.BASE;
}
@Override
public AssignExprIF base() {
return base;
}
@Override
public String toString() {
return base.toString();
}
@Override
public boolean equals(Object o) {
if (o instanceof RWSetBaseElement) {
return ((RWSetBaseElement) o).base().equals(base);
}
return false;
}
@Override
public int hashCode() {
return kind().hashCode()
^ (base.hashCode() + 31 * type().hashCode());
}
@Override
public AssignExprIF root() {
return base;
}
@Override
public int depth() {
return 1;
}
}
public static class CommonRWSetFieldElement extends CommonRWSetElement
implements
RWSetFieldElement {
private Field field;
private RWSetElement struct;
CommonRWSetFieldElement(ASTNode source, Type type, RWSetElement struct,
Field field) {
super(source, type);
this.struct = struct;
this.field = field;
}
@Override
public RWSetElementKind kind() {
return RWSetElementKind.FIELD;
}
@Override
public RWSetElement struct() {
return struct;
}
@Override
public Field field() {
return field;
}
@Override
public String toString() {
return struct.toString() + "." + field.getName();
}
@Override
public boolean equals(Object o) {
if (o instanceof RWSetFieldElement) {
RWSetFieldElement other = (RWSetFieldElement) o;
return other.struct().equals(struct())
&& other.field() == field();
}
return false;
}
@Override
public int hashCode() {
return kind().hashCode() ^ (struct.hashCode() + 7 * field.hashCode()
+ 31 * type().hashCode());
}
@Override
public AssignExprIF root() {
return struct.root();
}
@Override
public int depth() {
return struct.depth() + 1;
}
}
public static class CommonRWSetOffsetElement extends CommonRWSetElement
implements
RWSetOffsetElement {
private ExpressionNode offset;
private boolean isPositive;
private RWSetElement base;
CommonRWSetOffsetElement(ASTNode source, Type type, RWSetElement base,
ExpressionNode offset, boolean isPositive) {
super(source, type);
this.base = base;
this.isPositive = isPositive;
this.offset = offset;
}
@Override
public RWSetElementKind kind() {
return RWSetElementKind.OFFSET;
}
@Override
public RWSetElement base() {
return base;
}
@Override
public ExpressionNode offset() {
return offset;
}
@Override
public boolean isPositive() {
return isPositive;
}
@Override
public String toString() {
String sign = isPositive ? " + " : " - ";
return base.toString() + sign + offset.prettyRepresentation();
}
@Override
public boolean equals(Object o) {
if (o instanceof RWSetOffsetElement) {
RWSetOffsetElement other = (RWSetOffsetElement) o;
return other.base().equals(base())
&& other.offset().equals(offset())
&& other.isPositive() == isPositive;
}
return false;
}
@Override
public int hashCode() {
return kind().hashCode() ^ (base.hashCode() + 7 * offset.hashCode()
+ 31 * type().hashCode() + (isPositive ? 1 : 0));
}
@Override
public AssignExprIF root() {
return this.base.root();
}
@Override
public int depth() {
return base.depth() + 1;
}
}
public static class CommonRWSetSubscriptElement extends CommonRWSetElement
implements
RWSetSubscriptElement {
private RWSetElement array;
/**
* offset to the sub-array which is actually subscripted:
*/
private AssignOffsetIF offset;
private ExpressionNode[] indices;
CommonRWSetSubscriptElement(ASTNode source, Type type,
RWSetElement array, AssignOffsetIF offset,
ExpressionNode[] indices) {
super(source, type);
this.array = array;
this.offset = offset;
this.indices = indices;
}
@Override
public RWSetElementKind kind() {
return RWSetElementKind.SUBSCRIPT;
}
@Override
public RWSetElement array() {
return array;
}
@Override
public AssignOffsetIF offset() {
return offset;
}
@Override
public ExpressionNode[] indices() {
return indices;
}
@Override
public String toString() {
String str = array.toString();
str += "[" + offset.toString() + " + "
+ indices[0].prettyRepresentation() + "]";
for (int i = 1; i < indices.length; i++)
str += "[" + indices[i].prettyRepresentation() + "]";
return str;
}
@Override
public boolean equals(Object o) {
if (o instanceof RWSetSubscriptElement) {
RWSetSubscriptElement other = (RWSetSubscriptElement) o;
return other.array().equals(array())
&& other.offset().equals(offset())
&& Arrays.equals(other.indices(), indices);
}
return false;
}
@Override
public int hashCode() {
return kind().hashCode() ^ (array.hashCode() + 7 * offset.hashCode()
+ 31 * type().hashCode() + 91 * Arrays.hashCode(indices));
}
@Override
public AssignExprIF root() {
return this.array.root();
}
@Override
public int depth() {
return array.depth() + 1;
}
}
/* ******************* RWSet implementations **********************/
public static class CommonRWSet implements RWSet {
private Set<RWSetElement> reads;
private Set<RWSetElement> writes;
public CommonRWSet() {
this.reads = new HashSet<>();
this.writes = new HashSet<>();
}
@Override
public Set<RWSetElement> reads() {
return reads;
}
@Override
public Set<RWSetElement> writes() {
return writes;
}
@Override
public void addReads(RWSetElement... elements) {
for (RWSetElement e : elements)
reads.add(e);
}
@Override
public void addWrites(RWSetElement... elements) {
for (RWSetElement e : elements)
writes.add(e);
}
@Override
public void addReads(Iterable<RWSetElement> elements) {
for (RWSetElement e : elements)
reads.add(e);
}
@Override
public void addWrites(Iterable<RWSetElement> elements) {
for (RWSetElement e : elements)
writes.add(e);
}
@Override
public void add(RWSet rwset) {
this.reads.addAll(rwset.reads());
this.writes.addAll(rwset.writes());
}
@Override
public String toString() {
return "read:\n" + reads + "\nwrites\n" + writes;
}
}
/* ******************* factory implementations **********************/
public static class CommonReadWriteDataStructureFactory
implements
ReadWriteDataStructureFactory {
@Override
public RWSet newRWSet() {
return new CommonRWSet();
}
@Override
public RWSetElement arbitraryElement(ASTNode source, Type type) {
return new CommonRWSetArbitraryElement(source, type);
}
@Override
public RWSetElement baseElement(ASTNode source, AssignExprIF base) {
return new CommonRWSetBaseElement(source, base.type(), base);
}
@Override
public RWSetElement fieldElement(ASTNode source, RWSetElement struct,
Field field) {
assert struct.kind() != RWSetElement.RWSetElementKind.ARBITRARY;
return new CommonRWSetFieldElement(source, field.getType(), struct,
field);
}
@Override
public RWSetElement offsetElement(ASTNode source, RWSetElement base,
ExpressionNode offset, boolean isPositive) {
assert base.kind() != RWSetElement.RWSetElementKind.ARBITRARY;
return new CommonRWSetOffsetElement(source, base.type(), base,
offset, isPositive);
}
@Override
public RWSetElement subscriptElement(ASTNode source, RWSetElement array,
AssignOffsetIF offset, ExpressionNode[] indices) {
assert array.kind() != RWSetElement.RWSetElementKind.ARBITRARY;
Type type = (ObjectType) array.type();
int i = 1;
do {
type = ((ArrayType) type).getElementType();
} while (i++ < indices.length);
return new CommonRWSetSubscriptElement(source, type, array, offset,
indices);
}
}
}