Expr SpecFuncs(CallExpr ce) { Expr src, ndx; bool forPrev = false, forCell = false; int nMinArgs = 1; switch (ce.funcName) { case "PREVCELL": forCell = true; forPrev = true; break; case "PREV": nMinArgs = 0; forPrev = true; break; case "INDIRECT": forCell = true; break; case nameof(FuncDefs_Xlsx.COLUMN): // avoid COLUMN(args) fixing return(new CallExpr(nameof(FuncDefs_Xlsx.COLUMN), ce.args)); default: return(ce); } if (ce.args.Count < nMinArgs) { return(ce); } Expr arg; string name; if (ce.args.Count == 0) { arg = null; name = FCurrName; } else { arg = ce.args[0]; if (arg.nodeType == ExprType.Reference) { name = ((ReferenceExpr)arg).name; if (IsColumnName(name) || !forPrev && IsFullRelativeCell(CellRange.FromName(name))) { forCell = true; } else { name = OPs.TryAsString(arg, ctxRow) ?? name; } } else { arg = FixRowExpr(arg); name = OPs.TryAsName(arg, ctxRow); } } if (name == null) { var undefs = string.Join(", ", ctxHdr.NamesOfUndefinedValues().Concat(ctxRow.NamesOfUndefinedValues())); throw new Source.Exception($"Constant expected as value of {ce.args[0]}={arg} // ??? {undefs}"); } if (forCell || IsColumnName(name) || !forPrev && IsFullRelativeCell(CellRange.FromName(name))) { if (forPrev) { src = new IndexExpr(PrevValsRef, new ConstExpr(ctxRow.IndexOf(CellValsRef.name))); } else { var re1 = new ReferenceExpr(name); var re2 = FixHdrCellRef(re1); if (re2 != re1) { // ref to header cell return(re2); } else { // ref to row cell src = CellValsRef; } } ndx = new ConstExpr(name); } else { int i = ctxRow.IndexOf(name); if (i < 0 || Generator.Ctx.ctxDepthStep <= i) { throw new Source.Exception($"Value named '{name}' not found in row context"); } src = PrevValsRef; ndx = new ConstExpr(i); } return(new IndexExpr(src, ndx)); }