Exemple #1
0
        private Expression GenerateIteratorStatement(VariablePath iteratorVariablePath,
                                                     Func<Expression> generateMoveNextUpdatePosition,
                                                     int iteratorTupleIndex,
                                                     LabeledStatementAst stmt,
                                                     Action<List<Expression>, Expression> generateBody)
        {
            // We convert:
            //     foreach ($x in $enumerable) {}
            // Into:
            //     try
            //     {
            //         $oldforeach = $foreach
            //         $enumerable = condition
            //         $foreach = GetEnumerator $enumerable
            //         if ($foreach == $null && $enumerable != $null)
            //         {
            //             $foreach  = (new object[] { $enumerable }).GetEnumerator()
            //         }
            //         if ($foreach != $null)
            //         {
            //             while ($foreach.MoveNext())
            //             {
            //                 $x = $foreach.Current
            //             }
            //         }
            //    }
            //    finally
            //    {
            //        $foreach = $oldforeach
            //    }
            // The translation for switch is similar.

            var temps = new List<ParameterExpression>();
            var exprs = new List<Expression>();
            var avs = new AutomaticVarSaver(this, iteratorVariablePath, iteratorTupleIndex);
            bool generatingForeach = stmt is ForEachStatementAst;

            exprs.Add(avs.SaveAutomaticVar());

            // $enumerable = condition
            // $foreach/$switch = GetEnumerator $enumerable
            var enumerable = NewTemp(typeof(object), "enumerable");
            temps.Add(enumerable);
            if (generatingForeach)
            {
                exprs.Add(UpdatePosition(stmt.Condition));
            }
            exprs.Add(
                Expression.Assign(enumerable,
                                  GetRangeEnumerator(stmt.Condition.GetPureExpression())
                                    ?? CaptureStatementResults(stmt.Condition, CaptureAstContext.Enumerable).Convert(typeof(object))));

            var iteratorTemp = NewTemp(typeof(IEnumerator), iteratorVariablePath.UnqualifiedPath);
            temps.Add(iteratorTemp);
            exprs.Add(Expression.Assign(iteratorTemp,
                                        DynamicExpression.Dynamic(PSEnumerableBinder.Get(), typeof(IEnumerator), enumerable)));

            // In a foreach, generate:
            //     if ($foreach == $null && $enumerable != $null)
            //     {
            //         $foreach = (new object[] { $enumerable }).GetEnumerator()
            //     }
            // In a switch, generate:
            //     if ($switch == $null)
            //     {
            //         $switch = (new object[] { $enumerable }).GetEnumerator()
            //     }

            var testNeedScalarToEnumerable =
                generatingForeach
                    ? Expression.AndAlso(
                        Expression.Equal(iteratorTemp, ExpressionCache.NullConstant),
                        Expression.NotEqual(enumerable, ExpressionCache.NullConstant))
                    : Expression.Equal(iteratorTemp, ExpressionCache.NullConstant);
            var scalarToEnumerable =
                Expression.Assign(iteratorTemp,
                    Expression.Call(Expression.NewArrayInit(typeof(object),
                                        Expression.Convert(enumerable, typeof(object))),
                                    CachedReflectionInfo.IEnumerable_GetEnumerator));
            exprs.Add(Expression.IfThen(testNeedScalarToEnumerable, scalarToEnumerable));
            exprs.Add(avs.SetNewValue(iteratorTemp));

            var moveNext = Expression.Block(
                    generateMoveNextUpdatePosition(),
                    Expression.Call(iteratorTemp, CachedReflectionInfo.IEnumerator_MoveNext));

            var loop = GenerateWhileLoop(stmt.Label,
                                         () => moveNext,
                                         (loopBody, breakTarget, continueTarget) => generateBody(loopBody, Expression.Property(iteratorTemp, CachedReflectionInfo.IEnumerator_Current)));

            // With a foreach, the enumerator may never get assigned, in which case we skip the loop entirely.
            // Generate that test.
            // With a switch, the switch body is never skipped, so skip generating that test, and skip creating
            // target block.
            if (generatingForeach)
            {
                exprs.Add(Expression.IfThen(Expression.NotEqual(iteratorTemp, ExpressionCache.NullConstant), loop));
            }
            else
            {
                exprs.Add(loop);
            }

            return Expression.Block(
                temps.Concat(avs.GetTemps()),
                Expression.TryFinally(Expression.Block(exprs), avs.RestoreAutomaticVar()));
        }
Exemple #2
0
 private Expression GenerateIteratorStatement(VariablePath iteratorVariablePath, Func<Expression> generateMoveNextUpdatePosition, int iteratorTupleIndex, LabeledStatementAst stmt, Action<List<Expression>, Expression> generateBody)
 {
     List<ParameterExpression> first = new List<ParameterExpression>();
     List<Expression> expressions = new List<Expression>();
     AutomaticVarSaver saver = new AutomaticVarSaver(this, iteratorVariablePath, iteratorTupleIndex);
     bool flag = stmt is ForEachStatementAst;
     expressions.Add(saver.SaveAutomaticVar());
     ParameterExpression item = this.NewTemp(typeof(object), "enumerable");
     first.Add(item);
     if (flag)
     {
         expressions.Add(this.UpdatePosition(stmt.Condition));
     }
     expressions.Add(Expression.Assign(item, this.GetRangeEnumerator(stmt.Condition.GetPureExpression()) ?? this.CaptureStatementResults(stmt.Condition, CaptureAstContext.Enumerable, null).Convert(typeof(object))));
     ParameterExpression iteratorTemp = this.NewTemp(typeof(IEnumerator), iteratorVariablePath.UnqualifiedPath);
     first.Add(iteratorTemp);
     expressions.Add(Expression.Assign(iteratorTemp, Expression.Dynamic(PSEnumerableBinder.Get(), typeof(IEnumerator), item)));
     BinaryExpression test = flag ? Expression.AndAlso(Expression.Equal(iteratorTemp, ExpressionCache.NullConstant), Expression.NotEqual(item, ExpressionCache.NullConstant)) : Expression.Equal(iteratorTemp, ExpressionCache.NullConstant);
     BinaryExpression ifTrue = Expression.Assign(iteratorTemp, Expression.Call(Expression.NewArrayInit(typeof(object), new Expression[] { Expression.Convert(item, typeof(object)) }), CachedReflectionInfo.IEnumerable_GetEnumerator));
     expressions.Add(Expression.IfThen(test, ifTrue));
     expressions.Add(saver.SetNewValue(iteratorTemp));
     BlockExpression moveNext = Expression.Block(generateMoveNextUpdatePosition(), Expression.Call(iteratorTemp, CachedReflectionInfo.IEnumerator_MoveNext));
     Expression expression4 = this.GenerateWhileLoop(stmt.Label, () => moveNext, delegate (List<Expression> loopBody, LabelTarget breakTarget, LabelTarget continueTarget) {
         generateBody(loopBody, Expression.Property(iteratorTemp, CachedReflectionInfo.IEnumerator_Current));
     }, null);
     if (flag)
     {
         expressions.Add(Expression.IfThen(Expression.NotEqual(iteratorTemp, ExpressionCache.NullConstant), expression4));
     }
     else
     {
         expressions.Add(expression4);
     }
     return Expression.Block(first.Concat<ParameterExpression>(saver.GetTemps()), new Expression[] { Expression.TryFinally(Expression.Block(expressions), saver.RestoreAutomaticVar()) });
 }