Ejemplo n.º 1
0
        private DelayedTupleExpression LiftVariable(ParameterExpression param)
        {
            DelayedTupleExpression res;

            if (!_vars.TryGetValue(param, out res))
            {
                _vars[param] = res = new DelayedTupleExpression(_vars.Count, _tupleExpr, _tupleType, param.Type);
                _orderedVars.Add(new KeyValuePair <ParameterExpression, DelayedTupleExpression>(param, res));
            }

            return(res);
        }
Ejemplo n.º 2
0
        internal Expression Reduce(bool shouldInterpret, bool emitDebugSymbols, int compilationThreshold,
                                   IList <ParameterExpression> parameters, Func <Expression <Func <MutableTuple, object> >,
                                                                                 Expression <Func <MutableTuple, object> > > bodyConverter)
        {
            _state   = LiftVariable(Expression.Parameter(typeof(int), "state"));
            _current = LiftVariable(Expression.Parameter(typeof(object), "current"));

            // lift the parameters into the tuple
            foreach (ParameterExpression pe in parameters)
            {
                LiftVariable(pe);
            }
            DelayedTupleExpression liftedGen = LiftVariable(_generatorParam);
            // Visit body
            Expression body = Visit(_body);

            Debug.Assert(_returnLabels.Count == 1);

            // Add the switch statement to the body
            int count = _yields.Count;
            var cases = new SwitchCase[count + 1];

            for (int i = 0; i < count; i++)
            {
                cases[i] = Expression.SwitchCase(Expression.Goto(_yields[i].Label), AstUtils.Constant(_yields[i].State));
            }
            cases[count] = Expression.SwitchCase(Expression.Goto(_returnLabels.Peek()), AstUtils.Constant(Finished));

            // Create the lambda for the PythonGeneratorNext, hoisting variables
            // into a tuple outside the lambda
            Expression[] tupleExprs = new Expression[_vars.Count];
            foreach (var variable in _orderedVars)
            {
                // first 2 are our state & out var
                if (variable.Value.Index >= 2 && variable.Value.Index < (parameters.Count + 2))
                {
                    tupleExprs[variable.Value.Index] = parameters[variable.Value.Index - 2];
                }
                else
                {
                    tupleExprs[variable.Value.Index] = Expression.Default(variable.Key.Type);
                }
            }

            Expression          newTuple  = MutableTuple.Create(tupleExprs);
            Type                tupleType = _tupleType.Value = newTuple.Type;
            ParameterExpression tupleExpr = _tupleExpr.Value = Expression.Parameter(tupleType, "tuple");
            ParameterExpression tupleArg  = Expression.Parameter(typeof(MutableTuple), "tupleArg");

            _temps.Add(_gotoRouter);
            _temps.Add(tupleExpr);

            // temps for the outer lambda
            ParameterExpression tupleTmp = Expression.Parameter(tupleType, "tuple");
            ParameterExpression ret      = Expression.Parameter(typeof(PythonGenerator), "ret");

            var innerLambda = Expression.Lambda <Func <MutableTuple, object> >(
                Expression.Block(
                    _temps.ToArray(),
                    Expression.Assign(
                        tupleExpr,
                        Expression.Convert(
                            tupleArg,
                            tupleType
                            )
                        ),
                    Expression.Switch(Expression.Assign(_gotoRouter, _state), cases),
                    body,
                    MakeAssign(_state, AstUtils.Constant(Finished)),
                    Expression.Label(_returnLabels.Peek()),
                    _current
                    ),
                _name,
                new ParameterExpression[] { tupleArg }
                );

            // Generate a call to PythonOps.MakeGeneratorClosure(Tuple data, object generatorCode)
            return(Expression.Block(
                       new[] { tupleTmp, ret },
                       Expression.Assign(
                           ret,
                           Expression.Call(
                               typeof(PythonOps).GetMethod("MakeGenerator"),
                               parameters[0],
                               Expression.Assign(tupleTmp, newTuple),
                               emitDebugSymbols ?
                               (Expression)bodyConverter(innerLambda) :
                               (Expression)Expression.Constant(
                                   new LazyCode <Func <MutableTuple, object> >(
                                       bodyConverter(innerLambda),
                                       shouldInterpret,
                                       compilationThreshold
                                       ),
                                   typeof(object)
                                   )
                               )
                           ),
                       new DelayedTupleAssign(
                           new DelayedTupleExpression(liftedGen.Index, new StrongBox <ParameterExpression>(tupleTmp), _tupleType, typeof(PythonGenerator)),
                           ret
                           ),
                       ret
                       ));
        }