예제 #1
0
        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);
        }
예제 #2
0
파일: ForStatement.cs 프로젝트: Selz/fluid
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }