public static object GetConstant(this Generator.Ctx ctx, string valueName) { int i = ctx.IndexOf(valueName); var val = (i < 0) ? null : ctx[i]; if (val == null) { return(null); } var expr = val as Expr; if (expr != null) { val = Generator.Generate(expr, ctx); } if (OPs.KindOf(val) == ValueKind.Const) { return(val); } else if (expr != null) { return(ctx.Error(string.Format("Constant expected as value of '{0}' // {1}", valueName, expr))); } else { return(ctx.Error(string.Format("Constant expected as value of '{0}'", valueName))); } }
static Expr AggImpl(CallExpr ce, Generator.Ctx ctx) { var valsExpr = ce.args[0]; Expr keysExpr; if (ce.args.Count > 1) { keysExpr = ce.args[1]; } else { keysExpr = new ReferenceExpr(sWithKey); } var refAkk = new ReferenceExpr(string.Format("{0}:{1}:{2}", sAkk, valsExpr, keysExpr)); int iAkk = ctx.IndexOf(refAkk.name); Expr resultExpr; if (iAkk >= 0) { resultExpr = refAkk; } else { resultExpr = new CallExpr(FuncDefs_Solver.SolverWeightedSumsAdd, refAkk, new CallExpr(FuncDefs_Solver.SolverWeightedSumsNew, new ReferenceExpr(sFactory), valsExpr, keysExpr)); } return(resultExpr); }
public Task LoadData(AsyncExprCtx rootAec, Expr loadingExpr, CancellationToken ct) { int i = aggCtx.IndexOf(sFactory); if (i >= 0) { var f = (WeightedSums.Factory)aggCtx[i]; foreach (var n2i in aggCtx.name2ndx) { if (n2i.Key.StartsWith(sAkk)) { aggCtx[n2i.Value] = f.NewSums(); } } } var loadingCtx = new Generator.Ctx(aggCtx.parent); loadingCtx.CreateValue(sUsedParamsDict, aggCtx[aggCtx.IndexOf(sUsedParamsDict)]); loadingCtx.CreateValue(sLoadingInfo, this); var loadingCode = Generator.Generate(loadingExpr, loadingCtx); var ae = new AsyncExprCtx(loadingCtx, loadingCtx.values, rootAec); return(OPs.ConstValueOf(ae, loadingCode)); }
/// <summary> /// Iterative topological sorting of expressions (ability of calculated values names is taked into account) /// </summary> /// <param name="srcItems"></param> /// <param name="parentCtx"></param> /// <returns></returns> public static IEnumerable <Expr> DoSort(IEnumerable <Expr> srcItems, Generator.Ctx parentCtx) { List <ItemInfo> infos = srcItems.Select(item => new ItemInfo(item)).ToList(); while (true) { //****** sort items with defined names var allLets = new Dictionary <string, ItemInfo>(); foreach (var nfo in infos) { foreach (var name in nfo.lets.Keys) { allLets[name] = nfo; } } infos = TopoSort.DoSort(infos, ii => ii.refs.Keys.Where(s => allLets.ContainsKey(s)).Select(s => allLets[s])); var thereIsNameResolve = false; var allNamesRosolved = true; var ctx = new Generator.Ctx(parentCtx); //****** calculate unresolved names for (int i = 0; i < infos.Count; i++) { var nfo = infos[i]; // side effect?: new values can be declared in context var value = TryGen(ctx, nfo.expr); var lets2 = nfo.lets2; for (int j = 0; j < lets2.Count;) { var let2 = lets2[j]; var letName = TryGen(ctx, let2); if (letName != Fail && OPs.KindOf(letName) == ValueKind.Const) { thereIsNameResolve = true; lets2.RemoveAt(j); nfo.lets[Convert.ToString(letName)] = true; } else { j++; allNamesRosolved = false; } } var refs2 = nfo.refs2; for (int j = 0; j < refs2.Count;) { var ref2 = refs2[j]; var refName = TryGen(ctx, ref2); if (refName != Fail && OPs.KindOf(refName) == ValueKind.Const) { thereIsNameResolve = true; refs2.RemoveAt(j); nfo.refs[Convert.ToString(refName)] = true; } else { j++; allNamesRosolved = false; } } if (nfo.refs.Keys.Any(s => ctx.IndexOf(s) < 0)) { allNamesRosolved = false; } } if (allNamesRosolved || !thereIsNameResolve) { break; } } return(infos.Select(ii => ii.expr)); }
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)); }
public static object Filtering(Generator.Ctx ctx, string inputParam, string sourceData, IList <Expr> filterConditions, string[] outputParams) { var aliasOf = FuncDefs_Solver.GetAliases(ctx); // количество стадий = количество условий фильтрации + 1 стадия подготовки выходных данных int nStages = filterConditions.Count + 1; // для каждой стадии перечень параметров, необходимых для её обработки var stage = new StageInfo[nStages]; // перечень всех параметров всех стадий var usedParamsDict = new Dictionary <string, bool>(StringComparer.OrdinalIgnoreCase); #region Определяем используемые на стадиях обработки данных показатели (стадии фильтрации + стадия подготовки выходных данных) // проход по стадиям фильтрации с формированием перечней используемых параметров for (int i = 0; i < nStages - 1; i++) { var prmsDict = new Dictionary <string, bool>(StringComparer.OrdinalIgnoreCase); foreach (var paramName in filterConditions[i].EnumerateReferences().Where(ValueInfo.IsDescriptor)) { prmsDict[aliasOf.GetRealName(paramName)] = true; } var ownParams = prmsDict.Keys.ToArray <string>(); stage[i].ownParams = ownParams; stage[i].Cond = filterConditions[i]; foreach (var s in ownParams) { usedParamsDict[aliasOf.GetRealName(s)] = true; } } string[] outputParamsRealNames = outputParams.Select(s => aliasOf.GetRealName(s)).ToArray(); // стадия выходных данных stage[nStages - 1].ownParams = outputParamsRealNames; foreach (var s in outputParamsRealNames) { usedParamsDict[s] = true; } #endregion // справочник "параметр -> оценка сложности" var funcComplexity = new Dictionary <string, int>(); //// справочник "параметр -> влияющие на него параметры" //IDictionary<string, string[]> dependencies; // справочник "параметр -> имя вычисляющей его функции" IDictionary <string, string> param2func; // справочник "функция -> входы / выходы" var funcInpsOuts = new Dictionary <string, Tuple <string[], List <string> > >(); #region Определяем зависимости и "сложность" параметров { var localCtx = new Generator.Ctx(ctx); localCtx.GetOrCreateIndexOf(FuncDefs_Solver.optionSolverDependencies); var res = Generator.Generate( // вызываем функцию поиска решения, // которая при наличии optionSolverDependencies возвращает также справочник зависимостей new CallExpr(FuncDefs_Solver.FindSolutionExpr // перечень дополнительных входных параметров (которые в месте этого вызова не определены) , new ArrayExpr(new ConstExpr(inputParam)) // перечень выходных параметров, решение для которых (последовательность вызовов известных функций) надо найти , new ArrayExpr(usedParamsDict.Keys.Select(s => new ConstExpr(s)).ToArray()) ) // контекст кодогенератора для поиска решения (содержит перечень имён известных значений и описаний функций) , localCtx ); var deps = (IDictionary <string, object>)localCtx.values[localCtx.IndexOf(FuncDefs_Solver.optionSolverDependencies)]; //dependencies = deps.ToDictionary(p => p.Key, p => (p.Value == null) ? new string[0] : ((IList)p.Value).Cast<string>().Where(s => !s.StartsWith("#")).ToArray()); param2func = deps.ToDictionary( p => p.Key, p => (p.Value == null) ? string.Empty : ((IList)p.Value).Cast <string>().Where(s => s.StartsWith(FuncDefs_Solver.sDepsFuncNamePrefix)).First() , StringComparer.OrdinalIgnoreCase ); foreach (var d in deps) { var prm = d.Key; var arguments = (IList)d.Value; if (arguments == null) { arguments = new string[] { string.Empty } } ; Tuple <string[], List <string> > fInpsOuts; var sFunc = arguments[0].ToString(); if (!funcInpsOuts.TryGetValue(sFunc, out fInpsOuts)) { var inpFuncs = arguments.Cast <string>() .Skip(1) // first arg is function name .Select(s => param2func[s]) // get function name by her output parameter name .Where(f => f != null) .Distinct().ToArray(); fInpsOuts = new Tuple <string[], List <string> >(inpFuncs, new List <string>()); funcInpsOuts[sFunc] = fInpsOuts; } fInpsOuts.Item2.Add(prm); } var lstAllFuncs = funcInpsOuts.Keys.ToList(); bool someToDo = true; while (someToDo) { someToDo = false; for (int i = lstAllFuncs.Count - 1; i >= 0; --i) { var func = lstAllFuncs[i]; int cmpl = 0; foreach (var s in funcInpsOuts[func].Item1) { int c; if (!funcComplexity.TryGetValue(s, out c)) { cmpl = -1; break; } else { cmpl += c; } } if (cmpl >= 0) { funcComplexity.Add(func, cmpl + 1); lstAllFuncs.RemoveAt(i); someToDo = true; } } } System.Diagnostics.Trace.Assert(lstAllFuncs.Count == 0, "Filtering: lstAllFuncs.Count == 0"); } #endregion { // сортировка стадий по возрастанию "сложности" параметров int[] reorder = Enumerable.Range(0, nStages - 1) .OrderBy(i => (stage[i].ownParams.Length == 0) ? 0 : stage[i].ownParams.Select(s => param2func[s]).Distinct().Select(f => funcComplexity[f]).Sum()) .Concat(new int[] { nStages - 1 }) .ToArray(); Array.Sort(reorder, stage); } #region Проход по стадиям { #if SAFE_PARALLELIZATION bool inParallel = ctx.IndexOf(FuncDefs_Core.stateParallelizationAlreadyInvolved) < 0; #else const bool inParallel = true; #endif if (ctx.IndexOf(FuncDefs_Core.optionMinPartSize) < 0) { ctx.CreateValue(FuncDefs_Core.optionMinPartSize, defaultMinPartSize); } if (ctx.IndexOf(FuncDefs_Core.optionMaxPartSize) < 0) { ctx.CreateValue(FuncDefs_Core.optionMaxPartSize, defaultMaxPartSize); } var readyFuncs = new Dictionary <string, bool>(); readyFuncs.Add(string.Empty, true); var prevDataName = sourceData; var interstageParams = new string[] { inputParam }; var lstStages = new List <StageInfo>(stage); var readyStages = new List <StageInfo>(); var mergedStagesCode = new List <string>(); int iMergedStage = 0; while (lstStages.Count > 0 || readyStages.Count > 0) { for (int i = lstStages.Count - 1; i >= 0; i--) { if (lstStages[i].ownParams.All(prm => readyFuncs.ContainsKey(param2func[prm]))) { readyStages.Add(lstStages[i]); lstStages.RemoveAt(i); } } if (readyStages.Count > 0) { var conds = readyStages.Select(stg => stg.Cond) .Where(cond => cond != null) .OrderBy(cond => cond.Traverse(e => (e is CallExpr || e is ReferenceExpr) ? 1 : 0).Sum()) .ToArray(); bool lastStage = conds.Length == 0; Dictionary <string, bool> flowOfParams = readyStages.Concat(lstStages).SelectMany(si => si.ownParams).Distinct() .ToDictionary(s => s, s => true, StringComparer.OrdinalIgnoreCase); var ownParamsFuncs = readyStages .SelectMany(stg => stg.ownParams.Select(prm => param2func[prm]) .Where(func => !readyFuncs.ContainsKey(func))) .Distinct().ToArray(); var paramsToGetEnum = // все выходные параметры готовых функций (источников данных) readyFuncs.Keys.SelectMany(f => funcInpsOuts[f].Item2).Distinct() // оставляем только те, что нужны на этой и последующих стадиях, а также ID .Where(s => s.EndsWith("_ID") || s.Contains("_ID_") || flowOfParams.ContainsKey(s)) //// показатели оставляем в той форме, которая запрошена (например, в списке есть LIQUID_WATERCUT_OISP и его алиас LIQUID_WATERCUT, а запрошен именно LIQUID_WATERCUT) //.Select(s => aliasOf.AsIn(flowOfParams, s)) ; //if (lastStage) paramsToGetEnum = paramsToGetEnum.Distinct(); //else // paramsToGetEnum = paramsToGetEnum.Distinct(aliasOf); var paramsToGet = paramsToGetEnum.ToArray(); var condExpr = lastStage ? null : (conds.Length == 1) ? conds[0] : new CallExpr("AND", conds); var code = GetConditionStageText(prevDataName, lastStage ? interstageParams : interstageParams.Distinct(), paramsToGet, condExpr, (iMergedStage == 0), inParallel); prevDataName = "stgRows_" + iMergedStage.ToString(); code = string.Format("{0}\r\n..let({1}),", code, prevDataName); if (lastStage) { code += string.Format("\r\nPROGRESS('FilteringItemsList',{0}),\r\n", prevDataName); } mergedStagesCode.Add(code); iMergedStage++; interstageParams = paramsToGet.Distinct().ToArray(); readyStages.Clear(); } else { var stg = lstStages[0]; lstStages.RemoveAt(0); readyStages.Add(stg); AllSrcFuncs( stg.ownParams.Select(prm => param2func[prm]).Where(func => !readyFuncs.ContainsKey(func)).Distinct() , funcInpsOuts, readyFuncs); } } var sbCode = new StringBuilder(); sbCode.AppendLine("("); sbCode.AppendFormat("PROGRESS('FilteringStagesCount',{0}),", mergedStagesCode.Count); sbCode.AppendLine(); foreach (var code in mergedStagesCode) { sbCode.AppendLine(code); } sbCode.AppendFormat("PROGRESS('FilteringComplete',{0}.COLUMNS()),", prevDataName); sbCode.AppendLine(); sbCode.AppendLine(prevDataName); sbCode.AppendLine(")"); var sCode = sbCode.ToString(); return(Parser.ParseToExpr(sCode)); } #endregion }