CompilerContext context = generatorContext.getContext();
// process value, else, and all when clauses
RowExpression value = arguments.get(0);
ByteCodeNode valueBytecode = generatorContext.generate(value);
ByteCodeNode elseValue;
List<RowExpression> whenClauses;
RowExpression last = arguments.get(arguments.size() - 1);
if (last instanceof CallExpression && ((CallExpression) last).getSignature().getName().equals("WHEN")) {
whenClauses = arguments.subList(1, arguments.size());
elseValue = new Block(context)
.putVariable("wasNull", true)
.pushJavaDefault(returnType.getJavaType());
}
else {
whenClauses = arguments.subList(1, arguments.size() - 1);
elseValue = generatorContext.generate(last);
}
// determine the type of the value and result
Class<?> valueType = value.getType().getJavaType();
// evaluate the value and store it in a variable
LabelNode nullValue = new LabelNode("nullCondition");
Variable tempVariable = context.createTempVariable(valueType);
Block block = new Block(context)
.append(valueBytecode)
.append(ByteCodeUtils.ifWasNullClearPopAndGoto(context, nullValue, void.class, valueType))
.putVariable(tempVariable);
ByteCodeNode getTempVariableNode = VariableInstruction.loadVariable(tempVariable);
// build the statements
elseValue = new Block(context).visitLabel(nullValue).append(elseValue);
// reverse list because current if statement builder doesn't support if/else so we need to build the if statements bottom up
for (RowExpression clause : Lists.reverse(whenClauses)) {
Preconditions.checkArgument(clause instanceof CallExpression && ((CallExpression) clause).getSignature().getName().equals("WHEN"));
RowExpression operand = ((CallExpression) clause).getArguments().get(0);
RowExpression result = ((CallExpression) clause).getArguments().get(1);
// call equals(value, operand)
FunctionInfo equalsFunction = generatorContext.getRegistry().resolveOperator(OperatorType.EQUAL, ImmutableList.of(value.getType(), operand.getType()));
// TODO: what if operand is null? It seems that the call will return "null" (which is cleared below)
// and the code only does the right thing because the value in the stack for that scenario is
// Java's default for boolean == false
// This code should probably be checking for wasNull after the call and "failing" the equality
// check if wasNull is true
ByteCodeNode equalsCall = generatorContext.generateCall(
equalsFunction,
ImmutableList.of(generatorContext.generate(operand), getTempVariableNode));
Block condition = new Block(context)
.append(equalsCall)