/*
* JAME 6.2.1
* http://jame.sourceforge.net
*
* Copyright 2001, 2016 Andrea Medeghini
*
* This file is part of JAME.
*
* JAME is an application for creating fractals and other graphics artifacts.
*
* JAME is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JAME is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JAME. If not, see <http://www.gnu.org/licenses/>.
*
*/
package net.sf.jame.contextfree.parser;
import java.util.List;
import org.antlr.v4.runtime.Token;
class ASTSelect extends ASTExpression {
private static final int NOT_CACHED = -1;
private List<ASTExpression> arguments;
private ASTExpression selector;
private int tupleSize;
private int indexCache;
private StringBuilder entropy;
private boolean isSelect;
public ASTSelect(ASTExpression arguments, boolean asIf, Token location) {
super(location);
tupleSize = -1;
indexCache = NOT_CACHED;
selector = arguments;
isConstant = false;
isSelect = asIf;
if (selector == null || selector.size() < 3) {
error("select()/if() function requires arguments");
}
}
public boolean isSelect() {
return isSelect;
}
@Override
public void entropy(StringBuilder e) {
e.append(entropy);
}
@Override
public StackRule evalArgs(RTI rti, StackRule parent) {
if (type != EExpType.RuleType) {
throw new RuntimeException("Evaluation of a non-shape select() in a shape context");
}
return arguments.get(getIndex(rti)).evalArgs(rti, parent);
}
@Override
public ASTExpression simplify() {
if (indexCache == NOT_CACHED) {
for (ASTExpression argument : arguments) {
if (argument != null) {
argument = argument.simplify();
}
}
selector.simplify();
return this;
}
ASTExpression chosenOne = arguments.get(indexCache);
return chosenOne.simplify();
}
@Override
public int evaluate(double[] result, int length, RTI rti) {
if (type != EExpType.NumericType) {
throw new RuntimeException("Evaluation of a non-shape select() in a numeric context");
}
if (result == null)
return tupleSize;
return arguments.get(getIndex(rti)).evaluate(result, length, rti);
}
@Override
public void evaluate(Modification[] modification, boolean shapeDest, RTI rti) {
if (type != EExpType.ModType) {
throw new RuntimeException("Evaluation of a non-adjustment select() in an adjustment context");
}
arguments.get(getIndex(rti)).evaluate(modification, shapeDest, rti);
}
@Override
public ASTExpression compile(ECompilePhase ph) {
if (selector == null) {
return null;
}
for (ASTExpression argument : arguments) {
if (argument != null) {
argument.compile(ph);
}
}
if (selector != null) {
selector.compile(ph);
}
switch (ph) {
case TypeCheck:
{
selector.entropy(entropy);
entropy.append("\u00B5\u00A2\u004A\u0074\u00A9\u00DF");
locality = selector.getLocality();
arguments = extract(selector);
selector = arguments.get(0);
arguments.remove(0);
if (selector.getType() != EExpType.NumericType || selector.evaluate(null, 0) != 1) {
error("if()/select() selector must be a numeric scalar");
return null;
}
if (arguments.size() < 2) {
error("if()/select() selector must have at least two arguments");
return null;
}
type = arguments.get(0).getType();
isNatural = arguments.get(0).isNatural();
tupleSize = type == EExpType.NumericType ? arguments.get(0).evaluate(null, 0) : 1;
for (int i = 1; i < arguments.size(); i++) {
if (type != arguments.get(i).getType()) {
error("select()/if() choices must be of same type");
} else if (type == EExpType.NumericType && tupleSize != -1 && arguments.get(0).evaluate(null, 0) != tupleSize) {
error("select()/if() choices must be of same length");
tupleSize = -1;
}
isNatural = isNatural && arguments.get(i).isNatural();
}
if (selector.isConstant()) {
indexCache = getIndex(null);
isConstant = arguments.get(indexCache).isConstant();
locality = arguments.get(indexCache).getLocality();
isNatural = arguments.get(indexCache).isNatural();
}
}
break;
case Simplify:
break;
default:
break;
}
return null;
}
private int getIndex(RTI rti) {
if (indexCache != NOT_CACHED) {
return indexCache;
}
double select[] = new double[] { 0.0 };
selector.evaluate(select, 1, rti);
if (isSelect) {
return select[0] != 0 ? 0 : 1;
}
int i = (int)select[0];
if (i >= arguments.size()) {
return arguments.size() - 1;
}
return i;
}
}