public void GeneratesClosureWithoutOverflow()
        {
            var builder = new ClosureBuilder();

            var paths        = GeneratePaths(builder, 2);
            var helpers      = GenerateHelpers(builder, 2);
            var blockHelpers = GenerateBlockHelpers(builder, 2);
            var others       = GenerateOther(builder, 2);

            _ = builder.Build(out var closure);

            Assert.Equal(paths[0], closure.PI0);
            Assert.Equal(paths[1], closure.PI1);
            Assert.Null(closure.PIA);

            Assert.Equal(helpers[0], closure.HD0);
            Assert.Equal(helpers[1], closure.HD1);
            Assert.Null(closure.HDA);

            Assert.Equal(blockHelpers[0], closure.BHD0);
            Assert.Equal(blockHelpers[1], closure.BHD1);
            Assert.Null(closure.BHDA);

            Assert.Equal(others[0], closure.A[0]);
            Assert.Equal(others[1], closure.A[1]);
            Assert.Equal(2, closure.A.Length);
        }
        public void GeneratesClosureWithOverflow()
        {
            var builder = new ClosureBuilder();

            var paths        = GeneratePaths(builder, 6);
            var helpers      = GenerateHelpers(builder, 6);
            var blockHelpers = GenerateBlockHelpers(builder, 6);
            var others       = GenerateOther(builder, 6);

            _ = builder.Build(out var closure);

            Assert.Equal(paths[0], closure.PI0);
            Assert.Equal(paths[3], closure.PI3);
            Assert.Equal(paths[5], closure.PIA[1]);

            Assert.Equal(helpers[0], closure.HD0);
            Assert.Equal(helpers[3], closure.HD3);
            Assert.Equal(helpers[5], closure.HDA[1]);

            Assert.Equal(blockHelpers[0], closure.BHD0);
            Assert.Equal(blockHelpers[3], closure.BHD3);
            Assert.Equal(blockHelpers[5], closure.BHDA[1]);

            Assert.Equal(others[0], closure.A[0]);
            Assert.Equal(others[3], closure.A[3]);
            Assert.Equal(others[5], closure.A[5]);
        }
        private static List <object> GenerateOther(ClosureBuilder builder, int count)
        {
            var others = new List <object>();

            for (int i = 0; i < count; i++)
            {
                var other = new object();
                builder.Add(Const(other));
                others.Add(other);
            }

            return(others);
        }
        private static List <PathInfo> GeneratePaths(ClosureBuilder builder, int count)
        {
            var paths = new List <PathInfo>();

            for (int i = 0; i < count; i++)
            {
                var pathInfo = PathInfo.Parse($"{i}");
                builder.Add(Const(pathInfo));
                paths.Add(pathInfo);
            }

            return(paths);
        }
        public Expression <T> Invoke <T>(Expression <T> expression) where T : Delegate
        {
            var constants = new List <ConstantExpression>();
            var closureCollectorVisitor = new ClosureCollectorVisitor(constants);

            expression = (Expression <T>)closureCollectorVisitor.Visit(expression);

            if (constants.Count == 0)
            {
                return(expression);
            }

            var closureBuilder = new ClosureBuilder();

            for (var index = 0; index < constants.Count; index++)
            {
                var value = constants[index];
                closureBuilder.Add(value);
            }

            var closureDefinition = closureBuilder.Build(out var closure);

            var closureVisitor = new ClosureVisitor(closureDefinition);

            expression = (Expression <T>)closureVisitor.Visit(expression);

            var block = Block()
                        .Parameter(closureDefinition.Key)
                        .Line(Expression.Assign(closureDefinition.Key, Arg(closure)));

            if (expression !.Body is BlockExpression blockExpression)
            {
                var variables = blockExpression.Variables;
                for (var index = 0; index < blockExpression.Variables.Count; index++)
                {
                    block.Parameter(variables[index]);
                }

                block.Lines(blockExpression.Expressions);
            }
        private static List <Ref <IHelperDescriptor <HelperOptions> > > GenerateHelpers(ClosureBuilder builder, int count)
        {
            var helpers = new List <Ref <IHelperDescriptor <HelperOptions> > >();

            for (int i = 0; i < count; i++)
            {
                var helper = new Ref <IHelperDescriptor <HelperOptions> >();
                builder.Add(Const(helper));
                helpers.Add(helper);
            }

            return(helpers);
        }