/******************************************************************************
* Copyright (c) 2009 - 2015 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*****************************************************************************/
/**
*
*/
package com.ibm.wala.memsat.representation;
import java.util.ArrayList;
import java.util.List;
import kodkod.ast.Formula;
/**
* A value, field, or array composed of one or more guarded values.
*
* @specfield size: int
* @specfield guards: [0..size) ->one Formula
* @specfield phis: [0..size) ->one E
* @invariant size >= 0
* @invariant E in Node + HeapExpression + RealExpression
* @author Emina Torlak
*/
public abstract class PhiExpression<E> {
private PhiExpression() {}
/**
* Returns the number of guard/value pairs in this phi expression.
* @return this.size
*/
public abstract int size();
/**
* Adds the guard/value pair to this.phis. This method
* assumes that the given may evaluate to true only
* if all the guards seen so far evaluate to false.
* @requires value in HeapExpression and some this.phis =>
* value.walaField = this.phis[int].walaField
* @effects this.size' = this.size + 1
* @effects this.phis' = this.phis + this.size -> value
* @effects this.guards' = this.guards + this.size -> guard
* @throws IllegalArgumentException - guard/value is not a valid
* entry for this phi expression
*/
public abstract void add(Formula guard, E value);
/**
* Returns an instance of E that evaluates to the value in
* this.phis[int] whose guard evaluates to true. If no
* guard is true, or more than one guard is true, the meaning
* of the returned value is undefined.
* @return an instance of E that evaluates to the value in
* this.phis[int] whose guard evaluates to true.
* @throws IllegalStateException - this.size = 0
*/
public abstract E value();
/**
* Returns an empty PhiExpression for values of type interpreter.type().
* @return an empty PhiExpression for values of type interpreter.type()
*/
static <E> PhiExpression<E> valuePhi(final Interpreter<E> interpreter) {
return new PhiExpression<E>() {
private final List<E> phis = new ArrayList<E>();
private E value;
@Override
public void add(Formula guard, E value) {
phis.add(interpreter.guardedValue(guard, value));
value = null;
}
@Override
public E value() {
if (value==null) {
if (phis.isEmpty())
throw new IllegalStateException("cannot compute a phi with no values");
value = interpreter.phi(phis);
}
return value;
}
@Override
public int size() {
return phis.size();
}
};
}
/**
* Returns a PhiExpression initialized with the given
* guard / heap value pair. All subsequent calls to
* {@linkplain #add(Formula, Object)} on the returned
* phi expression must be passed a HeapExpression with
* the same <tt>walaField</tt> as the given heap expression.
* @return a PhiExpression initialized with the given
* guard / heap value pair
*/
static <E> PhiExpression<HeapExpression<E>> heapPhi(final Formula guard, final HeapExpression<E> expr) {
return new PhiExpression<HeapExpression<E>>() {
private final List<Formula> guards = new ArrayList<Formula>();
private final List<HeapExpression<E>> values = new ArrayList<HeapExpression<E>>();
private HeapExpression<E> value;
private final boolean isArray = expr.isArray();
{ add(guard,expr); }
@Override
public void add(Formula guard, HeapExpression<E> value) {
assert guard != null && value.isArray()==isArray;
guards.add(guard);
values.add(value);
value = null;
}
@SuppressWarnings("unchecked")
@Override
public HeapExpression<E> value() {
if (value == null) {
if (isArray) {
value = ArrayExpression.phi(guards, (List<ArrayExpression<E>>)(List<?>)values);
} else {
value = FieldExpression.phi(guards, (List<FieldExpression<E>>)(List<?>)values);
}
}
return value;
}
@Override
public int size() {
return guards.size();
}
};
}
}