CommonAddressOfExpression.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.AddressOfExpression;
import dev.civl.mc.model.IF.expression.ConditionalExpression;
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.CIVLPointerType;
import dev.civl.mc.model.IF.type.CIVLSetType;
import dev.civl.mc.model.IF.type.CIVLType;
import dev.civl.mc.model.IF.variable.Variable;

public class CommonAddressOfExpression extends CommonExpression
		implements
			AddressOfExpression {

	/* ************************** Private Fields *************************** */

	/**
	 * The operand of the address-off operator (<code> & </code>).
	 */
	private LHSExpression operand;

	/**
	 * Is this expression evaluating the offset of a field of some struct, which
	 * has the form <code>&(((T*)0)->f)</code>?
	 */
	private boolean isOffset = false;

	private CIVLType type4Offset = null;

	private int fieldIndex = -1;

	/* **************************** Constructor **************************** */

	/**
	 * Creates a new instance of AddressOfExpression.
	 * 
	 * @param source
	 *            The source code information of the expression.
	 * @param type
	 *            The type of the expression, which is always a (set-of) pointer
	 *            type.
	 * @param operand
	 *            The operand of the address-of operator (<code>&</code>).
	 */
	public CommonAddressOfExpression(CIVLSource source, CIVLType type,
			LHSExpression operand) {
		super(source, operand.expressionScope(), operand.lowestScope(), type);
		assert type.isPointerType() || (type.isSetType()
				&& ((CIVLSetType) type).elementType().isPointerType());
		this.operand = operand;
	}

	/* ****************** Methods from AddressOfExpression ***************** */

	@Override
	public LHSExpression operand() {
		return operand;
	}

	/* ********************** Methods from Expression ********************** */

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

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

	@Override
	public void purelyLocalAnalysisOfVariables(Scope funcScope) {
		this.operand.setPurelyLocal(false);
	}

	@Override
	public void purelyLocalAnalysis() {
		if (this.hasDerefs) {
			this.purelyLocal = false;
			return;
		}
		this.operand.purelyLocalAnalysis();
		this.purelyLocal = this.operand.isPurelyLocal();
	}

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

	@Override
	public Expression replaceWith(ConditionalExpression oldExpression,
			Expression newExpression) {
		Expression newOperand = operand.replaceWith(oldExpression,
				newExpression);
		CommonAddressOfExpression result = null;

		if (newOperand != null) {
			result = new CommonAddressOfExpression(this.getSource(),
					(CIVLPointerType) this.expressionType,
					(LHSExpression) newOperand);
		}
		return result;
	}

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

		if (variableWritten != null)
			variableSet.add(variableWritten);
		return variableSet;
	}

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

		if (variableWritten != null)
			variableSet.add(variableWritten);
		return variableSet;
	}

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

	/* ************************ Methods from Object ************************ */

	@Override
	public String toString() {
		return "&(" + operand + ")";
	}

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

		return this.operand.equals(that.operand());
	}

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

	@Override
	public void setErrorFree(boolean value) {
		super.setErrorFree(value);
		this.operand.setErrorFree(value);
	}

	@Override
	public boolean isFieldOffset() {
		return this.isOffset;
	}

	@Override
	public void setFieldOffset(boolean value) {
		this.isOffset = value;
	}

	@Override
	public void setTypeForOffset(CIVLType type) {
		this.type4Offset = type;
	}

	@Override
	public void setFieldIndex(int index) {
		this.fieldIndex = index;
	}

	@Override
	public CIVLType getTypeForOffset() {
		return this.type4Offset;
	}

	@Override
	public int getFieldIndex() {
		return this.fieldIndex;
	}
}