Exemple #1
0
        public static void CreateFunction(string name, FullCellAddr outputCell, FullCellAddr[] inputCells)
        {
            name = name.ToUpper();
            // If the function exists, with the same input and output cells, keep it.
            // If it is a placeholder, overwrite its applier; if its input and output
            // cells have changed, recreate it (including its SdfInfo record).
            Function oldFunction = Function.Get(name);

            if (oldFunction != null)
            {
                if (!oldFunction.IsPlaceHolder)
                {
                    return;
                }
            }
            // Registering the function before compilation allows it to call itself recursively
            SdfInfo sdfInfo = Register(outputCell, inputCells, name);

            // Console.WriteLine("Compiling {0} as #{1}", name, info.index);
            Update(sdfInfo, CompileSdf(sdfInfo));
            if (oldFunction != null)             // ... and is not a placeholder
            {
                oldFunction.UpdateApplier(sdfInfo.Apply, sdfInfo.IsVolatile);
            }
            else
            {
                new Function(name, sdfInfo.Apply, isVolatile: sdfInfo.IsVolatile);
            }
        }
Exemple #2
0
        // Evaluate cell's expression if necessary and cache its value;
        // also enqueue supported cells for evaluation if we use support graph
        public override Value Eval(Sheet sheet, int col, int row)
        {
            switch (state)
            {
            case CellState.Uptodate:
                break;

            case CellState.Computing:
                FullCellAddr culprit = new FullCellAddr(sheet, col, row);
                String       msg     = String.Format("### CYCLE in cell {0} formula {1}",
                                                     culprit,
                                                     Show(col, row, workbook.format));
                throw new CyclicException(msg, culprit);

            case CellState.Dirty:
            case CellState.Enqueued:
                state = CellState.Computing;
                v     = e.Eval(sheet, col, row);
                state = CellState.Uptodate;
                if (workbook.UseSupportSets)
                {
                    ForEachSupported(EnqueueCellForEvaluation);
                }
                break;
            }
            return(v);
        }
		public static CGExpr BuildExpression(FullCellAddr addr,
											 Dictionary<FullCellAddr, Variable> addressToVariable) {
			Cell cell;
			if (!addr.TryGetCell(out cell)) {
				return new CGTextConst(TextValue.EMPTY);
			}
			else if (cell is NumberCell) {
				return new CGNumberConst(((NumberCell)cell).value);
			}
			else if (cell is TextCell) {
				return new CGTextConst(((TextCell)cell).value);
			}
			else if (cell is QuoteCell) {
				return new CGTextConst(((QuoteCell)cell).value);
			}
			else if (cell is BlankCell) {
				return new CGError("#FUNERR: Blank cell in function");
			}
			else if (cell is Formula) {
				// Translate the expr relative to its containing cell at addr
				CGExpressionBuilder cgBuilder = new CGExpressionBuilder(addressToVariable, addr);
				Expr expr = ((Formula)cell).Expr;
				expr.VisitorCall(cgBuilder);
				return cgBuilder.result;
			}
			else if (cell is ArrayFormula) {
				return new CGError("#FUNERR: Array formula in function");
			}
			else {
				throw new ImpossibleException("BuildExpression: " + cell);
			}
		}
Exemple #4
0
        // Partially evaluate the programList with respect to the given static inputs,
        // producing a new ProgramLines object.
        public ProgramLines PEval(Value[] args, FullCellAddr[] residualInputs)
        {
            PEnv pEnv = new PEnv();

            // Map static input cells to their constant values:
            for (int i = 0; i < args.Length; i++)
            {
                pEnv[inputCells[i]] = CGConst.Make(args[i]);
            }
            ProgramLines residual = new ProgramLines(outputCell, residualInputs);

            // PE-time environment PEnv maps each residual input cell address to the delegate argument:
            for (int i = 0; i < residualInputs.Length; i++)
            {
                FullCellAddr input = residualInputs[i];
                pEnv[input] = new CGCellRef(input, residual.addressToVariable[input]);
            }
            // Process the given function's compute cells in dependency order, output last:
            foreach (ComputeCell ccell in programList)
            {
                ComputeCell rCcell = ccell.PEval(pEnv);
                if (rCcell != null)
                {
                    residual.AddComputeCell(ccell.cellAddr, rCcell);
                }
            }
            residual = residual.PruneZeroUseCells();
            return(residual);
        }
Exemple #5
0
        private bool HasPrecedentHelper(FullCellAddr node, ICollection <FullCellAddr> transitivePrecedents, HashSet <FullCellAddr> visitedCells)
        {
            HashSet <FullCellAddr> precedents;

            if (nodesPrecedents.TryGetValue(node, out precedents))
            {
                foreach (FullCellAddr addr in transitivePrecedents)
                {
                    if (precedents.Contains(addr))
                    {
                        return(true);
                    }
                }
                foreach (FullCellAddr addr in precedents)
                {
                    if (visitedCells.Add(addr))
                    {
                        if (HasPrecedentHelper(addr, transitivePrecedents, visitedCells))
                        {
                            return(true);
                        }
                    }
                }
            }
            return(false);
        }
Exemple #6
0
 public override void DependsOn(FullCellAddr here, Action <FullCellAddr> dependsOn)
 {
     foreach (Expr e in es)
     {
         e.DependsOn(here, dependsOn);
     }
 }
Exemple #7
0
        /// <summary>
        /// Find all transitive precedents, that is, cells
        /// that this cell transitively depends on.
        /// The cell thisFca is within the function sheet being translated.
        /// Cells outside the function sheet are not traced.
        /// </summary>
        /// <param name="thisFca"></param>
        /// <exception cref="CyclicException"></exception>
        private void GetTransitivePrecedents(FullCellAddr thisFca)
        {
            ISet <FullCellAddr> precedents = new HashSet <FullCellAddr>();
            IDepend             node       = getNode(thisFca);

            if (node != null)
            {
                node.DependsOn(thisFca, delegate(FullCellAddr fca) { precedents.Add(fca); });
            }

            // Now precedents is the set of cells directly referred from
            // the Expr in cell thisFca; that is, that cell's direct precedents

            foreach (FullCellAddr addr in precedents)
            {
                // Trace dependencies only from cells on this sheet,
                // and don't trace precedents of input cells
                if (addr.sheet == thisFca.sheet)
                {
                    if (!AddPrecedentDependent(addr, thisFca) && !inputCellSet.Contains(addr))
                    {
                        GetTransitivePrecedents(addr);
                    }
                }
            }
        }
Exemple #8
0
        private bool HasDependentHelper(FullCellAddr node,
                                        ICollection <FullCellAddr> transitiveDependents,
                                        HashSet <FullCellAddr> visitedCells)
        {
            HashSet <FullCellAddr> dependents;

            if (nodesDependents.TryGetValue(node, out dependents))
            {
                foreach (FullCellAddr addr in transitiveDependents)
                {
                    if (dependents.Contains(addr))
                    {
                        return(true);
                    }
                }
                foreach (FullCellAddr addr in dependents)
                {
                    if (visitedCells.Add(addr))                     // returns true only first time
                    {
                        if (HasDependentHelper(addr, transitiveDependents, visitedCells))
                        {
                            return(true);
                        }
                    }
                }
            }
            return(false);
        }
Exemple #9
0
		/// <summary>
		/// Make "precedent" a precedent of "node", and 
		/// make "node" a dependent of "precedent".  
		/// If the required sets of precedents resp. dependents do not exist, 
		/// create them and associate them with "node" resp. "precedent".
		/// </summary>
		/// <exception cref="CyclicException">If a static cycle exists</exception>
		public bool AddPrecedentDependent(FullCellAddr precedent, FullCellAddr node) {
			HashSet<FullCellAddr> precedents;
			if (nodesPrecedents.TryGetValue(node, out precedents)) {
				try {
					precedents.Add(precedent);
				}
				catch (ArgumentException) {
					//Happens if the element already exists: there is a cycle
					throw new CyclicException("Static cycle through cell " + precedent, precedent);
				}
			}
			else {
				precedents = new HashSet<FullCellAddr>();
				precedents.Add(precedent);
				nodesPrecedents.Add(node, precedents);
			}

			HashSet<FullCellAddr> dependents;
			if (nodesDependents.TryGetValue(precedent, out dependents)) {
				if (!dependents.Add(node)) {
					//Happens if the element already exists: there is a cycle
					throw new CyclicException("Static cycle through cell " + node, node);
				}
				else {
					return true;
				}
			}
			else {
				dependents = new HashSet<FullCellAddr>();
				dependents.Add(node);
				nodesDependents.Add(precedent, dependents);
				return false;
			}
		}
Exemple #10
0
        public void ChangeFocus(FullCellAddr fca)
        {
            sheetHolder.SelectTab(fca.sheet.Name);
            SheetTab sheetTab = (SheetTab)sheetHolder.SelectedTab;

            sheetTab.ScrollTo(fca);
        }
Exemple #11
0
        // Register, unregister, update and look up the SDF tables

        /// <summary>
        /// Allocate an index for a new SDF, but do not bind its SdfDelegate
        /// </summary>
        /// <param name="outputCell"></param>
        /// <param name="inputCells"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static SdfInfo Register(FullCellAddr outputCell, FullCellAddr[] inputCells, string name)
        {
            name = name.ToUpper();
            SdfInfo sdfInfo = GetInfo(name);

            if (sdfInfo == null)               // New SDF, register it
            {
                sdfInfo = new SdfInfo(outputCell, inputCells, name, nextIndex++);
                Debug.Assert(sdfInfo.index == nextIndex - 1);
                sdfNameToInfo[name] = sdfInfo;
                if (sdfInfo.index >= sdfDelegates.Length)
                {
                    Debug.Assert(sdfDelegates.Length == sdfInfos.Length);
                    // Reallocate sdfDelegates array
                    Delegate[] newSdfs = new Delegate[2 * sdfDelegates.Length];
                    Array.Copy(sdfDelegates, newSdfs, sdfDelegates.Length);
                    sdfDelegates = newSdfs;
                    // Reallocate sdfInfos array
                    SdfInfo[] newSdfInfos = new SdfInfo[2 * sdfInfos.Length];
                    Array.Copy(sdfInfos, newSdfInfos, sdfInfos.Length);
                    sdfInfos = newSdfInfos;
                }
                sdfInfos[sdfInfo.index] = sdfInfo;
                // Update SDF function listbox if created and visible
                SdfForm sdfForm = System.Windows.Forms.Application.OpenForms["sdf"] as SdfForm;
                if (sdfForm != null && sdfForm.Visible)
                {
                    sdfForm.PopulateFunctionListBox(false);
                    sdfForm.PopulateFunctionListBox(name);
                    sdfForm.Invalidate();
                }
            }
            return(sdfInfo);
        }
Exemple #12
0
		public CGNormalCellRef(FullCellAddr cellAddr) {
			if (cellAddr.sheet.IsFunctionSheet) {
				this.index = -1; // Illegal cell reference
			}
			else {
				this.index = valueTable.GetIndex(cellAddr);
			}
		}
Exemple #13
0
 public virtual void DependsOn(FullCellAddr here, Action <FullCellAddr> dependsOn)
 {
     expr.DependsOn(here, dependsOn);
     if (evalCond != null)
     {
         evalCond.DependsOn(here, dependsOn);
     }
 }
Exemple #14
0
 public void AddComputeCell(FullCellAddr fca, ComputeCell ccell)
 {
     programList.Add(ccell);
     fcaToComputeCell.Add(fca, ccell);
     if (ccell.var != null)
     {
         addressToVariable.Add(fca, ccell.var);
     }
 }
Exemple #15
0
 // Set or remove (message=null) cell error mark
 public void SetCyclicError(String message)
 {
     if (Workbook.Cyclic != null)
     {
         FullCellAddr culprit = Workbook.Cyclic.culprit;
         sheetHolder.SelectTab(culprit.sheet.Name);
         SelectedSheet.SetCellErrorText(culprit.ca, message);
     }
 }
Exemple #16
0
		public DependencyGraph(FullCellAddr outputCell, FullCellAddr[] inputCells, Func<FullCellAddr, IDepend> getNode) {
			this.outputCell = outputCell;
			this.nodesDependents = new Dictionary<FullCellAddr, HashSet<FullCellAddr>>();
			this.nodesPrecedents = new Dictionary<FullCellAddr, HashSet<FullCellAddr>>();
			this.inputCells = inputCells;
			this.inputCellSet = new HashSet<FullCellAddr>();
			this.inputCellSet.UnionWith(inputCells);
			this.getNode = getNode;
			CollectPrecedents();
		}
Exemple #17
0
		private Variable numberVar; // If non-null, unwrap to this Number variable
		// If var==null then numberVar==null

		public ComputeCell(CGExpr expr, Variable var, FullCellAddr cellAddr) {
			this.expr = expr;
			this.var = var;
			// The output cell's expression is in tail position:
			if (var == null) {
				this.expr.NoteTailPosition();
			}
			this.cellAddr = cellAddr;
			this.numberVar = null;
		}
Exemple #18
0
		internal SdfInfo(FullCellAddr outputCell,
						 FullCellAddr[] inputCells,
						 string name,
						 int index) {
			this.outputCell = outputCell;
			this.inputCells = inputCells;
			this.name = name.ToUpper();
			this.index = index;
			this.arity = inputCells.Length;
		}
        private void AddCellToFunction(String info, FullCellAddr addr)
        {
            HashSet <String> names;

            if (!addressToFunctionList.TryGetValue(addr, out names))
            {
                names = new HashSet <String>();
                addressToFunctionList[addr] = names;
            }
            names.Add(info);
        }
Exemple #20
0
 internal SdfInfo(FullCellAddr outputCell,
                  FullCellAddr[] inputCells,
                  string name,
                  int index)
 {
     this.outputCell = outputCell;
     this.inputCells = inputCells;
     this.name       = name.ToUpper();
     this.index      = index;
     this.arity      = inputCells.Length;
 }
Exemple #21
0
 public DependencyGraph(FullCellAddr outputCell, FullCellAddr[] inputCells, Func <FullCellAddr, IDepend> getNode)
 {
     this.outputCell      = outputCell;
     this.nodesDependents = new Dictionary <FullCellAddr, HashSet <FullCellAddr> >();
     this.nodesPrecedents = new Dictionary <FullCellAddr, HashSet <FullCellAddr> >();
     this.inputCells      = inputCells;
     this.inputCellSet    = new HashSet <FullCellAddr>();
     this.inputCellSet.UnionWith(inputCells);
     this.getNode = getNode;
     CollectPrecedents();
 }
Exemple #22
0
 public CGNormalCellRef(FullCellAddr cellAddr)
 {
     if (cellAddr.sheet.IsFunctionSheet)
     {
         this.index = -1;                 // Illegal cell reference
     }
     else
     {
         this.index = valueTable.GetIndex(cellAddr);
     }
 }
Exemple #23
0
		public ProgramLines(FullCellAddr outputCell, FullCellAddr[] inputCells) {
			this.outputCell = outputCell;
			this.inputCells = inputCells;
			programList = new List<ComputeCell>();
			fcaToComputeCell = new Dictionary<FullCellAddr, ComputeCell>();
			unwrapInputCells = new List<UnwrapInputCell>();
			addressToVariable = new Dictionary<FullCellAddr, Variable>();
			for (short i = 0; i < inputCells.Length; i++) {
				FullCellAddr addr = inputCells[i];
				addressToVariable.Add(addr, new LocalArgument(addr.ToString(), Typ.Value, i));
			}
		}
Exemple #24
0
        private Variable numberVar;      // If non-null, unwrap to this Number variable
        // If var==null then numberVar==null

        public ComputeCell(CGExpr expr, Variable var, FullCellAddr cellAddr)
        {
            this.expr = expr;
            this.var  = var;
            // The output cell's expression is in tail position:
            if (var == null)
            {
                this.expr.NoteTailPosition();
            }
            this.cellAddr  = cellAddr;
            this.numberVar = null;
        }
Exemple #25
0
 public ProgramLines(FullCellAddr outputCell, FullCellAddr[] inputCells)
 {
     this.outputCell   = outputCell;
     this.inputCells   = inputCells;
     programList       = new List <ComputeCell>();
     fcaToComputeCell  = new Dictionary <FullCellAddr, ComputeCell>();
     unwrapInputCells  = new List <UnwrapInputCell>();
     addressToVariable = new Dictionary <FullCellAddr, Variable>();
     for (short i = 0; i < inputCells.Length; i++)
     {
         FullCellAddr addr = inputCells[i];
         addressToVariable.Add(addr, new LocalArgument(addr.ToString(), Typ.Value, i));
     }
 }
Exemple #26
0
        public FullCellAddr[] ResidualInputs(FunctionValue fv)
        {
            // The residual input cells are those that have input value NA
            FullCellAddr[] residualInputs = new FullCellAddr[fv.Arity];
            int            j = 0;

            for (int i = 0; i < fv.args.Length; i++)
            {
                if (fv.args[i] == ErrorValue.naError)
                {
                    residualInputs[j++] = inputCells[i];
                }
            }
            return(residualInputs);
        }
Exemple #27
0
        // Register SDFs (and maybe later: convert DELAY calls to DelayCell).
        private void RegisterSdfs(Sheet sheet, int col, int row)
        {
            Cell cell = sheet[col, row];

            if (cell == null || !(cell is Formula))
            {
                return;
            }
            Expr e = (cell as Formula).Expr;

            if (!(e is FunCall))
            {
                return;
            }
            FunCall funCall = e as FunCall;

            Expr[] es = funCall.es;
            switch (funCall.function.name)
            {
            case "DEFINE":
                if (es.Length >= 2 && es[0] is TextConst && es[1] is CellRef)
                {
                    String         sdfName    = ((TextConst)es[0]).value.value;
                    FullCellAddr   outputCell = ((CellRef)es[1]).GetAbsoluteAddr(sheet, col, row);
                    FullCellAddr[] inputCells = new FullCellAddr[es.Length - 2];
                    bool           ok         = true;
                    for (int i = 2; ok && i < es.Length; i++)
                    {
                        CellRef inputCellRef = es[i] as CellRef;
                        ok = inputCellRef != null;
                        if (ok)
                        {
                            inputCells[i - 2] = inputCellRef.GetAbsoluteAddr(sheet, col, row);
                        }
                    }
                    if (ok)
                    {
                        Funcalc.SdfManager.Register(outputCell, inputCells, sdfName);
                    }
                }
                break;

            case "DELAY":
                break;
            }
        }
Exemple #28
0
        /// <summary>
        /// Count number of references from cell at fromFca to cell address toFca
        /// </summary>
        private static int GetCount(FullCellAddr fromFca, FullCellAddr toFca)
        {
            int  count = 0;
            Cell fromCell;

            if (fromFca.TryGetCell(out fromCell))
            {
                fromCell.DependsOn(fromFca,
                                   delegate(FullCellAddr fca) {
                    if (toFca.Equals(fca))
                    {
                        count++;
                    }
                });
            }
            return(count);
        }
Exemple #29
0
 public static void CreateFunction(string name, FullCellAddr outputCell, FullCellAddr[] inputCells) {
   name = name.ToUpper();
   // If the function exists, with the same input and output cells, keep it.
   // If it is a placeholder, overwrite its applier; if its input and output
   // cells have changed, recreate it (including its SdfInfo record).
   Function oldFunction = Function.Get(name);
   if (oldFunction != null) 
     if (!oldFunction.IsPlaceHolder)
       return;
   // Registering the function before compilation allows it to call itself recursively
   SdfInfo sdfInfo = Register(outputCell, inputCells, name);
   // Console.WriteLine("Compiling {0} as #{1}", name, info.index);
   Update(sdfInfo, CompileSdf(sdfInfo));
   if (oldFunction != null) // ... and is not a placeholder
     oldFunction.UpdateApplier(sdfInfo.Apply, sdfInfo.IsVolatile);
   else
     new Function(name, sdfInfo.Apply, isVolatile: sdfInfo.IsVolatile);
 }
Exemple #30
0
        /// <summary>
        /// Make "precedent" a precedent of "node", and
        /// make "node" a dependent of "precedent".
        /// If the required sets of precedents resp. dependents do not exist,
        /// create them and associate them with "node" resp. "precedent".
        /// </summary>
        /// <exception cref="CyclicException">If a static cycle exists</exception>
        public bool AddPrecedentDependent(FullCellAddr precedent, FullCellAddr node)
        {
            HashSet <FullCellAddr> precedents;

            if (nodesPrecedents.TryGetValue(node, out precedents))
            {
                try {
                    precedents.Add(precedent);
                }
                catch (ArgumentException) {
                    //Happens if the element already exists: there is a cycle
                    throw new CyclicException("Static cycle through cell " + precedent, precedent);
                }
            }
            else
            {
                precedents = new HashSet <FullCellAddr>();
                precedents.Add(precedent);
                nodesPrecedents.Add(node, precedents);
            }

            HashSet <FullCellAddr> dependents;

            if (nodesDependents.TryGetValue(precedent, out dependents))
            {
                if (!dependents.Add(node))
                {
                    //Happens if the element already exists: there is a cycle
                    throw new CyclicException("Static cycle through cell " + node, node);
                }
                else
                {
                    return(true);
                }
            }
            else
            {
                dependents = new HashSet <FullCellAddr>();
                dependents.Add(node);
                nodesDependents.Add(precedent, dependents);
                return(false);
            }
        }
Exemple #31
0
        public void CallVisitor(CellRef cellRef)
        {
            FullCellAddr cellAddr = cellRef.GetAbsoluteAddr(thisFca);

            if (cellAddr.sheet != thisFca.sheet)
            {
                // Reference to other sheet, hopefully a normal sheet
                result = new CGNormalCellRef(cellAddr);
            }
            else if (this.addressToVariable.ContainsKey(cellAddr))
            {
                // Reference to a cell that has already been computed in a local variable
                result = new CGCellRef(cellAddr, this.addressToVariable[cellAddr]);
            }
            else             // Inline the cell's formula's expression
            {
                result = BuildExpression(cellAddr, addressToVariable);
            }
        }
Exemple #32
0
        public static CGExpr BuildExpression(FullCellAddr addr,
                                             Dictionary <FullCellAddr, Variable> addressToVariable)
        {
            Cell cell;

            if (!addr.TryGetCell(out cell))
            {
                return(new CGTextConst(TextValue.EMPTY));
            }
            else if (cell is NumberCell)
            {
                return(new CGNumberConst(((NumberCell)cell).value));
            }
            else if (cell is TextCell)
            {
                return(new CGTextConst(((TextCell)cell).value));
            }
            else if (cell is QuoteCell)
            {
                return(new CGTextConst(((QuoteCell)cell).value));
            }
            else if (cell is BlankCell)
            {
                return(new CGError("#FUNERR: Blank cell in function"));
            }
            else if (cell is Formula)
            {
                // Translate the expr relative to its containing cell at addr
                CGExpressionBuilder cgBuilder = new CGExpressionBuilder(addressToVariable, addr);
                Expr expr = ((Formula)cell).Expr;
                expr.VisitorCall(cgBuilder);
                return(cgBuilder.result);
            }
            else if (cell is ArrayFormula)
            {
                return(new CGError("#FUNERR: Array formula in function"));
            }
            else
            {
                throw new ImpossibleException("BuildExpression: " + cell);
            }
        }
Exemple #33
0
        /// <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));
        }
Exemple #34
0
		// Evaluate cell's expression if necessary and cache its value; 
		// also enqueue supported cells for evaluation if we use support graph
		public override Value Eval(Sheet sheet, int col, int row) {
			switch (state) {
				case CellState.Uptodate:
					break;
				case CellState.Computing:
					FullCellAddr culprit = new FullCellAddr(sheet, col, row);
					String msg = String.Format("### CYCLE in cell {0} formula {1}",
											   culprit,
											   Show(col, row, workbook.format));
					throw new CyclicException(msg, culprit);
				case CellState.Dirty:
				case CellState.Enqueued:
					state = CellState.Computing;
					v = e.Eval(sheet, col, row);
					state = CellState.Uptodate;
					if (workbook.UseSupportSets) {
						ForEachSupported(EnqueueCellForEvaluation);
					}
					break;
			}
			return v;
		}
Exemple #35
0
        /// <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);
                }
            }
        }
Exemple #36
0
        private void AddNode(HashList <FullCellAddr> sorted, FullCellAddr node)
        {
            HashSet <FullCellAddr> precedents;

            if (GetPrecedents(node, out precedents))
            {
                Cell cell;
                foreach (FullCellAddr precedent in precedents)
                {
                    // By including only non-input Formula and ArrayFormula cells, we avoid that
                    // constant cells get stored in local variables.  The result will not contain
                    // constants cells (and will contain an input cell only if it is also the
                    // output cell), so must the raw graph to find all cells belonging to an SDF.
                    if (!sorted.Contains(precedent) &&
                        precedent.TryGetCell(out cell) &&
                        (cell is Formula || cell is ArrayFormula) &&
                        !inputCellSet.Contains(precedent))
                    {
                        AddNode(sorted, precedent);
                    }
                }
            }
            sorted.Add(node);             // Last in HashList
        }
Exemple #37
0
		private bool HasPrecedentHelper(FullCellAddr node, ICollection<FullCellAddr> transitivePrecedents, HashSet<FullCellAddr> visitedCells) {
			HashSet<FullCellAddr> precedents;
			if (nodesPrecedents.TryGetValue(node, out precedents)) {
				foreach (FullCellAddr addr in transitivePrecedents) {
					if (precedents.Contains(addr)) {
						return true;
					}
				}
				foreach (FullCellAddr addr in precedents) {
					if (visitedCells.Add(addr)) {
						if (HasPrecedentHelper(addr, transitivePrecedents, visitedCells)) {
							return true;
						}
					}
				}
			}
			return false;
		}
Exemple #38
0
		/// <summary>
		/// Tests whether possiblePrecedents contains any cell that node 
		/// transitively depends on. 
		/// </summary>
		/// <param name="node"></param>
		/// <param name="transitivePrecedents"></param>
		/// <returns></returns>
		public bool HasPrecedent(FullCellAddr node, ICollection<FullCellAddr> transitivePrecedents) {
			HashSet<FullCellAddr> visitedCells = new HashSet<FullCellAddr>();
			return HasPrecedentHelper(node, transitivePrecedents, visitedCells);
		}
Exemple #39
0
		private bool HasDependentHelper(FullCellAddr node,
										ICollection<FullCellAddr> transitiveDependents,
										HashSet<FullCellAddr> visitedCells) {
			HashSet<FullCellAddr> dependents;
			if (nodesDependents.TryGetValue(node, out dependents)) {
				foreach (FullCellAddr addr in transitiveDependents) {
					if (dependents.Contains(addr)) {
						return true;
					}
				}
				foreach (FullCellAddr addr in dependents) {
					if (visitedCells.Add(addr)) // returns true only first time
					{
						if (HasDependentHelper(addr, transitiveDependents, visitedCells)) {
							return true;
						}
					}
				}
			}
			return false;
		}
Exemple #40
0
 public void ChangeFocus(FullCellAddr fca)
 {
     sheetHolder.SelectTab(fca.sheet.Name);
       SheetTab sheetTab = (SheetTab)sheetHolder.SelectedTab;
       sheetTab.ScrollTo(fca);
 }
Exemple #41
0
		// Call dependsOn(fca) on all cells fca referred from expression, with multiplicity.
		// Cannot be implemented in terms of VisitRefs, which visits only once.
		public abstract void DependsOn(FullCellAddr here, Action<FullCellAddr> dependsOn);
Exemple #42
0
		private void AddNode(HashList<FullCellAddr> sorted, FullCellAddr node) {
			HashSet<FullCellAddr> precedents;
			if (GetPrecedents(node, out precedents)) {
				Cell cell;
				foreach (FullCellAddr precedent in precedents) {
					// By including only non-input Formula and ArrayFormula cells, we avoid that 
					// constant cells get stored in local variables.  The result will not contain 
					// constants cells (and will contain an input cell only if it is also the 
					// output cell), so must the raw graph to find all cells belonging to an SDF.
					if (!sorted.Contains(precedent)
						&& precedent.TryGetCell(out cell)
						&& (cell is Formula || cell is ArrayFormula)
						&& !inputCellSet.Contains(precedent)) {
						AddNode(sorted, precedent);
					}
				}
			}
			sorted.Add(node); // Last in HashList
		}
Exemple #43
0
		public HashSet<FullCellAddr> GetDependents(FullCellAddr fca) { return nodesDependents[fca]; }
Exemple #44
0
		public override void DependsOn(FullCellAddr here, Action<FullCellAddr> dependsOn) {
			foreach (CGExpr e in es) {
				e.DependsOn(here, dependsOn);
			}
		}
Exemple #45
0
		public CyclicException(String msg, FullCellAddr culprit) : base(msg) { this.culprit = culprit; }
Exemple #46
0
		public virtual void DependsOn(FullCellAddr here, Action<FullCellAddr> dependsOn) {
			expr.DependsOn(here, dependsOn);
			if (evalCond != null) {
				evalCond.DependsOn(here, dependsOn);
			}
		}
Exemple #47
0
		internal bool GetPrecedents(FullCellAddr node, out HashSet<FullCellAddr> precedents) { return nodesPrecedents.TryGetValue(node, out precedents); }
Exemple #48
0
 public abstract void DependsOn(FullCellAddr here, Action <FullCellAddr> dependsOn);
Exemple #49
0
		/// <summary>
		/// Find all transitive precedents, that is, cells 
		/// that this cell transitively depends on.
		/// The cell thisFca is within the function sheet being translated.  
		/// Cells outside the function sheet are not traced.
		/// </summary>
		/// <param name="thisFca"></param>
		/// <exception cref="CyclicException"></exception>
		private void GetTransitivePrecedents(FullCellAddr thisFca) {
			ISet<FullCellAddr> precedents = new HashSet<FullCellAddr>();
			IDepend node = getNode(thisFca);
			if (node != null) {
				node.DependsOn(thisFca, delegate(FullCellAddr fca) { precedents.Add(fca); });
			}

			// Now precedents is the set of cells directly referred from 
			// the Expr in cell thisFca; that is, that cell's direct precedents

			foreach (FullCellAddr addr in precedents) {
				// Trace dependencies only from cells on this sheet, 
				// and don't trace precedents of input cells
				if (addr.sheet == thisFca.sheet) {
					if (!AddPrecedentDependent(addr, thisFca) && !inputCellSet.Contains(addr)) {
						GetTransitivePrecedents(addr);
					}
				}
			}
		}
Exemple #50
0
 public void ScrollTo(FullCellAddr fca)
 {
     dgv.FirstDisplayedScrollingRowIndex = Math.Max(0, fca.ca.row - 1);
 }
Exemple #51
0
		public override void DependsOn(FullCellAddr here, Action<FullCellAddr> dependsOn) {
			// We do not track dependencies on cells on ordinary sheets
		}
Exemple #52
0
 // Register SDFs (and maybe later: convert DELAY calls to DelayCell).
 private void RegisterSdfs(Sheet sheet, int col, int row)
 {
     Cell cell = sheet[col, row];
       if (cell == null || !(cell is Formula))
     return;
       Expr e = (cell as Formula).Expr;
       if (!(e is FunCall))
     return;
       FunCall funCall = e as FunCall;
       Expr[] es = funCall.es;
       switch (funCall.function.name) {
     case "DEFINE":
       if (es.Length >= 2 && es[0] is TextConst && es[1] is CellRef) {
     String sdfName = (es[0] as TextConst).value.value;
     FullCellAddr outputCell = (es[1] as CellRef).GetAbsoluteAddr(sheet, col, row);
     FullCellAddr[] inputCells = new FullCellAddr[es.Length - 2];
     bool ok = true;
     for (int i = 2; ok && i < es.Length; i++) {
       CellRef inputCellRef = es[i] as CellRef;
       ok = inputCellRef != null;
       if (ok)
         inputCells[i - 2] = inputCellRef.GetAbsoluteAddr(sheet, col, row);
     }
     if (ok)
       Funcalc.SdfManager.Register(outputCell, inputCells, sdfName);
       }
       break;
     case "DELAY":
       break;
     default:
       /* do nothing */
       break;
       }
 }
Exemple #53
0
 public void ScrollTo(FullCellAddr fca)
 {
     dgv.FirstDisplayedScrollingRowIndex = Math.Max(0, fca.ca.row - 1);
 }
		private CGExpr result; // The result of the compilation is left here

		private CGExpressionBuilder(Dictionary<FullCellAddr, Variable> addressToVariable,
									FullCellAddr addr) {
			thisFca = addr;
			this.addressToVariable = addressToVariable;
		}
Exemple #55
0
 public void ChangeCellBackgroundColor(FullCellAddr fca, Color c)
 {
     dgv[fca.ca.col, fca.ca.row].Style.BackColor = c;
 }
Exemple #56
0
		public override void DependsOn(FullCellAddr here, Action<FullCellAddr> dependsOn) { e.DependsOn(here, dependsOn); }
Exemple #57
0
 public void ChangeCellBackgroundColor(FullCellAddr fca, Color c)
 {
     sheetHolder.SelectTab(fca.sheet.Name);
       SelectedSheet.ChangeCellBackgroundColor(fca, c);
 }
Exemple #58
0
		// Create SDFs 
		private void CreateSdfs(Sheet sheet, int col, int row) {
			Cell cell = sheet[col, row];
			if (cell == null || !(cell is Formula)) {
				return;
			}
			Expr e = (cell as Formula).Expr;
			if (!(e is FunCall)) {
				return;
			}
			FunCall funCall = e as FunCall;
			Expr[] es = funCall.es;
			switch (funCall.function.name) {
				case "DEFINE":
					if (es.Length >= 2 && es[0] is TextConst && es[1] is CellRef) {
						String sdfName = ((TextConst)es[0]).value.value;
						FullCellAddr outputCell = ((CellRef)es[1]).GetAbsoluteAddr(sheet, col, row);
						FullCellAddr[] inputCells = new FullCellAddr[es.Length - 2];
						bool ok = true;
						for (int i = 2; ok && i < es.Length; i++) {
							CellRef inputCellRef = es[i] as CellRef;
							ok = inputCellRef != null;
							if (ok) {
								inputCells[i - 2] = inputCellRef.GetAbsoluteAddr(sheet, col, row);
							}
						}
						if (ok) {
							Funcalc.SdfManager.CreateFunction(sdfName, outputCell, inputCells);
						}
					}
					break;
			}
		}
Exemple #59
0
 public override void DependsOn(FullCellAddr here, Action <FullCellAddr> dependsOn)
 {
 }
Exemple #60
0
		public override void DependsOn(FullCellAddr here, Action<FullCellAddr> dependsOn) {
			// It seems that this could uselessly be called on every cell 
			// that shares the formula, but this will not happen on function sheets
			caf.formula.DependsOn(here, dependsOn);
		}