/**
*
*/
package expressions;
import java.util.Set;
import java.util.TreeSet;
import types.MonoType;
import common.prettyprinter.PrettyStringBuilder;
/**
* Implementation of the <b>(REC)</b> rule.
*
* @author bmeurer
* @version $Id$
*/
public final class Recursion extends Expression {
//
// Attributes
//
/**
* The identifier for the recursion.
*
* @see #getId()
*/
private String id;
/**
* The type for the <code>id</code> or <code>null</code>.
*
* @see #getTau()
*/
private MonoType tau;
/**
* The body of the recursion.
*
* @see #getE()g
*/
private Expression e;
//
// Constructors
//
/**
* Convenience wrapper for {@link #Recursion(String, MonoType, Expression)}
* passing <code>null</code> for <code>tau</code>.
*
* @param id the identifier of the recursive expression.
* @param e the expression.
*
* @throws NullPointerException if either <code>id</code> or
* <code>e</code> is <code>null</code>.
*/
public Recursion(String id, Expression e) {
this(id, null, e);
}
/**
* Allocates a new <b>(REC)</b> expression.
*
* @param id the identifier of the recursive expression.
* @param e the expression.
*
* @throws NullPointerException if either <code>id</code> or
* <code>e</code> is <code>null</code>.
*/
public Recursion(String id, MonoType tau, Expression e) {
if (id == null) {
throw new NullPointerException("id is null");
}
if (e == null) {
throw new NullPointerException("e is null");
}
this.id = id;
this.tau = tau;
this.e = e;
}
//
// Accessors
//
/**
* @return Returns the id.
*/
public String getId() {
return this.id;
}
/**
* @return Returns the tau.
*/
public MonoType getTau() {
return this.tau;
}
/**
* @return Returns the e.
*/
public Expression getE() {
return this.e;
}
//
// Primitives
//
/**
* Performs the substitution for recursive expressions.
*
* @param id the identifier.
* @param e the expression to substitute.
* @return the resulting expression.
*
* @see expressions.Expression#substitute(java.lang.String, expressions.Expression)
*/
@Override
public Expression substitute(String id, Expression e) {
if (this.id.equals(id)) {
return this;
}
else {
// determine the free identifiers for e
Set<String> free = e.free();
// generate a new unique identifier
String newId = this.id;
while (free.contains(newId))
newId = newId + "'";
// perform the bound renaming
Expression newE = this.e.substitute(this.id, new Identifier(newId));
// perform the substitution
return new Recursion(newId, this.tau, newE.substitute(id, e));
}
}
/**
* Returns the free identifiers of the
* subexpression minus the identifier of
* the <b>(REC)</b> expression.
*
* @return the free identifiers.
*
* @see expressions.Expression#free()
*/
@Override
public Set<String> free() {
Set<String> set = new TreeSet<String>();
set.addAll(this.e.free());
set.remove(this.id);
return set;
}
//
// Pretty printing
//
/**
* Returns the pretty string builder for rec expressions.
* @return the pretty string builder for rec expressions.
* @see expressions.Expression#toPrettyStringBuilder()
*/
@Override
protected PrettyStringBuilder toPrettyStringBuilder() {
PrettyStringBuilder builder = new PrettyStringBuilder(this, 0);
builder.appendKeyword("rec");
builder.appendText(" " + this.id);
if (this.tau != null) {
builder.appendText(":");
builder.appendText(this.tau.toString());
}
builder.appendText(".");
builder.appendBuilder(this.e.toPrettyStringBuilder(), 0);
return builder;
}
}