com.strobel.expressions.ConcatExpression Maven / Gradle / Ivy
/*
* ConcatExpression.java
*
* Copyright (c) 2012 Mike Strobel
*
* This source code is based on the Dynamic Language Runtime from Microsoft,
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0.
* A copy of the license can be found in the License.html file at the root of this distribution.
* By using this source code in any fashion, you are agreeing to be bound by the terms of the
* Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*/
package com.strobel.expressions;
import com.strobel.collections.ImmutableList;
import com.strobel.collections.ListBuffer;
import com.strobel.reflection.Type;
import com.strobel.reflection.Types;
/**
* @author Mike Strobel
*/
public final class ConcatExpression extends Expression {
private final ExpressionList extends Expression> _operands;
public ConcatExpression(final ExpressionList extends Expression> operands) {
_operands = operands;
}
public ExpressionList extends Expression> getOperands() {
return _operands;
}
@Override
public ExpressionType getNodeType() {
return ExpressionType.Extension;
}
@Override
public Type> getType() {
return Types.String;
}
@Override
protected Expression accept(final ExpressionVisitor visitor) {
return visitor.visitConcat(this);
}
public final ConcatExpression update(final ExpressionList extends Expression> operands) {
if (operands == _operands) {
return this;
}
return concat(operands);
}
final ConcatExpression rewrite(final ExpressionList extends Expression> operands) {
assert operands == null || operands.size() == _operands.size();
return concat(operands);
}
@Override
protected Expression visitChildren(final ExpressionVisitor visitor) {
return update(visitor.visit(getOperands()));
}
@Override
public boolean canReduce() {
return true;
}
@Override
public Expression reduce() {
final ExpressionList extends Expression> originalOperands = _operands;
final ListBuffer reducedOperands = ListBuffer.lb();
for (int i = 0, n = originalOperands.size(); i < n; i++) {
final Expression operand = originalOperands.get(i);
if (!ConstantCheck.isStringLiteral(operand)) {
reducedOperands.add(operand);
continue;
}
StringBuilder sb = null;
for (int j = i + 1; j < n; j++) {
final Expression nextOperand = originalOperands.get(j);
if (!ConstantCheck.isStringLiteral(nextOperand)) {
break;
}
if (sb == null) {
sb = new StringBuilder();
sb.append((String)((ConstantExpression)operand).getValue());
}
sb.append((String)((ConstantExpression)nextOperand).getValue());
++i;
}
reducedOperands.add(
sb != null ? constant(sb.toString())
: operand
);
}
final ParameterExpression sb = variable(Types.StringBuilder);
final Expression[] body = new Expression[reducedOperands.size() + 2];
body[0] = assign(
sb,
makeNew(Types.StringBuilder.getConstructor())
);
int i = 0;
for (ImmutableList o = reducedOperands.toList();
o.nonEmpty();
o = o.tail) {
body[++i] = call(sb, "append", o.head);
}
body[body.length - 1] = call(sb, "toString");
return block(
new ParameterExpression[] { sb },
body
);
}
}