// this needs to do what usually DefIL does and, in addition, create all the contained variables private void RegisterILAndContent(ParIL parIL, int iteration) { // first create the content: e.g. for ils_earns_loop3: yem_loop3, yse_loop3 ... Dictionary <string, double> content = new Dictionary <string, double>(); foreach (var entry in parIL.GetFlatContent()) { string origVarName = entry.varSpec.name; if (!RegisterVar(origVarName, parIL.description, iteration)) { return; } string storeName = ComposeStoreName(origVarName, iteration); // entry of new il: e.g. name: yem_loop3, factor: 1 if (!content.ContainsKey(storeName)) { content.Add(storeName, entry.addFactor); // the usual case } else { content[storeName] += entry.addFactor; // exception: e.g. il contains two ils, which share variables } } // ... then do do what usually DefIL does, i.e. register the incomelist (e.g. ils_earns_loop3) // note: this IL differs from its original by being "flat", i.e. ils are resolved into their variables infoStore.operandAdmin.RegisterIL( name: ComposeStoreName(parIL.name, iteration), creatorFun: DefFun.Store, description: parIL.description, content: content, warnIfNonMon: false); }
internal bool isMonetary = false; // should this varil be formatted like monetary internal override void CheckAndPrepare(FunBase fun) { GetFootnoteNumbers(xmlValue, out string potentialIL); if (infoStore.operandAdmin.Exists(potentialIL) && infoStore.operandAdmin.GetParType(potentialIL) == DefPar.PAR_TYPE.IL) { parIL = new ParIL(infoStore) { xmlValue = xmlValue, description = this.description }; parIL.CheckAndPrepare(fun); } else { parVal = new ParVar(infoStore) { xmlValue = xmlValue, description = this.description }; parVal.CheckAndPrepare(fun); } if (infoStore.operandAdmin.GetIsMonetary(GetName())) { isMonetary = true; } }
private bool CheckPrePost(ILSpecification ilSpecification, ParBase parPrefix, ParBase parPostfix, bool checkContent = true) { ilSpecification.prefix = parPrefix?.xmlValue ?? string.Empty; ilSpecification.postfix = parPostfix?.xmlValue ?? string.Empty; if (string.IsNullOrEmpty(ilSpecification.prefix) && string.IsNullOrEmpty(ilSpecification.postfix)) { return(true); // if no prefix or postfix is defined, then all vars match naming by definition. } if (!checkContent) { return(true); } foreach (string v in ParIL.GetILComponents(ilSpecification.ilName, infoStore.operandAdmin)) { if (v.StartsWith(ilSpecification.prefix, StringComparison.OrdinalIgnoreCase) && v.EndsWith(ilSpecification.postfix, StringComparison.OrdinalIgnoreCase)) { continue; } infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: {ilSpecification.ilName}: contained variables must be named {GetFullVarName("*", ilSpecification)}; " + $"variable {v} does not follow this rule" }); return(false); } return(true); }
private List <string> GetCoreVars(ILSpecification ilSpecification) { List <string> cv = new List <string>(); foreach (string v in ParIL.GetILComponents(ilSpecification.ilName, infoStore.operandAdmin)) { cv.Add(GetCoreVarName(v, ilSpecification)); } return(cv); }
private void PrepareDefILPar() { foreach (ParIL parIL in GetNonUniquePar <ParIL>(DefPar.DefOutput.DefIL)) { // see comment in PrepareOutVar upon creating a ParIL // note, that existence of IL and IL-content is checked in the "standard" parameter checking foreach (string v in ParIL.GetILComponents(parIL.name, infoStore.operandAdmin)) { AddToOutList(v, parIL.description); } } }
/// <summary> /// called by OperandAdmin.CheckRegistration, i.e. on checking if a variable/IL, e.g. used in a formula, is valid /// checks if this Store-function could be possibly "responsible" for this variable/IL /// (e.g. ask for yem_loop3 - Store is responsible if POSTLOOP-parameter=loop and there is a VAR-parameter=yem) /// if responsible, registration takes place as described above /// </summary> internal bool IsStoreOperand(string testOperandName) { if (storeType == STORETYPE.FIX) { return(false); // variables of POSTFIX-Stores are not produced "on demand" (see explanation above) } int iteration = NOTAP; foreach (ParVar par in GetNonUniquePar <ParVar>(DefPar.Store.Var)) { if (CheckIfResponsibleAndGetIteration(par.name)) { RegisterVar(par.name, par.description, iteration); return(true); } } foreach (ParIL par in GetNonUniquePar <ParIL>(DefPar.Store.IL)) { // first check for IL itself, e.g. ils_earns_loop7 if (CheckIfResponsibleAndGetIteration(par.name)) { RegisterILAndContent(par, iteration); return(true); } // then check for the content, e.g. yem_loop7, yse_loop7 foreach (string ilVar in ParIL.GetILComponents(par.name, infoStore.operandAdmin)) { if (CheckIfResponsibleAndGetIteration(ilVar)) { RegisterVar(ilVar, par.description, iteration); return(true); } } } return(false); bool CheckIfResponsibleAndGetIteration(string origName) { string storeName = ComposeStoreName(origName, NOTAP); return(testOperandName.StartsWith(storeName) && int.TryParse(testOperandName.Substring(storeName.Length), out iteration)); } }
internal bool IsProspectiveLoopOperand(string operand) // see InfoStore.IsProspectiveStoreOperand for description { // note that this can be called before (or after) PrepareNonCommonPar, therefore one cannot rely on variables (e.g. post, storeType, ...) // also note that we are only looking for the "running" operands, e.g. yem_loop, ils_earns_loop (i.e. without an iteration) ParBase parPostLoop = GetUniquePar <ParBase>(DefPar.Store.PostLoop); if (parPostLoop == null) { return(false); // most likely a PostFix-Store, thus not relevant } foreach (ParVar par in GetNonUniquePar <ParVar>(DefPar.Store.Var)) { if (ComposeStoreName(par.xmlValue, NOTAP, parPostLoop.xmlValue).ToLower() == operand.ToLower()) { return(true); } } foreach (ParIL par in GetNonUniquePar <ParIL>(DefPar.Store.IL)) { // first check for IL itself, e.g. ils_earns_loop string ili = ComposeStoreName(par.xmlValue, NOTAP, parPostLoop.xmlValue); if (ComposeStoreName(par.xmlValue, NOTAP, parPostLoop.xmlValue).ToLower() == operand.ToLower()) { return(true); } // then check for the content, e.g. yem_loop, yse_loop if (!infoStore.operandAdmin.Exists(par.xmlValue)) { continue; // only check if il is already registered } foreach (string ilVar in ParIL.GetILComponents(par.xmlValue, infoStore.operandAdmin)) { if (ComposeStoreName(ilVar, NOTAP, parPostLoop.xmlValue).ToLower() == operand.ToLower()) { return(true); } } } return(false); }
private bool CloneILStructure(string ilName, string outIlName) { Dictionary <string, double> content = new Dictionary <string, double>(); foreach (ParIL.Entry varIL in ParIL.ResolveILContent(ilName, infoStore.operandAdmin)) { if (!varIL.isIL) { string corename = GetCoreVarName(varIL.varSpec.name, baseILSpecification); string outVarName = GetFullVarName(corename, outILSpecification); infoStore.operandAdmin.RegisterVar( name: outVarName, creatorFun: DefFun.Store, description: description, isMonetary: infoStore.operandAdmin.GetIsMonetary(varIL.varSpec.name), isGlobal: infoStore.operandAdmin.GetIsGlobal(varIL.varSpec.name), isWriteable: false, // cannot be used as output variable setInitialised: true); if (!infoStore.operandAdmin.Exists(outVarName)) { return(false); // registration failed } content.Add(outVarName, varIL.addFactor); } else { string newILName = GetFullVarName(GetCoreVarName(varIL.ilName, baseILSpecification), outILSpecification); CloneILStructure(varIL.ilName, newILName); content.Add(newILName, varIL.addFactor); } } infoStore.operandAdmin.RegisterIL( // do what usually DefIL does, i.e. register the incomelist name: outIlName, creatorFun: DefFun.IlArithOp, description: description, content: content, warnIfNonMon: false); return(infoStore.operandAdmin.Exists(outIlName)); }
private bool RegisterVar(string origVarName, Description description, int iteration, string level = null, ParIL unitLoopILPar = null) { string storeVarName = ComposeStoreName(origVarName, iteration); if ((from v in vars select v.storeVar.name).Contains(storeVarName)) { return(true); // this can easily happen by storing ILs with overlapping content } infoStore.operandAdmin.RegisterVar( name: storeVarName, creatorFun: DefFun.Store, description: description, isMonetary: infoStore.operandAdmin.GetIsMonetary(origVarName), isGlobal: false, isWriteable: false, // cannot be used as output variable setInitialised: true); if (!infoStore.operandAdmin.Exists(storeVarName)) { return(false); // registration failed } vars.Add(new StoreVar() { origVar = new VarSpec() { name = origVarName }, storeVar = new VarSpec() { name = storeVarName }, iteration = iteration, level = level, unitLoopILPar = unitLoopILPar }); return(true); }
internal override void CheckAndPrepare(FunBase fun) { if (FunIlArithOp.HandlesCheckAndPrepare(this)) { return; // IlArithOp has a special handling for the Formula parameter (see FunIlArithOp.cs) } if (xmlValue.Contains("}#")) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = true, runTimeErrorId = description.funID, message = $"{description.Get()}: Footnotes should not be placed outside curly brackets! Please make sure that all footnotes are directly applied to a single operand." }); } // for optimisation reasons handle #Amount and periods (#y, #w, ...) before parsing the formula: // alternatively one could allow for PAR_TYPE.NUMBER in the switch below, which would create a ParNumber that takes care // but then e.g. 1200#y*3 would, for each HH, ask for parNumber.GetValue()*3, while with this "preparsing" we just have 300 string preParsedFormula = PreParse(xmlValue, fun); // parse the main formula try { parsedExpression = calc.CompileExpression(preParsedFormula); } catch (Exception e) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: {e.Message}" }); return; } foreach (string op in calc.Variables.Keys) // parse the formula ... { ParBase_FormulaComponent opPar = null; // ... and prepare the operands GetFootnoteNumbers(op, out string opName); // temporarily remove potential footnotes to get the pure operand (e.g. yem#1->yem) // handle "partner:yem" or "head:yem" if (opName.Contains(":")) { // this is not allowed outside DefTU! if (description.fun.Name != DefFun.DefTu) { infoStore.communicator.ReportError(new Communicator.ErrorInfo() { isWarning = false, message = $"{description.Get()}: invalid use of target outside of a DefTU '{opName}'." }); } opName = opName.Substring(opName.IndexOf(":") + 1); } if (infoStore.operandAdmin.Exists(opName)) { switch (infoStore.operandAdmin.GetParType(opName)) { //case DefPar.PAR_TYPE.NUMBER: opPar = new ParNumber(infoStore); break; // see PreParse above case DefPar.PAR_TYPE.VAR: opPar = new ParVar(infoStore); break; case DefPar.PAR_TYPE.IL: opPar = new ParIL(infoStore); break; case DefPar.PAR_TYPE.QUERY: opPar = new ParQuery(infoStore); break; } } else { opPar = new ParVar(infoStore); // if not yet in the operand-list, the only (not faulty) option is a data-variable } opPar.description = description; opPar.xmlValue = op; opPar.CheckAndPrepare(fun); operands.Add(op, opPar); } }