CommonDotExpression.java

/**
 * 
 */
package dev.civl.mc.model.common.expression;

import java.util.HashSet;
import java.util.Set;

import dev.civl.mc.model.IF.CIVLSource;
import dev.civl.mc.model.IF.Scope;
import dev.civl.mc.model.IF.expression.ConditionalExpression;
import dev.civl.mc.model.IF.expression.DotExpression;
import dev.civl.mc.model.IF.expression.Expression;
import dev.civl.mc.model.IF.expression.LHSExpression;
import dev.civl.mc.model.IF.expression.VariableExpression;
import dev.civl.mc.model.IF.type.CIVLSetType;
import dev.civl.mc.model.IF.type.CIVLType;
import dev.civl.mc.model.IF.variable.Variable;

/**
 * @author zirkel
 * 
 */
public class CommonDotExpression extends CommonExpression
		implements
			DotExpression {

	private Expression structOrUnion;// TODO shall this be of type
										// LHSExpression?
	private int fieldIndex;

	/**
	 * A dot expression is a reference to a field in a struct.
	 * 
	 * @param struct
	 *            The struct referenced by this dot expression.
	 * @param field
	 *            The field referenced by this dot expression.
	 */
	public CommonDotExpression(CIVLSource source, Expression struct,
			int fieldIndex, CIVLType expressionType) {
		super(source, struct.expressionScope(), struct.lowestScope(),
				expressionType);
		assert struct.getExpressionType().isStructType()
				|| struct.getExpressionType().isUnionType()
				|| struct.getExpressionType().isSetType();

		assert struct.getExpressionType().isSetType()
				? ((CIVLSetType) struct.getExpressionType()).elementType()
						.isStructType()
						|| ((CIVLSetType) struct.getExpressionType())
								.elementType().isUnionType()
				: true;
		this.structOrUnion = struct;
		this.fieldIndex = fieldIndex;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see dev.civl.mc.model.IF.expression.DotExpression#struct()
	 */
	@Override
	public Expression structOrUnion() {
		return structOrUnion;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see dev.civl.mc.model.IF.expression.DotExpression#field()
	 */
	@Override
	public int fieldIndex() {
		return fieldIndex;
	}

	@Override
	public String toString() {
		return "(" + structOrUnion.toString() + ")." + fieldIndex;
	}

	@Override
	public ExpressionKind expressionKind() {
		return ExpressionKind.DOT;
	}

	@Override
	public void calculateDerefs() {
		this.structOrUnion.calculateDerefs();
		this.hasDerefs = this.structOrUnion.hasDerefs();
	}

	@Override
	public void setPurelyLocal(boolean pl) {
		// TODO what if &(a.index) where a is defined as a struct
		// and index is a field of the struct
	}

	@Override
	public void purelyLocalAnalysisOfVariables(Scope funcScope) {
		this.structOrUnion.purelyLocalAnalysisOfVariables(funcScope);
		Scope exprScope = this.expressionScope();
		
		if (exprScope != null && funcScope.isDescendantOf(exprScope))
			this.setPurelyLocal(false);
	}

	@Override
	public void purelyLocalAnalysis() {
		if (this.hasDerefs) {
			this.purelyLocal = false;
			return;
		}
		// if (this.expressionType.isPointerType()
		// || this.expressionType.isHandleType()) {
		// this.setPurelyLocal(false);
		// return;
		// }
		this.structOrUnion.purelyLocalAnalysis();
		this.purelyLocal = this.structOrUnion.isPurelyLocal();
	}

	@Override
	public void replaceWith(ConditionalExpression oldExpression,
			VariableExpression newExpression) {
		if (structOrUnion == oldExpression) {
			structOrUnion = newExpression;
			return;
		}
		structOrUnion.replaceWith(oldExpression, newExpression);
	}

	@Override
	public Expression replaceWith(ConditionalExpression oldExpression,
			Expression newExpression) {
		Expression newStruct = structOrUnion.replaceWith(oldExpression,
				newExpression);
		CommonDotExpression result = null;

		if (newStruct != null) {
			result = new CommonDotExpression(this.getSource(), newStruct,
					this.fieldIndex, this.getExpressionType());
		}
		return result;
	}

	@Override
	public Variable variableWritten(Scope scope) {
		if (structOrUnion instanceof LHSExpression) {
			return ((LHSExpression) structOrUnion).variableWritten(scope);
		}
		return null;
	}

	@Override
	public Variable variableWritten() {
		if (structOrUnion instanceof LHSExpression) {
			return ((LHSExpression) structOrUnion).variableWritten();
		}
		return null;
	}

	@Override
	public Set<Variable> variableAddressedOf(Scope scope) {
		Set<Variable> variableSet = new HashSet<>();
		Set<Variable> operandResult = structOrUnion.variableAddressedOf(scope);

		if (operandResult != null)
			variableSet.addAll(operandResult);
		return variableSet;
	}

	@Override
	public Set<Variable> variableAddressedOf() {
		Set<Variable> variableSet = new HashSet<>();
		Set<Variable> operandResult = structOrUnion.variableAddressedOf();

		if (operandResult != null)
			variableSet.addAll(operandResult);
		return variableSet;
	}

	@Override
	public boolean isStruct() {
		CIVLType type = structOrUnion.getExpressionType();

		if (type.isSetType())
			type = ((CIVLSetType) type).elementType();
		return type.isStructType();
	}

	@Override
	public boolean isUnion() {
		CIVLType type = structOrUnion.getExpressionType();

		if (type.isSetType())
			type = ((CIVLSetType) type).elementType();
		return type.isUnionType();
	}

	@Override
	public LHSExpressionKind lhsExpressionKind() {
		return LHSExpressionKind.DOT;
	}

	@Override
	protected boolean expressionEquals(Expression expression) {
		DotExpression that = (DotExpression) expression;

		return this.fieldIndex == that.fieldIndex()
				&& this.structOrUnion.equals(that.structOrUnion());
	}

	@Override
	public boolean containsHere() {
		return this.structOrUnion.containsHere();
	}

	@Override
	protected void addFreeVariables(Set<Variable> result) {
		((CommonExpression) structOrUnion).addFreeVariables(result);
	}
}