public static IEnumerator ConvertAnythingToIterator(TemplateFrame frame, object o) { o = ConvertAnythingIteratableToIterator(frame, o); IEnumerator iter = o as IEnumerator; if (iter != null) return iter; Template.AttributeList singleton = new Template.AttributeList(1); singleton.Add(o); return singleton.GetEnumerator(); }
// <names,phones:{n,p | ...}> or <a,b:t()> // todo: i, i0 not set unless mentioned? map:{k,v | ..}? protected virtual Template.AttributeList ZipMap(TemplateFrame frame, List<object> exprs, Template prototype) { Template self = frame.Template; if (exprs == null || prototype == null || exprs.Count == 0) { return null; // do not apply if missing templates or empty values } // make everything iterable for (int i = 0; i < exprs.Count; i++) { object attr = exprs[i]; if (attr != null) exprs[i] = ConvertAnythingToIterator(frame, attr); } // ensure arguments line up int numExprs = exprs.Count; CompiledTemplate code = prototype.impl; List<FormalArgument> formalArguments = code.FormalArguments; if (!code.HasFormalArgs || formalArguments == null) { _errorManager.RuntimeError(frame, ErrorType.MISSING_FORMAL_ARGUMENTS); return null; } // todo: track formal args not names for efficient filling of locals object[] formalArgumentNames = formalArguments.Select(i => i.Name).ToArray(); int nformalArgs = formalArgumentNames.Length; if (prototype.IsAnonymousSubtemplate) nformalArgs -= predefinedAnonSubtemplateAttributes.Length; if (nformalArgs != numExprs) { _errorManager.RuntimeError(frame, ErrorType.MAP_ARGUMENT_COUNT_MISMATCH, numExprs, nformalArgs); // TODO just fill first n // truncate arg list to match smaller size int shorterSize = Math.Min(formalArgumentNames.Length, numExprs); numExprs = shorterSize; Array.Resize(ref formalArgumentNames, shorterSize); } // keep walking while at least one attribute has values Template.AttributeList results = new Template.AttributeList(); int i2 = 0; // iteration number from 0 while (true) { // get a value for each attribute in list; put into Template instance int numEmpty = 0; Template embedded = group.CreateStringTemplateInternally(prototype); embedded.RawSetAttribute("i0", i2); embedded.RawSetAttribute("i", i2 + 1); for (int a = 0; a < numExprs; a++) { IEnumerator it = (IEnumerator)exprs[a]; if (it != null && it.MoveNext()) { string argName = (string)formalArgumentNames[a]; object iteratedValue = it.Current; embedded.RawSetAttribute(argName, iteratedValue); } else { numEmpty++; } } if (numEmpty == numExprs) break; results.Add(embedded); i2++; } return results; }