public override Expr Move(int deltaCol, int deltaRow) { Expr[] newEs = new Expr[es.Length]; for (int i = 0; i < es.Length; i++) { newEs[i] = es[i].Move(deltaCol, deltaRow); } return new FunCall(function, newEs); }
private Value v; // Up to date if state==Uptodate public Formula(Workbook workbook, Expr e) { Debug.Assert(workbook != null); Debug.Assert(e != null); this.workbook = workbook; this.e = e; this.state = CellState.Uptodate; }
public static Formula Make(Workbook workbook, Expr e) { if (e == null) { return null; } else { return new Formula(workbook, e); } }
// Can be copied with sharing if arguments can public override Expr CopyTo(int col, int row) { bool same = true; Expr[] newEs = new Expr[es.Length]; for (int i = 0; i < es.Length; i++) { newEs[i] = es[i].CopyTo(col, row); same &= Object.ReferenceEquals(newEs[i], es[i]); } return same ? this : new FunCall(function, newEs); }
public override CGExpr PEval(PEnv pEnv, bool hasDynamicControl) { CGExpr[] res = PEvalArgs(pEnv, hasDynamicControl); // If all args are constant then evaluate else residualize: if (AllConstant(res)) { Expr[] es = new Expr[res.Length]; for (int i = 0; i < res.Length; i++) { es[i] = Const.Make((res[i] as CGConst).Value); } // Use the interpretive implementation's applier on a fake sheet // and fake cell coordinates, but constant argument expressions: return CGConst.Make(applier(null, es, -1, -1)); } else { return Residualize(res); } }
public static Expr Make(String name, Expr[] es) { Function function = Function.Get(name); if (function == null) { function = Function.MakeUnknown(name); } for (int i = 0; i < es.Length; i++) { if (es[i] == null) { es[i] = new Error("#SYNTAX"); } } if (name == "SPECIALIZE" && es.Length > 1) { return new FunCall("SPECIALIZE", Make("CLOSURE", es)); } else { return new FunCall(function, es); } }
public override Adjusted<Expr> InsertRowCols(Sheet modSheet, bool thisSheet, int R, int N, int r, bool doRows) { Expr[] newEs = new Expr[es.Length]; int upper = int.MaxValue; bool same = true; for (int i = 0; i < es.Length; i++) { Adjusted<Expr> ae = es[i].InsertRowCols(modSheet, thisSheet, R, N, r, doRows); upper = Math.Min(upper, ae.upper); same = same && ae.same; newEs[i] = ae.e; } return new Adjusted<Expr>(new FunCall(function, newEs), upper, same); }
private void Exprs1(out Expr[] es) { Expr e1, e2; List<Expr> elist = new List<Expr>(); Expr(out e1); elist.Add(e1); while (la.kind == 30 || la.kind == 31) { if (la.kind == 30) { Get(); } else { Get(); } Expr(out e2); elist.Add(e2); } es = elist.ToArray(); }
private void Application(out Expr e) { String s; Expr[] es; e = null; Name(out s); Expect(27); if (la.kind == 28) { Get(); e = FunCall.Make(s.ToUpper(), new Expr[0]); } else if (StartOf(4)) { Exprs1(out es); Expect(28); e = FunCall.Make(s.ToUpper(), es); } else { SynErr(39); } }
private void PowFactor(out Expr e) { Expr e2; Factor(out e); while (la.kind == 29) { Get(); Factor(out e2); e = FunCall.Make("^", new Expr[] {e, e2}); } }
private void Term(out Expr e) { Expr e2; String op; PowFactor(out e); while (la.kind == 32 || la.kind == 33) { MulOp(out op); PowFactor(out e2); e = FunCall.Make(op, new Expr[] {e, e2}); } }
private void Factor(out Expr e) { RARef r1, r2; Sheet s1 = null; double d; bool sheetError = false; e = null; switch (la.kind) { case 1: { Application(out e); break; } case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: { if (StartOf(2)) {} else { Get(); s1 = workbook[t.val.Substring(0, t.val.Length - 1)]; if (s1 == null) { sheetError = true; } } Raref(out r1); if (StartOf(3)) { if (sheetError) { e = new Error(ErrorValue.refError); } else { e = new CellRef(s1, r1); } } else if (la.kind == 26) { Get(); Raref(out r2); if (sheetError) { e = new Error(ErrorValue.refError); } else { e = new CellArea(s1, r1, r2); } } else { SynErr(37); } break; } case 2: { Number(out d); e = new NumberConst(d); break; } case 18: { Get(); Factor(out e); if (e is NumberConst) { e = new NumberConst(-((NumberConst)e).value.value); } else { e = FunCall.Make("NEG", new Expr[] {e}); } break; } case 15: { Get(); e = new TextConst(t.val.Substring(1, t.val.Length - 2)); break; } case 27: { Get(); Expr(out e); Expect(28); break; } default: SynErr(38); break; } }
private void LogicalTerm(out Expr e) { Expr e2; String op; e = null; Term(out e); while (la.kind == 17 || la.kind == 18 || la.kind == 19) { AddOp(out op); Term(out e2); e = FunCall.Make(op, new Expr[] {e, e2}); } }
// ----- End of SDF-callable built-in functions ----- public bool IsVolatile(Expr[] es) { // A partial application is volatile if the underlying function is if (name == "CLOSURE") { if (es.Length > 0 && es[0] is TextConst) { String sdfName = (es[0] as TextConst).value.value; SdfInfo sdfInfo = SdfManager.GetInfo(sdfName); return sdfInfo != null && sdfInfo.IsVolatile; } else { return false; } } else { return isVolatile; } }
private static Value Closure(Sheet sheet, Expr[] es, int col, int row) { // First argument may be a (constant) function name or a FunctionValue if (es.Length < 1) { return ErrorValue.argCountError; } int argCount = es.Length - 1; Value[] arguments = new Value[argCount]; for (int i = 1; i < es.Length; i++) { Value vi = es[i].Eval(sheet, col, row); if (vi == null) { return ErrorValue.argTypeError; } arguments[i - 1] = vi; } if (es[0] is TextConst) { String name = (es[0] as TextConst).value.value; SdfInfo sdfInfo = SdfManager.GetInfo(name); if (sdfInfo == null) { return ErrorValue.nameError; } if (argCount != 0 && argCount != sdfInfo.arity) { return ErrorValue.argCountError; } return new FunctionValue(sdfInfo, arguments); } else { Value v0 = es[0].Eval(sheet, col, row); if (v0 is FunctionValue) // Further application of a partial application { return (v0 as FunctionValue).FurtherApply(arguments); } else if (v0 is ErrorValue) { return v0; } else { return ErrorValue.argTypeError; } } }
// Auxiliary for EXTERN and EXTERNVOLATILE private static Value CallExtern(Sheet sheet, Expr[] es, int col, int row) { if (es.Length < 1) { return ErrorValue.argCountError; } TextConst nameAndSignatureConst = es[0] as TextConst; if (nameAndSignatureConst == null) { return ErrorValue.argTypeError; } try { // This retrieves the method from cache, or creates it: ExternalFunction ef = ExternalFunction.Make(nameAndSignatureConst.value.value); Value[] values = new Value[es.Length - 1]; for (int i = 0; i < values.Length; i++) { values[i] = es[i + 1].Eval(sheet, col, row); } return ef.Call(values); } catch (TargetInvocationException exn) // From external method { return ErrorValue.Make(exn.InnerException.Message); } catch (Exception exn) // Covers a multitude of sins { return ErrorValue.Make("#EXTERN: " + exn.Message); } }
private FunCall(Function function, Expr[] es) { // Assert: function != null, all es[i] != null this.function = function; this.es = es; }
public Value Apply(Sheet sheet, Expr[] es, int col, int row) { // Arity is checked in the SdfInfo.CallN methods switch (es.Length) { case 0: return Call0(); case 1: return Call1(es[0].Eval(sheet, col, row)); case 2: return Call2(es[0].Eval(sheet, col, row), es[1].Eval(sheet, col, row)); case 3: return Call3(es[0].Eval(sheet, col, row), es[1].Eval(sheet, col, row), es[2].Eval(sheet, col, row)); case 4: return Call4(es[0].Eval(sheet, col, row), es[1].Eval(sheet, col, row), es[2].Eval(sheet, col, row), es[3].Eval(sheet, col, row)); case 5: return Call5(es[0].Eval(sheet, col, row), es[1].Eval(sheet, col, row), es[2].Eval(sheet, col, row), es[3].Eval(sheet, col, row), es[4].Eval(sheet, col, row)); case 6: return Call6(es[0].Eval(sheet, col, row), es[1].Eval(sheet, col, row), es[2].Eval(sheet, col, row), es[3].Eval(sheet, col, row), es[4].Eval(sheet, col, row), es[5].Eval(sheet, col, row)); case 7: return Call7(es[0].Eval(sheet, col, row), es[1].Eval(sheet, col, row), es[2].Eval(sheet, col, row), es[3].Eval(sheet, col, row), es[4].Eval(sheet, col, row), es[5].Eval(sheet, col, row), es[6].Eval(sheet, col, row)); case 8: return Call8(es[0].Eval(sheet, col, row), es[1].Eval(sheet, col, row), es[2].Eval(sheet, col, row), es[3].Eval(sheet, col, row), es[4].Eval(sheet, col, row), es[5].Eval(sheet, col, row), es[6].Eval(sheet, col, row), es[7].Eval(sheet, col, row)); case 9: return Call9(es[0].Eval(sheet, col, row), es[1].Eval(sheet, col, row), es[2].Eval(sheet, col, row), es[3].Eval(sheet, col, row), es[4].Eval(sheet, col, row), es[5].Eval(sheet, col, row), es[6].Eval(sheet, col, row), es[7].Eval(sheet, col, row), es[8].Eval(sheet, col, row)); default: return ErrorValue.Make("#FUNERR: Too many arguments"); } }
private void Expr(out Expr e) { Expr e2; String op; e = null; LogicalTerm(out e); while (StartOf(1)) { LogicalOp(out op); LogicalTerm(out e2); e = FunCall.Make(op, new Expr[] {e, e2}); } }
public override void InsertRowCols(Dictionary<Expr, Adjusted<Expr>> adjusted, Sheet modSheet, bool thisSheet, int R, int N, int r, bool doRows) { Adjusted<Expr> ae; if (adjusted.ContainsKey(e) && r < adjusted[e].upper) { // There is a valid cached adjusted expression ae = adjusted[e]; } else { // Compute a new adjusted expression and insert into the cache ae = e.InsertRowCols(modSheet, thisSheet, R, N, r, doRows); Console.WriteLine("Making new adjusted at rowcol " + r + "; upper = " + ae.upper); if (ae.same) { // For better sharing, reuse unadjusted e if same ae = new Adjusted<Expr>(e, ae.upper, ae.same); Console.WriteLine("Reusing expression"); } adjusted[e] = ae; } Debug.Assert(r < ae.upper, "Formula.InsertRowCols"); e = ae.e; }
// Evaluate expression array private static Value[] Eval(Expr[] es, Sheet sheet, int col, int row) { Value[] vs = new Value[es.Length]; for (int i = 0; i < es.Length; i++) { vs[i] = es[i].Eval(sheet, col, row); } return vs; }