/*
* Copyright 2015 S. Webber
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.oakgp.function.choice;
import static java.lang.Boolean.TRUE;
import static org.oakgp.Type.booleanType;
import static org.oakgp.node.NodeType.isConstant;
import java.util.function.Predicate;
import org.oakgp.Arguments;
import org.oakgp.Assignments;
import org.oakgp.Type;
import org.oakgp.function.Function;
import org.oakgp.function.Signature;
import org.oakgp.node.FunctionNode;
import org.oakgp.node.Node;
import org.oakgp.node.walk.NodeWalk;
import org.oakgp.util.Utils;
/**
* A selection operator that uses a boolean expression to determine which code to evaluate.
* <p>
* Expects three arguments:
* <ol>
* <li>Conditional statement.</li>
* <li>Value to evaluate to if the conditional statement is {@code true}.</li>
* <li>Value to evaluate to if the conditional statement is {@code false}.</li>
* </ol>
*/
public final class If implements Function {
private static final int TRUE_IDX = 1;
private static final int FALSE_IDX = 2;
private final Signature signature;
/** Constructs a selection operator that returns values of the specified type. */
public If(Type type) {
signature = Signature.createSignature(type, booleanType(), type, type);
}
@Override
public Object evaluate(Arguments arguments, Assignments assignments) {
int index = getOutcomeArgumentIndex(arguments, assignments);
return arguments.getArg(index).evaluate(assignments);
}
@Override
public Signature getSignature() {
return signature;
}
@Override
public Node simplify(Arguments arguments) {
Node trueBranch = arguments.secondArg();
Node falseBranch = arguments.thirdArg();
if (trueBranch.equals(falseBranch)) {
return trueBranch;
}
Node condition = arguments.firstArg();
if (isConstant(condition)) {
int index = getOutcomeArgumentIndex(arguments, null);
return index == TRUE_IDX ? trueBranch : falseBranch;
}
Predicate<Node> criteria = n -> n.equals(condition);
Node simplifiedTrueBranch = NodeWalk.replaceAll(trueBranch, criteria, n -> Utils.TRUE_NODE);
Node simplifiedFalseBranch = NodeWalk.replaceAll(falseBranch, criteria, n -> Utils.FALSE_NODE);
if (trueBranch != simplifiedTrueBranch || falseBranch != simplifiedFalseBranch) {
return new FunctionNode(this, condition, simplifiedTrueBranch, simplifiedFalseBranch);
} else {
return null;
}
}
private int getOutcomeArgumentIndex(Arguments arguments, Assignments assignments) {
return TRUE.equals(arguments.firstArg().evaluate(assignments)) ? TRUE_IDX : FALSE_IDX;
}
}