public override async Task <Completion> WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context) { IEnumerable <FluidValue> elements = Array.Empty <FluidValue>(); if (Member != null) { var member = await Member.EvaluateAsync(context); elements = member.Enumerate(); } else if (Range != null) { int start = Convert.ToInt32((await Range.From.EvaluateAsync(context)).ToNumberValue()); int end = Convert.ToInt32((await Range.To.EvaluateAsync(context)).ToNumberValue()); elements = Enumerable.Range(start, end - start + 1).Select(x => new NumberValue(x)); } if (!elements.Any()) { return(Completion.Normal); } // Apply options if (Offset != null) { var offset = (int)(await Offset.EvaluateAsync(context)).ToNumberValue(); elements = elements.Skip(offset); } if (Limit != null) { var limit = (int)(await Limit.EvaluateAsync(context)).ToNumberValue(); elements = elements.Take(limit); } if (Reversed) { elements = elements.Reverse(); } var list = elements.ToList(); if (!list.Any()) { return(Completion.Normal); } try { var forloop = new Dictionary <string, FluidValue>(); forloop.Add("length", new NumberValue(list.Count)); context.SetValue("forloop", new DictionaryValue(new FluidValueDictionaryFluidIndexable(forloop))); for (var i = 0; i < list.Count; i++) { var item = list[i]; context.SetValue(Identifier, item); // Set helper variables forloop["index"] = new NumberValue(i + 1); forloop["index0"] = new NumberValue(i); forloop["rindex"] = new NumberValue(list.Count - i - 1); forloop["rindex0"] = new NumberValue(list.Count - i); forloop["first"] = new BooleanValue(i == 0); forloop["last"] = new BooleanValue(i == list.Count - 1); Completion completion = Completion.Normal; for (var index = 0; index < Statements.Count; index++) { var statement = Statements[index]; completion = await statement.WriteToAsync(writer, encoder, context); if (completion != Completion.Normal) { // Stop processing the block statements break; } } if (completion == Completion.Continue) { // Go to next iteration continue; } if (completion == Completion.Break) { // Leave the loop break; } } } finally { context.LocalScope.Delete("forloop"); } return(Completion.Normal); }
public override async ValueTask <Completion> WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context) { IEnumerable <FluidValue> elements = Array.Empty <FluidValue>(); if (Member != null) { var member = await Member.EvaluateAsync(context); elements = member.Enumerate(); } else if (Range != null) { int start = Convert.ToInt32((await Range.From.EvaluateAsync(context)).ToNumberValue()); int end = Convert.ToInt32((await Range.To.EvaluateAsync(context)).ToNumberValue()); // Cache range if (_rangeElements == null || _rangeStart != start || _rangeEnd != end) { _rangeElements = new List <FluidValue>(); for (var i = start; i <= end; i++) { _rangeElements.Add(NumberValue.Create(i)); } elements = _rangeElements; _rangeStart = start; _rangeEnd = end; } else { elements = _rangeElements; } } if (!elements.Any()) { return(Completion.Normal); } // Apply options if (Offset != null) { var offset = (int)(await Offset.EvaluateAsync(context)).ToNumberValue(); elements = elements.Skip(offset); } if (Limit != null) { var limit = (int)(await Limit.EvaluateAsync(context)).ToNumberValue(); elements = elements.Take(limit); } if (Reversed) { elements = elements.Reverse(); } var list = elements.ToList(); if (!list.Any()) { return(Completion.Normal); } // Selz: We need to keep the original value for the identifier so that // after the for statement it will not be override var originalValue = context.GetValue(Identifier); try { var forloop = new ForLoopValue(); var length = forloop.Length = list.Count; context.SetValue("forloop", forloop); for (var i = 0; i < length; i++) { context.IncrementSteps(); var item = list[i]; context.SetValue(Identifier, item); // Set helper variables forloop.Index = i + 1; forloop.Index0 = i; forloop.RIndex = length - i - 1; forloop.RIndex0 = length - i; forloop.First = i == 0; forloop.Last = i == length - 1; Completion completion = Completion.Normal; for (var index = 0; index < Statements.Count; index++) { var statement = Statements[index]; completion = await statement.WriteToAsync(writer, encoder, context); // Restore the forloop property after every statement in case it replaced it, // for instance if it contains a nested for loop context.SetValue("forloop", forloop); if (completion != Completion.Normal) { // Stop processing the block statements break; } } if (completion == Completion.Continue) { // Go to next iteration continue; } if (completion == Completion.Break) { // Leave the loop break; } } } finally { context.LocalScope.Delete("forloop"); context.SetValue(Identifier, originalValue); } return(Completion.Normal); }
public override async ValueTask <Completion> WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context) { List <FluidValue> list = null; if (Member != null) { var member = await Member.EvaluateAsync(context); list = member.ToList(); } else if (Range != null) { int start = Convert.ToInt32((await Range.From.EvaluateAsync(context)).ToNumberValue()); int end = Convert.ToInt32((await Range.To.EvaluateAsync(context)).ToNumberValue()); // Cache range if (_rangeElements == null || _rangeStart != start || _rangeEnd != end) { _rangeElements = new List <FluidValue>(end - start); for (var i = start; i <= end; i++) { _rangeElements.Add(NumberValue.Create(i)); } list = _rangeElements; _rangeStart = start; _rangeEnd = end; } else { list = _rangeElements; } } if (list is null || list.Count == 0) { if (Else != null) { await Else.WriteToAsync(writer, encoder, context); } return(Completion.Normal); } // Apply options var startIndex = 0; if (Offset is not null) { var offset = (int)(await Offset.EvaluateAsync(context)).ToNumberValue(); startIndex = offset; } var count = Math.Max(0, list.Count - startIndex); if (Limit is not null) { var limit = (int)(await Limit.EvaluateAsync(context)).ToNumberValue(); count = Math.Min(count, limit); } if (count == 0) { if (Else != null) { await Else.WriteToAsync(writer, encoder, context); } return(Completion.Normal); } if (Reversed) { list.Reverse(startIndex, count); } try { var forloop = new ForLoopValue(); var length = forloop.Length = startIndex + count; context.SetValue("forloop", forloop); for (var i = startIndex; i < length; i++) { context.IncrementSteps(); var item = list[i]; context.SetValue(Identifier, item); // Set helper variables forloop.Index = i + 1; forloop.Index0 = i; forloop.RIndex = length - i - 1; forloop.RIndex0 = length - i; forloop.First = i == 0; forloop.Last = i == length - 1; Completion completion = Completion.Normal; for (var index = 0; index < _statements.Count; index++) { var statement = _statements[index]; completion = await statement.WriteToAsync(writer, encoder, context); // Restore the forloop property after every statement in case it replaced it, // for instance if it contains a nested for loop context.SetValue("forloop", forloop); if (completion != Completion.Normal) { // Stop processing the block statements break; } } if (completion == Completion.Continue) { // Go to next iteration continue; } if (completion == Completion.Break) { // Leave the loop break; } } } finally { context.LocalScope.Delete("forloop"); } return(Completion.Normal); }
public override async ValueTask <Completion> WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context) { var source = (await Source.EvaluateAsync(context)).Enumerate(context).ToList(); if (source.Count == 0) { if (Else != null) { await Else.WriteToAsync(writer, encoder, context); } return(Completion.Normal); } // Apply options var startIndex = 0; if (Offset is not null) { if (_isContinueOffset) { startIndex = (int)context.GetValue(_continueOffsetLiteral).ToNumberValue(); } else { var offset = (int)(await Offset.EvaluateAsync(context)).ToNumberValue(); startIndex = offset; } } var count = Math.Max(0, source.Count - startIndex); if (Limit is not null) { var limit = (int)(await Limit.EvaluateAsync(context)).ToNumberValue(); // Limit can be negative if (limit >= 0) { count = Math.Min(count, limit); } else { count = Math.Max(0, count + limit); } } if (count == 0) { if (Else != null) { await Else.WriteToAsync(writer, encoder, context); } return(Completion.Normal); } if (Reversed) { source.Reverse(startIndex, count); } context.EnterForLoopScope(); try { var forloop = new ForLoopValue(); var length = forloop.Length = startIndex + count; context.LocalScope._properties["forloop"] = forloop; for (var i = startIndex; i < length; i++) { context.IncrementSteps(); var item = source[i]; context.LocalScope._properties[Identifier] = item; // Set helper variables forloop.Index = i + 1; forloop.Index0 = i; forloop.RIndex = length - i - 1; forloop.RIndex0 = length - i; forloop.First = i == 0; forloop.Last = i == length - 1; if (_continueOffsetLiteral != null) { context.SetValue(_continueOffsetLiteral, forloop.Index); } Completion completion = Completion.Normal; for (var index = 0; index < _statements.Count; index++) { var statement = _statements[index]; completion = await statement.WriteToAsync(writer, encoder, context); //// Restore the forloop property after every statement in case it replaced it, //// for instance if it contains a nested for loop //context.LocalScope._properties["forloop"] = forloop; if (completion != Completion.Normal) { // Stop processing the block statements break; } } if (completion == Completion.Continue) { // Go to next iteration continue; } if (completion == Completion.Break) { // Leave the loop break; } } } finally { context.ReleaseScope(); } return(Completion.Normal); }