package expressions;
import java.util.Arrays;
import java.util.Vector;
import common.prettyprinter.PrettyStringBuilder;
import expressions.annotation.SyntacticSugar;
/**
* Syntactic sugar for lists.
*
* @author Benedikt Meurer
* @version $Id$
*/
@SyntacticSugar
public final class List extends Expression {
//
// Attributes
//
/**
* The expressions within this list.
*
* @see #getExpressions()
* @see #getExpressions(int)
*/
private Expression[] expressions;
//
// Constructor
//
/**
* Constructs a new <code>List</code> instance
* with the specified <code>expressions</code>.
*
* @param expressions a non empty array of {@link Expression}s.
*
* @throws IllegalArgumentException if <code>expressions</code>
* is empty.
*/
public List(Expression[] expressions) {
if (expressions.length == 0) {
throw new IllegalArgumentException("expressions is empty");
}
this.expressions = expressions;
}
/**
* Creates a new <code>List</code> with <code>e1</code> as the
* first list item. <code>e2</code> can either be the empty
* list, anoter <code>List</code> instance, or an application
* of the {@link UnaryCons} operator to a pair where the
* second item can again be interpreted as <code>List</code>
* using this constructor.
*
* @param e1 the first item.
* @param e2 another list.
*
* @throws ClassCastException if none of the above conditions
* match.
*/
List(Expression e1, Expression e2) {
// allocate a vector for the expressions of the list and
// prepend e1 as new first item
Vector<Expression> expressions = new Vector<Expression>();
expressions.add(e1);
// now check e2
if (e2 instanceof EmptyList) {
// e2 is the empty list, nothing to append
}
else if (e2 instanceof List) {
// e2 is a List, append the items
expressions.addAll(Arrays.asList(((List)e2).getExpressions()));
}
else {
// e2 must be an application of unary cons to a pair
Application app2 = (Application)e2;
Tuple tuple = (Tuple)app2.getE2();
if (!(app2.getE1() instanceof UnaryCons) || tuple.getArity() != 2) {
throw new ClassCastException();
}
// turn the tuple into a list
List list = new List(tuple.getExpressions(0), tuple.getExpressions(1));
// and add the list items to our expressions
expressions.addAll(Arrays.asList(list.getExpressions()));
}
// jep, we have our expression list
this.expressions = expressions.toArray(new Expression[0]);
}
//
// Primitives
//
/**
* {@inheritDoc}
*
* @see expressions.Expression#isValue()
*/
@Override
public boolean isValue() {
for (Expression expression : this.expressions) {
if (!expression.isValue()) {
return false;
}
}
return true;
}
/**
* {@inheritDoc}
*
* @see expressions.Expression#translateSyntacticSugar()
*/
@Override
public Expression translateSyntacticSugar() {
Expression e = EmptyList.EMPTY_LIST;
for (int n = this.expressions.length - 1; n >= 0; --n) {
e = new Application(UnaryCons.CONS, new Tuple(new Expression[] { this.expressions[n], e }));
}
return e;
}
/**
* {@inheritDoc}
*
* @see expressions.Expression#substitute(java.lang.String, expressions.Expression)
*/
@Override
public Expression substitute(String id, Expression e) {
// substitute all subexpressions
Expression[] expressions = new Expression[this.expressions.length];
for (int n = 0; n < expressions.length; ++n)
expressions[n] = this.expressions[n].substitute(id, e);
return new List(expressions);
}
/**
* {@inheritDoc}
*
* @see expressions.Expression#toPrettyStringBuilder()
*/
@Override
protected PrettyStringBuilder toPrettyStringBuilder() {
PrettyStringBuilder builder = new PrettyStringBuilder(this, 6);
builder.appendText("[");
for (int n = 0; n < this.expressions.length; ++n) {
if (n > 0) {
builder.appendText("; ");
builder.appendBreak();
}
builder.appendBuilder(this.expressions[n].toPrettyStringBuilder(), 0);
}
builder.appendText("]");
return builder;
}
//
// Accessors
//
/**
* Returns the sub expressions within this <code>List</code>.
*
* @return the sub expressions within this <code>List</code>.
*/
public Expression[] getExpressions() {
return this.expressions;
}
/**
* Returns the sub expression at the specified <code>index</code>.
*
* @param index the index of the sub expression to return.
*
* @return the sub expression at <code>index</code>.
*
* @throws ArrayIndexOutOfBoundsException if the <code>index</code>
* is out of bounds.
*/
public Expression getExpressions(int index) {
return this.expressions[index];
}
//
// List methods
//
/**
* Returns the first expression in the list.
*
* @return the first expression in the list.
*
* @see #tail()
*/
public Expression head() {
return this.expressions[0];
}
/**
* Returns the list without the first expression,
* which may be the empty list.
*
* @return the list without the first expression.
*
* @see #head()
*/
public Expression tail() {
if (this.expressions.length > 1) {
Expression[] expressions = new Expression[this.expressions.length - 1];
for (int n = 0; n < expressions.length; ++n) {
expressions[n] = this.expressions[n + 1];
}
return new List(expressions);
}
else {
return EmptyList.EMPTY_LIST;
}
}
}