コード例 #1
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);
        }
コード例 #2
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);
        }
コード例 #3
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);
        }
コード例 #4
0
        public override async ValueTask <Completion> WriteToAsync(TextWriter writer, TextEncoder encoder, TemplateContext context)
        {
            context.IncrementSteps();

            var relativePath = (await Path.EvaluateAsync(context)).ToStringValue();

            if (!relativePath.EndsWith(ViewExtension, StringComparison.OrdinalIgnoreCase))
            {
                relativePath += ViewExtension;
            }

            if (_cachedTemplate == null || !string.Equals(_cachedTemplate.Name, System.IO.Path.GetFileNameWithoutExtension(relativePath), StringComparison.Ordinal))
            {
                await _semaphore.WaitAsync();

                try
                {
                    if (_cachedTemplate == null || !string.Equals(_cachedTemplate.Name, System.IO.Path.GetFileNameWithoutExtension(relativePath), StringComparison.Ordinal))
                    {
                        var fileProvider = context.Options.FileProvider;

                        var fileInfo = fileProvider.GetFileInfo(relativePath);

                        if (fileInfo == null || !fileInfo.Exists)
                        {
                            throw new FileNotFoundException(relativePath);
                        }

                        var content = "";

                        using (var stream = fileInfo.CreateReadStream())
                            using (var streamReader = new StreamReader(stream))
                            {
                                content = await streamReader.ReadToEndAsync();
                            }

                        if (!_parser.TryParse(content, out var template, out var errors))
                        {
                            throw new ParseException(errors);
                        }

                        var identifier = System.IO.Path.GetFileNameWithoutExtension(relativePath);

                        _cachedTemplate = new CachedTemplate(template, identifier);
                    }
                }
                finally
                {
                    _semaphore.Release();
                }
            }

            try
            {
                context.EnterChildScope();

                if (With != null)
                {
                    var with = await With.EvaluateAsync(context);

                    context.SetValue(Alias ?? _cachedTemplate.Name, with);

                    await _cachedTemplate.Template.RenderAsync(writer, encoder, context);
                }
                else if (AssignStatements != null)
                {
                    var length = AssignStatements.Count;
                    for (var i = 0; i < length; i++)
                    {
                        await AssignStatements[i].WriteToAsync(writer, encoder, context);
                    }

                    await _cachedTemplate.Template.RenderAsync(writer, encoder, context);
                }
                else if (For != null)
                {
                    try
                    {
                        var forloop = new ForLoopValue();

                        var list = (await For.EvaluateAsync(context)).Enumerate(context).ToList();

                        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(Alias ?? _cachedTemplate.Name, 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;

                            await _cachedTemplate.Template.RenderAsync(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);
                        }
                    }
                    finally
                    {
                        context.LocalScope.Delete("forloop");
                    }
                }
                else
                {
                    // no with, for or assignments, e.g. {% include 'products' %}
                    await _cachedTemplate.Template.RenderAsync(writer, encoder, context);
                }
            }
            finally
            {
                context.ReleaseScope();
            }

            return(Completion.Normal);
        }