/** * Translate from an array of indices of the burnable inputs to an array of indices of all inputs * to the gem * * @param unboundArgsToBurn An array of indices relative to the burnable (ie unburned, unbound) * inputs of the gem * @param sourceGem The gem that these are the inputs of * @return An array of indices of inputs relative to ALL inputs of the gem, corresponding to the * contents of unburnedArgsToBurn. */ private static int[] translateBurnCombo(int[] unboundArgsToBurn, Gem sourceGem) { int[] argsToBurn = new int[unboundArgsToBurn.length]; // loop indices: // i - index of the current input // j - counter to keep track of how many unbound and unburned inputs we have passed // k - index of the next element of unboudnArgsToBurn to check for (int i = 0, j = 0, k = 0; i < sourceGem.getNInputs() && k < unboundArgsToBurn.length; i++) { Gem.PartInput currentInput = sourceGem.getInputPart(i); if (currentInput.isConnected() || currentInput.isBurnt()) { // Skip over unburnable inputs continue; } // This is the j'th burnable input // Check to see if this argument should be burned, and if so, add its index relative to the // list of all inputs // to the argsToBurn array if (unboundArgsToBurn[k] == j) { argsToBurn[k] = i; k++; } j++; } return argsToBurn; }
/** * Return whether autoburning will result in a unification. Only inputs on the given gem will be * considered for burning. * * @param destType The destination type to unify with. * @param gem The gem on which to attempt "autoburning". * @param info the typeCheck info to use. * @return AutoburnLogic.AutoburnInfo autoburnable result. */ public static AutoburnInfo getAutoburnInfo(TypeExpr destType, Gem gem, TypeCheckInfo info) { // see if we got a real type if (destType == null) { return AutoburnInfo.makeNoUnificationPossibleAutoburnInfo(); } int[] burnableArgIndices; List<TypeExpr> sourceTypeList = new ArrayList<TypeExpr>(); // input types, then output type. TypeExpr outType = (gem instanceof CollectorGem) ? ((CollectorGem) gem).getCollectingPart().getType() : gem.getOutputPart().getType(); TypeExpr[] outTypePieces = outType.getTypePieces(); // A collector gem's collecting part is not burnable. if (gem instanceof CollectorGem && !((CollectorGem) gem).isConnected()) { burnableArgIndices = new int[0]; } else { // declare the burnt arg indices array burnableArgIndices = new int[gem.getNInputs()]; if (burnableArgIndices.length != 0) { // get the unbound input parts of the gem and keep track of which ones are burnable int unburnedCount = 0; int burnedCount = 0; for (int i = 0, n = gem.getNInputs(); i < n; i++) { Gem.PartInput input = gem.getInputPart(i); if (!input.isConnected()) { if (input.isBurnt()) { sourceTypeList.add(outTypePieces[burnedCount]); burnedCount++; } else { sourceTypeList.add(input.getType()); burnableArgIndices[unburnedCount] = sourceTypeList.size() - 1; unburnedCount++; } } } // Calculate what the output type would be if none of the arguments were burned. TypeExpr newOutType = outTypePieces[outTypePieces.length - 1]; for (int i = outTypePieces.length - 2; i >= burnedCount; i--) { newOutType = TypeExpr.makeFunType(outTypePieces[i], newOutType); } outType = newOutType; // Assign to a new trimmed down array int[] newIndices = new int[unburnedCount]; System.arraycopy(burnableArgIndices, 0, newIndices, 0, unburnedCount); burnableArgIndices = newIndices; } } // Add the output type to the source types. sourceTypeList.add(outType); return getAutoburnInfoWorker( destType, sourceTypeList.toArray(new TypeExpr[0]), burnableArgIndices, info, gem); }