/// <summary> /// Insert code to unwrap the computed value of a cell, if the cell /// has type Value but is referred to as a Number more than once. /// Also register the unwrapped version of the variable /// in the NumberVariables dictionary. /// CodeGenerate.Initialize(ilg) must be called first. /// </summary> public void CreateUnwrappedNumberCells() { HashBag<FullCellAddr> numberUses = CountNumberUses(); foreach (KeyValuePair<FullCellAddr, int> numberUseCount in numberUses.ItemMultiplicities()) { FullCellAddr fca = numberUseCount.Key; if (numberUseCount.Value >= 2 && addressToVariable[fca].Type == Typ.Value) { Variable numberVar = new LocalVariable(fca + "_number", Typ.Number); ComputeCell ccell; if (fcaToComputeCell.TryGetValue(fca, out ccell)) // fca is ordinary computed cell { ccell.NumberVar = numberVar; } else // fca is an input cell { unwrapInputCells.Add(new UnwrapInputCell(addressToVariable[fca], numberVar)); } NumberVariables.Add(fca, numberVar); } } }
/// <summary> /// Compiles the topologically sorted list of Expr to a list (program) /// of ComputeCells, encapsulating CGExprs. Builds a map from cellAddr to /// local variable ids, for compiling sheet-internal cellrefs to ldloc instructions. /// </summary> public void AddComputeCells(DependencyGraph dpGraph, IList<FullCellAddr> cellList) { Debug.Assert(dpGraph.outputCell == cellList[cellList.Count - 1]); CGExpr outputExpr; if (cellList.Count == 0 || cellList.Count == 1 && dpGraph.inputCellSet.Contains(cellList.Single())) { // The output cell is also an input cell; load it: outputExpr = new CGCellRef(dpGraph.outputCell, addressToVariable[dpGraph.outputCell]); } else { // First process all non-output cells, and ignore all input cells: foreach (FullCellAddr cellAddr in cellList) { if (cellAddr.Equals(dpGraph.outputCell)) { continue; } HashSet<FullCellAddr> dependents = dpGraph.GetDependents(cellAddr); int minUses = dependents.Count; if (minUses == 1) { FullCellAddr fromFca = dependents.First(); minUses = Math.Max(minUses, GetCount(fromFca, cellAddr)); } // Now if minUses==1 then there is at most one use of the cell at cellAddr, // and no local variable is needed. Otherwise, allocate a local variable: if (minUses > 1) { CGExpr newExpr = CGExpressionBuilder.BuildExpression(cellAddr, addressToVariable); Variable var = new LocalVariable(cellAddr.ToString(), newExpr.Type()); AddComputeCell(cellAddr, new ComputeCell(newExpr, var, cellAddr)); } } // Then process the output cell: outputExpr = CGExpressionBuilder.BuildExpression(dpGraph.outputCell, addressToVariable); } // Add the output cell expression last, without a variable to bind it to; hence the null, // also indicating that (only) the output cell is in tail position: AddComputeCell(dpGraph.outputCell, new ComputeCell(outputExpr, null, dpGraph.outputCell)); }