private ExpressionNode rewriteHVLookup( ExpressionNodeForFunction _fun )
{
final Function fun = _fun.getFunction();
final ExpressionNode valueNode = _fun.argument( 0 );
final ExpressionNodeForArrayReference arrayNode = (ExpressionNodeForArrayReference) _fun.argument( 1 );
final ExpressionNode indexNode = _fun.argument( 2 );
final ExpressionNode lookupArrayNode = getHVLookupSubArray( fun, arrayNode, 0 );
final ExpressionNode matchNode;
final Function matchFun = (indexNode instanceof ExpressionNodeForConstantValue) ? INTERNAL_MATCH_INT : MATCH;
if (_fun.cardinality() >= 4) {
final ExpressionNode typeNode = _fun.argument( 3 );
matchNode = new ExpressionNodeForFunction( matchFun, valueNode, lookupArrayNode, typeNode );
}
else {
matchNode = new ExpressionNodeForFunction( matchFun, valueNode, lookupArrayNode );
}
if (indexNode instanceof ExpressionNodeForConstantValue) {
final ExpressionNodeForConstantValue constIndex = (ExpressionNodeForConstantValue) indexNode;
final int index = this.numericType.toInt( constIndex.value(), -1 ) - 1;
final ExpressionNode valueArrayNode = getHVLookupSubArray( fun, arrayNode, index );
return fun( INDEX, valueArrayNode, matchNode );
}
else {
final String matchRefName = "x";
final ExpressionNode matchRefNode = var( matchRefName );
final ExpressionNode selectorNode = indexNode;
final ExpressionNode defaultNode = err( "#VALUE/REF! because index is out of range in H/VLOOKUP" );
final ArrayDescriptor desc = arrayNode.arrayDescriptor();
final int nArrays = (fun == HLOOKUP) ? desc.numberOfRows() : desc.numberOfColumns();
final ExpressionNodeForSwitchCase[] caseNodes = new ExpressionNodeForSwitchCase[ nArrays ];
for (int iArray = 0; iArray < nArrays; iArray++) {
final ExpressionNode valueArrayNode = getHVLookupSubArray( fun, arrayNode, iArray );
final ExpressionNode lookupNode = fun( INDEX, valueArrayNode, matchRefNode );
caseNodes[ iArray ] = new ExpressionNodeForSwitchCase( lookupNode, iArray + 1 );
}
final ExpressionNode switchNode = new ExpressionNodeForSwitch( selectorNode, defaultNode, caseNodes );
final ExpressionNode matchLetNode = letByName( matchRefName, matchNode, switchNode );
return matchLetNode;
}
}