コード例 #1
0
ファイル: Compiler.cs プロジェクト: 40a/PowerShell
        public object VisitTryStatement(TryStatementAst tryStatementAst)
        {
            var temps = new List<ParameterExpression>();
            var tryBlockExprs = new List<Expression>();
            var finallyBlockExprs = new List<Expression>();

            // We must set $ExecutionContext.PropagateExceptionsToEnclosingStatementBlock = $true so we don't prompt
            // if an exception is raised, and we must restore the previous value when leaving because we can't
            // know if we're dynamically executing code guarded by a try/catch.
            var oldActiveHandler = NewTemp(typeof(bool), "oldActiveHandler");
            temps.Add(oldActiveHandler);
            var handlerInScope = Expression.Property(_executionContextParameter,
                                     CachedReflectionInfo.ExecutionContext_ExceptionHandlerInEnclosingStatementBlock);
            tryBlockExprs.Add(Expression.Assign(oldActiveHandler, handlerInScope));
            tryBlockExprs.Add(Expression.Assign(handlerInScope, ExpressionCache.Constant(true)));
            finallyBlockExprs.Add(Expression.Assign(handlerInScope, oldActiveHandler));

            CompileStatementListWithTraps(tryStatementAst.Body.Statements, tryStatementAst.Body.Traps, tryBlockExprs, temps);

            var catches = new List<CatchBlock>();

            if (tryStatementAst.CatchClauses.Count == 1 && tryStatementAst.CatchClauses[0].IsCatchAll)
            {
                // Generate:
                //    catch (RuntimeException rte)
                //    {
                //        oldrte = context.CurrentExceptionBeingHandled
                //        context.CurrentExceptionBeingHandled = rte
                //        oldDollarUnder = $_
                //        $_ = new ErrorRecord(rte.ErrorRecord, rte)
                //        try {
                //            user catch code
                //        } finally {
                //            $_ = oldDollarUnder
                //            context.CurrentExceptionBeingHandled = oldrte
                //        }
                AutomaticVarSaver avs = new AutomaticVarSaver(this, SpecialVariables.UnderbarVarPath,
                                                              (int)AutomaticVariable.Underbar);
                var rte = NewTemp(typeof(RuntimeException), "rte");
                var oldrte = NewTemp(typeof(RuntimeException), "oldrte");
                var errorRecord = Expression.New(CachedReflectionInfo.ErrorRecord__ctor,
                                                 Expression.Property(rte, CachedReflectionInfo.RuntimeException_ErrorRecord),
                                                 rte);
                var catchExprs = new List<Expression>
                                     {
                                     Expression.Assign(oldrte, s_currentExceptionBeingHandled),
                                     Expression.Assign(s_currentExceptionBeingHandled, rte),
                                     avs.SaveAutomaticVar(),
                                     avs.SetNewValue(errorRecord)
                                 };
                StatementBlockAst statementBlock = tryStatementAst.CatchClauses[0].Body;
                CompileStatementListWithTraps(statementBlock.Statements, statementBlock.Traps, catchExprs, temps);

                var tf = Expression.TryFinally(
                    Expression.Block(typeof(void), catchExprs),
                    Expression.Block(typeof(void),
                                     avs.RestoreAutomaticVar(),
                                     Expression.Assign(s_currentExceptionBeingHandled, oldrte)));

                catches.Add(Expression.Catch(typeof(PipelineStoppedException), Expression.Rethrow()));
                catches.Add(Expression.Catch(rte, Expression.Block(avs.GetTemps().Append(oldrte).ToArray(), tf)));
            }
            else if (tryStatementAst.CatchClauses.Count > 0)
            {
                // We can't generate a try/catch in quite the way one might expect for a few reasons:
                //     * At compile time, we may not have loaded the types that are being caught
                //     * We wrap exceptions in a RuntimeException so they can carry a position.
                //
                // Instead, we generate something like:
                //     try {}
                //     catch (RuntimeException re) {
                //         try
                //         {
                //             oldexception = context.CurrentExceptionBeingHandled
                //             context.CurrentExceptionBeingHandled = re
                //             old_ = $_
                //             $_ = re.ErrorRecord
                //             switch (ExceptionHandlingOps.FindMatchingHandler(re, types))
                //             {
                //             case 0:
                //                  /* first handler */
                //                  break;
                //             case 1:
                //             case 2:
                //                  /* second handler (we do allow a single handler for multiple types) */
                //                  break;
                //             default:
                //                  /* no matching handler, but could be a trap or user might want prompting */
                //                  /* will rethrow the exception if that's what we need to do */
                //                  ExceptionHandlingOps.CheckActionPreference(functionContext, exception);
                //             }
                //         } finally {
                //             $_ = old_
                //             context.CurrentExceptionBeingHandled = oldexception
                //         }
                //     }

                // Try to get the types at compile time.  We could end up with nulls in this array, we'll handle
                // that with runtime code.
                int countTypes = 0;
                for (int index = 0; index < tryStatementAst.CatchClauses.Count; index++)
                {
                    var c = tryStatementAst.CatchClauses[index];
                    // If CatchTypes.Count is empty, we still want to count the catch all handler.
                    countTypes += Math.Max(c.CatchTypes.Count, 1);
                }

                var catchTypes = new Type[countTypes];
                Expression catchTypesExpr = Expression.Constant(catchTypes);
                var dynamicCatchTypes = new List<Expression>();
                var cases = new List<SwitchCase>();
                int handlerTypeIndex = 0;
                int i = 0;

                var exception = Expression.Parameter(typeof(RuntimeException));
                for (int index = 0; index < tryStatementAst.CatchClauses.Count; index++)
                {
                    var c = tryStatementAst.CatchClauses[index];
                    if (c.IsCatchAll)
                    {
                        catchTypes[i] = typeof(ExceptionHandlingOps.CatchAll);
                    }
                    else
                    {
                        for (int index1 = 0; index1 < c.CatchTypes.Count; index1++)
                        {
                            var ct = c.CatchTypes[index1];
                            catchTypes[i] = ct.TypeName.GetReflectionType();
                            if (catchTypes[i] == null)
                            {
                                // Type needs to be resolved at runtime, so we'll use code like:
                                //
                                // if (catchTypes[i] == null) catchTypes[i] = ResolveTypeName(ct.TypeName)
                                //
                                // We use a constant array, resolve just once (unless it fails) to prevent re-resolving
                                // each time it executes.

                                var indexExpr = Expression.ArrayAccess(catchTypesExpr, ExpressionCache.Constant(i));
                                dynamicCatchTypes.Add(
                                    Expression.IfThen(
                                        Expression.Equal(indexExpr, ExpressionCache.NullType),
                                        Expression.Assign(
                                            indexExpr,
                                            Expression.Call(CachedReflectionInfo.TypeOps_ResolveTypeName,
                                                            Expression.Constant(ct.TypeName),
                                                            Expression.Constant(ct.Extent)))));
                            }
                            i += 1;
                        }
                    }

                    // Wrap the body in a void block so all cases have the same type.
                    var catchBody = Expression.Block(typeof(void), Compile(c.Body));

                    if (c.IsCatchAll)
                    {
                        cases.Add(Expression.SwitchCase(catchBody,
                                                        ExpressionCache.Constant(handlerTypeIndex)));
                        handlerTypeIndex += 1;
                    }
                    else
                    {
                        cases.Add(Expression.SwitchCase(catchBody,
                                                        Enumerable.Range(handlerTypeIndex,
                                                                         handlerTypeIndex + c.CatchTypes.Count).Select(
                                                                             ExpressionCache.Constant)));
                        handlerTypeIndex += c.CatchTypes.Count;
                    }
                }

                if (dynamicCatchTypes.Count > 0)
                {
                    // This might be worth a strict-mode check - if there was a typo, the typo isn't discovered until
                    // the first time an exception is raised, which is rather unfortunate.

                    catchTypesExpr = Expression.Block(dynamicCatchTypes.Append(catchTypesExpr));
                }

                AutomaticVarSaver avs = new AutomaticVarSaver(this, SpecialVariables.UnderbarVarPath,
                                                              (int)AutomaticVariable.Underbar);
                var swCond = Expression.Call(CachedReflectionInfo.ExceptionHandlingOps_FindMatchingHandler,
                                             LocalVariablesParameter, exception, catchTypesExpr, _executionContextParameter);
                var oldexception = NewTemp(typeof(RuntimeException), "oldrte");

                var tf = Expression.TryFinally(
                    Expression.Block(
                        typeof(void),
                        Expression.Assign(oldexception, s_currentExceptionBeingHandled),
                        Expression.Assign(s_currentExceptionBeingHandled, exception),
                        avs.SaveAutomaticVar(),
                        // $_ is set in the call to ExceptionHandlingOps.FindMatchingHandler
                        Expression.Switch(
                            swCond,
                            Expression.Call(
                                CachedReflectionInfo.ExceptionHandlingOps_CheckActionPreference,
                                _functionContext, exception),
                            cases.ToArray())),
                    Expression.Block(
                        avs.RestoreAutomaticVar(),
                        Expression.Assign(s_currentExceptionBeingHandled, oldexception)));

                catches.Add(Expression.Catch(typeof(PipelineStoppedException), Expression.Rethrow()));
                catches.Add(Expression.Catch(exception, Expression.Block(avs.GetTemps().Append(oldexception).ToArray(), tf)));
            }

            if (tryStatementAst.Finally != null)
            {
                // Generate:
                //     oldIsStopping = ExceptionHandlingOps.SuspendStoppingPipeline(executionContext);
                //     try {
                //         user finally statements
                //     } finally {
                //         ExceptionHandlingOps.RestoreStoppingPipeline(executionContext, oldIsStopping);
                //     }

                var oldIsStopping = NewTemp(typeof(bool), "oldIsStopping");
                temps.Add(oldIsStopping);
                finallyBlockExprs.Add(
                    Expression.Assign(oldIsStopping,
                                      Expression.Call(CachedReflectionInfo.ExceptionHandlingOps_SuspendStoppingPipeline,
                                                      _executionContextParameter)));
                var nestedFinallyExprs = new List<Expression>();
                CompileStatementListWithTraps(tryStatementAst.Finally.Statements,
                                              tryStatementAst.Finally.Traps, nestedFinallyExprs, temps);
                if (nestedFinallyExprs.Count == 0)
                {
                    nestedFinallyExprs.Add(ExpressionCache.Empty);
                }

                finallyBlockExprs.Add(Expression.Block(
                    Expression.TryFinally(
                        Expression.Block(nestedFinallyExprs),
                        Expression.Call(CachedReflectionInfo.ExceptionHandlingOps_RestoreStoppingPipeline,
                                        _executionContextParameter,
                                        oldIsStopping))));
            }

            // Our result must have void type, so make sure it does.
            if (tryBlockExprs[tryBlockExprs.Count - 1].Type != typeof(void))
            {
                tryBlockExprs.Add(ExpressionCache.Empty);
            }

            if (catches.Count > 0)
            {
                return Expression.Block(
                    temps.ToArray(),
                    Expression.TryCatchFinally(
                        Expression.Block(tryBlockExprs),
                        Expression.Block(finallyBlockExprs),
                        catches.ToArray()));
            }

            return Expression.Block(
                temps.ToArray(),
                Expression.TryFinally(
                    Expression.Block(tryBlockExprs),
                    Expression.Block(finallyBlockExprs)));
        }
コード例 #2
0
ファイル: Compiler.cs プロジェクト: 40a/PowerShell
        private Action<List<Expression>, Expression> GetSwitchBodyGenerator(SwitchStatementAst switchStatementAst, AutomaticVarSaver avs, ParameterExpression skipDefault)
        {
            return (exprs, newValue) =>
                   {
                       var clauseEvalBinder = PSSwitchClauseEvalBinder.Get(switchStatementAst.Flags);
                       exprs.Add(avs.SetNewValue(newValue));

                       if (skipDefault != null)
                       {
                           exprs.Add(Expression.Assign(skipDefault, ExpressionCache.Constant(false)));
                       }

                       IsConstantValueVisitor iscvv = new IsConstantValueVisitor();
                       ConstantValueVisitor cvv = new ConstantValueVisitor();

                       int clauseCount = switchStatementAst.Clauses.Count;
                       for (int i = 0; i < clauseCount; i++)
                       {
                           var clause = switchStatementAst.Clauses[i];

                           Expression test;
                           object constValue = ((bool)clause.Item1.Accept(iscvv)) ? clause.Item1.Accept(cvv) : null;
                           if (constValue is ScriptBlock)
                           {
                               var call = Expression.Call(Expression.Constant(constValue),
                                                           CachedReflectionInfo.ScriptBlock_DoInvokeReturnAsIs,
                               /*useLocalScope=*/         ExpressionCache.Constant(true),
                               /*errorHandlingBehavior=*/ Expression.Constant(ScriptBlock.ErrorHandlingBehavior.WriteToExternalErrorPipe),
                               /*dollarUnder=*/           GetLocal((int)AutomaticVariable.Underbar).Convert(typeof(object)),
                               /*input=*/                 ExpressionCache.AutomationNullConstant,
                               /*scriptThis=*/            ExpressionCache.AutomationNullConstant,
                               /*args=*/                  ExpressionCache.NullObjectArray);
                               test = DynamicExpression.Dynamic(PSConvertBinder.Get(typeof(bool)), typeof(bool), call);
                           }
                           else if (constValue != null)
                           {
                               SwitchFlags flags = switchStatementAst.Flags;
                               Expression conditionExpr = constValue is Regex || constValue is WildcardPattern
                                                    ? (Expression)Expression.Constant(constValue)
                                                    : DynamicExpression.Dynamic(PSToStringBinder.Get(), typeof(string),
                                                                                (constValue is Type)
                                                                                    ? Expression.Constant(constValue, typeof(Type))
                                                                                    : Expression.Constant(constValue),
                                                                                _executionContextParameter);
                               Expression currentAsString =
                                   DynamicExpression.Dynamic(PSToStringBinder.Get(), typeof(string), GetLocal((int)AutomaticVariable.Underbar),
                                                             _executionContextParameter);
                               if ((flags & SwitchFlags.Regex) != 0 || constValue is Regex)
                               {
                                   test = Expression.Call(CachedReflectionInfo.SwitchOps_ConditionSatisfiedRegex,
                                       /*caseSensitive=*/ ExpressionCache.Constant((flags & SwitchFlags.CaseSensitive) != 0),
                                       /*condition=*/     conditionExpr,
                                       /*errorPosition=*/ Expression.Constant(clause.Item1.Extent),
                                       /*str=*/           currentAsString,
                                       /*context=*/       _executionContextParameter);
                               }
                               else if ((flags & SwitchFlags.Wildcard) != 0 || constValue is WildcardPattern)
                               {
                                   // It would be a little better to just build the wildcard at compile time, but
                                   // the runtime method must exist when variable cases are involved.
                                   test = Expression.Call(CachedReflectionInfo.SwitchOps_ConditionSatisfiedWildcard,
                                       /*caseSensitive=*/ ExpressionCache.Constant((flags & SwitchFlags.CaseSensitive) != 0),
                                       /*condition=*/     conditionExpr,
                                       /*str=*/           currentAsString,
                                       /*context=*/       _executionContextParameter);
                               }
                               else
                               {
                                   test = CallStringEquals(conditionExpr, currentAsString,
                                                           ((flags & SwitchFlags.CaseSensitive) == 0));
                               }
                           }
                           else
                           {
                               var cond = Compile(clause.Item1);
                               test = DynamicExpression.Dynamic(clauseEvalBinder, typeof(bool),
                                                                cond, GetLocal((int)AutomaticVariable.Underbar), _executionContextParameter);
                           }

                           exprs.Add(UpdatePosition(clause.Item1));
                           if (skipDefault != null)
                           {
                               exprs.Add(Expression.IfThen(
                                   test,
                                   Expression.Block(Compile(clause.Item2),
                                                    Expression.Assign(skipDefault, ExpressionCache.Constant(true)))));
                           }
                           else
                           {
                               exprs.Add(Expression.IfThen(test, Compile(clause.Item2)));
                           }
                       }

                       if (skipDefault != null)
                       {
                           exprs.Add(Expression.IfThen(Expression.Not(skipDefault), Compile(switchStatementAst.Default)));
                       }
                   };
        }
コード例 #3
0
ファイル: Compiler.cs プロジェクト: 40a/PowerShell
        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()));
        }
コード例 #4
0
ファイル: Compiler.cs プロジェクト: 40a/PowerShell
        public object VisitSwitchStatement(SwitchStatementAst switchStatementAst)
        {
            var avs = new AutomaticVarSaver(this, SpecialVariables.UnderbarVarPath, (int)AutomaticVariable.Underbar);
            var temps = new List<ParameterExpression>();
            ParameterExpression skipDefault = null;
            if (switchStatementAst.Default != null)
            {
                skipDefault = NewTemp(typeof(bool), "skipDefault");
                temps.Add(skipDefault);
            }

            var switchBodyGenerator = GetSwitchBodyGenerator(switchStatementAst, avs, skipDefault);

            if ((switchStatementAst.Flags & SwitchFlags.File) != 0)
            {
                // Generate:
                //
                //    string path = SwitchOps.ResolveFilePath(cond.Extent, cond, context);
                //    StreamReader sr = null;
                //    try
                //    {
                //        sr = new StreamReader(path);
                //        string line;
                //        while ((line = sr.ReadLine()) != null)
                //        {
                //            $_ = line
                //            test clauses
                //        }
                //    }
                //    catch (FlowControlException) { throw; }
                //    catch (Exception exception)
                //    {
                //        CommandProcessorBase.CheckForSevereException(exception);
                //        // "The file could not be read:" + fne.Message
                //        throw InterpreterError.NewInterpreterExceptionWithInnerException(path, typeof(RuntimeException),
                //            cond.Extent, "FileReadError", ParserStrings.FileReadError, exception, exception.Message);
                //    }
                //    finally
                //    {
                //        if (sr != null) sr.Dispose();
                //    }

                var exprs = new List<Expression>();

                var path = NewTemp(typeof(string), "path");
                temps.Add(path);

                exprs.Add(UpdatePosition(switchStatementAst.Condition));

                // We should not preserve the partial output if exception is thrown when evaluating the condition.
                var cond = DynamicExpression.Dynamic(PSToStringBinder.Get(), typeof(string),
                                                     CaptureStatementResults(switchStatementAst.Condition, CaptureAstContext.AssignmentWithoutResultPreservation),
                                                     _executionContextParameter);
                exprs.Add(
                    Expression.Assign(
                        path,
                        Expression.Call(CachedReflectionInfo.SwitchOps_ResolveFilePath,
                                        Expression.Constant(switchStatementAst.Condition.Extent),
                                        cond,
                                        _executionContextParameter)));

                var tryBodyExprs = new List<Expression>();

                var streamReader = NewTemp(typeof(StreamReader), "streamReader");
                var line = NewTemp(typeof(string), "line");
                temps.Add(streamReader);
                temps.Add(line);

                tryBodyExprs.Add(
                    Expression.Assign(streamReader,
                                      Expression.New(CachedReflectionInfo.StreamReader_ctor, path)));
                var loopTest =
                    Expression.NotEqual(
                        Expression.Assign(line,
                                          Expression.Call(streamReader, CachedReflectionInfo.StreamReader_ReadLine)).Cast(typeof(object)),
                        ExpressionCache.NullConstant);

                tryBodyExprs.Add(avs.SaveAutomaticVar());
                tryBodyExprs.Add(GenerateWhileLoop(switchStatementAst.Label,
                                            () => loopTest,
                                            (loopBody, breakTarget, continueTarget) => switchBodyGenerator(loopBody, line)));
                var tryBlock = Expression.Block(tryBodyExprs);
                var finallyBlock = Expression.Block(
                    Expression.IfThen(
                        Expression.NotEqual(streamReader, ExpressionCache.NullConstant),
                        Expression.Call(streamReader.Cast(typeof(IDisposable)), CachedReflectionInfo.IDisposable_Dispose)),
                    avs.RestoreAutomaticVar());
                var exception = NewTemp(typeof(Exception), "exception");
                var catchAllBlock = Expression.Block(
                    tryBlock.Type,
                    Expression.Call(CachedReflectionInfo.CommandProcessorBase_CheckForSevereException, exception),
                    ThrowRuntimeErrorWithInnerException("FileReadError",
                                                        ParserStrings.FileReadError,
                                                        exception,
                                                        Expression.Property(exception, CachedReflectionInfo.Exception_Message)));

                exprs.Add(Expression.TryCatchFinally(
                    tryBlock, finallyBlock,
                    new[]
                    {
                        Expression.Catch(typeof(FlowControlException), Expression.Rethrow(tryBlock.Type)),
                        Expression.Catch(exception, catchAllBlock)
                    }));

                return Expression.Block(temps.Concat(avs.GetTemps()), exprs);
            }

            // We convert:
            //     switch ($enumerable) {}
            // Into:
            //     $switch = GetEnumerator $enumerable
            //     if ($switch == $null)
            //     {
            //         $switch  = (new object[] { $enumerable }).GetEnumerator()
            //     }
            // REVIEW: should we consider this form of switch a loop for the purposes of deciding
            // to compile or not?  I have a feeling the loop form is uncommon and compiling isn't worth it.

            var tryStmt = Expression.TryFinally(
                Expression.Block(
                    avs.SaveAutomaticVar(),
                    GenerateIteratorStatement(SpecialVariables.switchVarPath, () => UpdatePosition(switchStatementAst.Condition), _switchTupleIndex,
                                              switchStatementAst, switchBodyGenerator)
                    ),
                avs.RestoreAutomaticVar());

            return Expression.Block(temps.Concat(avs.GetTemps()), tryStmt);
        }
コード例 #5
0
ファイル: Compiler.cs プロジェクト: nickchal/pash
 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()) });
 }
コード例 #6
0
ファイル: Compiler.cs プロジェクト: nickchal/pash
 public object VisitTryStatement(TryStatementAst tryStatementAst)
 {
     List<ParameterExpression> temps = new List<ParameterExpression>();
     List<Expression> exprs = new List<Expression>();
     List<Expression> expressions = new List<Expression>();
     ParameterExpression item = this.NewTemp(typeof(bool), "oldActiveHandler");
     temps.Add(item);
     MemberExpression right = Expression.Property(_executionContextParameter, CachedReflectionInfo.ExecutionContext_ExceptionHandlerInEnclosingStatementBlock);
     exprs.Add(Expression.Assign(item, right));
     exprs.Add(Expression.Assign(right, ExpressionCache.Constant(true)));
     expressions.Add(Expression.Assign(right, item));
     this.CompileStatementListWithTraps(tryStatementAst.Body.Statements, tryStatementAst.Body.Traps, exprs, temps);
     List<CatchBlock> source = new List<CatchBlock>();
     if ((tryStatementAst.CatchClauses.Count == 1) && tryStatementAst.CatchClauses[0].IsCatchAll)
     {
         AutomaticVarSaver saver = new AutomaticVarSaver(this, SpecialVariables.UnderbarVarPath, 0);
         ParameterExpression expression = this.NewTemp(typeof(RuntimeException), "rte");
         ParameterExpression left = this.NewTemp(typeof(RuntimeException), "oldrte");
         NewExpression newValue = Expression.New(CachedReflectionInfo.ErrorRecord__ctor, new Expression[] { Expression.Property(expression, CachedReflectionInfo.RuntimeException_ErrorRecord), expression });
         List<Expression> list5 = new List<Expression> {
             Expression.Assign(left, _currentExceptionBeingHandled),
             Expression.Assign(_currentExceptionBeingHandled, expression),
             saver.SaveAutomaticVar(),
             saver.SetNewValue(newValue)
         };
         StatementBlockAst body = tryStatementAst.CatchClauses[0].Body;
         this.CompileStatementListWithTraps(body.Statements, body.Traps, list5, temps);
         TryExpression expression6 = Expression.TryFinally(Expression.Block(typeof(void), list5), Expression.Block(typeof(void), new Expression[] { saver.RestoreAutomaticVar(), Expression.Assign(_currentExceptionBeingHandled, left) }));
         source.Add(Expression.Catch(typeof(PipelineStoppedException), Expression.Rethrow()));
         source.Add(Expression.Catch(expression, Expression.Block(saver.GetTemps().Append<ParameterExpression>(left).ToArray<ParameterExpression>(), new Expression[] { expression6 })));
     }
     else if (tryStatementAst.CatchClauses.Any<CatchClauseAst>())
     {
         int num = 0;
         foreach (CatchClauseAst ast2 in tryStatementAst.CatchClauses)
         {
             num += Math.Max(ast2.CatchTypes.Count, 1);
         }
         Type[] typeArray = new Type[num];
         Expression array = Expression.Constant(typeArray);
         List<Expression> list7 = new List<Expression>();
         List<SwitchCase> list8 = new List<SwitchCase>();
         int i = 0;
         int index = 0;
         ParameterExpression expression8 = Expression.Parameter(typeof(RuntimeException));
         foreach (CatchClauseAst ast3 in tryStatementAst.CatchClauses)
         {
             if (ast3.IsCatchAll)
             {
                 typeArray[index] = typeof(ExceptionHandlingOps.CatchAll);
             }
             else
             {
                 foreach (TypeConstraintAst ast4 in ast3.CatchTypes)
                 {
                     typeArray[index] = ast4.TypeName.GetReflectionType();
                     if (typeArray[index] == null)
                     {
                         IndexExpression expression9 = Expression.ArrayAccess(array, new Expression[] { ExpressionCache.Constant(index) });
                         list7.Add(Expression.IfThen(Expression.Equal(expression9, ExpressionCache.NullType), Expression.Assign(expression9, Expression.Call(CachedReflectionInfo.TypeOps_ResolveTypeName, Expression.Constant(ast4.TypeName)))));
                     }
                     index++;
                 }
             }
             BlockExpression expression10 = Expression.Block(typeof(void), new Expression[] { this.Compile(ast3.Body) });
             if (ast3.IsCatchAll)
             {
                 list8.Add(Expression.SwitchCase(expression10, new Expression[] { ExpressionCache.Constant(i) }));
                 i++;
             }
             else
             {
                 list8.Add(Expression.SwitchCase(expression10, Enumerable.Range(i, i + ast3.CatchTypes.Count).Select<int, Expression>(new Func<int, Expression>(ExpressionCache.Constant))));
                 i += ast3.CatchTypes.Count;
             }
         }
         if (list7.Any<Expression>())
         {
             array = Expression.Block(list7.Append<Expression>(array));
         }
         AutomaticVarSaver saver2 = new AutomaticVarSaver(this, SpecialVariables.UnderbarVarPath, 0);
         MethodCallExpression switchValue = Expression.Call(CachedReflectionInfo.ExceptionHandlingOps_FindMatchingHandler, this.LocalVariablesParameter, expression8, array, _executionContextParameter);
         ParameterExpression expression12 = this.NewTemp(typeof(RuntimeException), "oldrte");
         TryExpression expression13 = Expression.TryFinally(Expression.Block(typeof(void), new Expression[] { Expression.Assign(expression12, _currentExceptionBeingHandled), Expression.Assign(_currentExceptionBeingHandled, expression8), saver2.SaveAutomaticVar(), Expression.Switch(switchValue, Expression.Call(CachedReflectionInfo.ExceptionHandlingOps_CheckActionPreference, _functionContext, expression8), list8.ToArray()) }), Expression.Block(saver2.RestoreAutomaticVar(), Expression.Assign(_currentExceptionBeingHandled, expression12)));
         source.Add(Expression.Catch(typeof(PipelineStoppedException), Expression.Rethrow()));
         source.Add(Expression.Catch(expression8, Expression.Block(saver2.GetTemps().Append<ParameterExpression>(expression12).ToArray<ParameterExpression>(), new Expression[] { expression13 })));
     }
     if (tryStatementAst.Finally != null)
     {
         ParameterExpression expression14 = this.NewTemp(typeof(bool), "oldIsStopping");
         temps.Add(expression14);
         expressions.Add(Expression.Assign(expression14, Expression.Call(CachedReflectionInfo.ExceptionHandlingOps_SuspendStoppingPipeline, _executionContextParameter)));
         List<Expression> list9 = new List<Expression>();
         this.CompileStatementListWithTraps(tryStatementAst.Finally.Statements, tryStatementAst.Finally.Traps, list9, temps);
         if (!list9.Any<Expression>())
         {
             list9.Add(ExpressionCache.Empty);
         }
         expressions.Add(Expression.Block(new Expression[] { Expression.TryFinally(Expression.Block(list9), Expression.Call(CachedReflectionInfo.ExceptionHandlingOps_RestoreStoppingPipeline, _executionContextParameter, expression14)) }));
     }
     if (!exprs.Last<Expression>().Type.Equals(typeof(void)))
     {
         exprs.Add(ExpressionCache.Empty);
     }
     if (source.Any<CatchBlock>())
     {
         return Expression.Block(temps.ToArray(), new Expression[] { Expression.TryCatchFinally(Expression.Block(exprs), Expression.Block(expressions), source.ToArray()) });
     }
     return Expression.Block(temps.ToArray(), new Expression[] { Expression.TryFinally(Expression.Block(exprs), Expression.Block(expressions)) });
 }
コード例 #7
0
ファイル: Compiler.cs プロジェクト: nickchal/pash
 public object VisitSwitchStatement(SwitchStatementAst switchStatementAst)
 {
     AutomaticVarSaver avs = new AutomaticVarSaver(this, SpecialVariables.UnderbarVarPath, 0);
     List<ParameterExpression> first = new List<ParameterExpression>();
     ParameterExpression item = null;
     if (switchStatementAst.Default != null)
     {
         item = this.NewTemp(typeof(bool), "skipDefault");
         first.Add(item);
     }
     Action<List<Expression>, Expression> switchBodyGenerator = this.GetSwitchBodyGenerator(switchStatementAst, avs, item);
     if ((switchStatementAst.Flags & SwitchFlags.File) != SwitchFlags.None)
     {
         List<Expression> expressions = new List<Expression>();
         ParameterExpression expression2 = this.NewTemp(typeof(string), "path");
         first.Add(expression2);
         expressions.Add(this.UpdatePosition(switchStatementAst.Condition));
         DynamicExpression expression3 = Expression.Dynamic(PSToStringBinder.Get(), typeof(string), this.CaptureStatementResults(switchStatementAst.Condition, CaptureAstContext.Assignment, null), _executionContextParameter);
         expressions.Add(Expression.Assign(expression2, Expression.Call(CachedReflectionInfo.SwitchOps_ResolveFilePath, Expression.Constant(switchStatementAst.Condition.Extent), expression3, _executionContextParameter)));
         List<Expression> list3 = new List<Expression>();
         ParameterExpression expression4 = this.NewTemp(typeof(StreamReader), "streamReader");
         ParameterExpression line = this.NewTemp(typeof(string), "line");
         first.Add(expression4);
         first.Add(line);
         list3.Add(Expression.Assign(expression4, Expression.New(CachedReflectionInfo.StreamReader_ctor, new Expression[] { expression2 })));
         BinaryExpression loopTest = Expression.NotEqual(Expression.Assign(line, Expression.Call(expression4, CachedReflectionInfo.StreamReader_ReadLine)).Cast(typeof(object)), ExpressionCache.NullConstant);
         list3.Add(avs.SaveAutomaticVar());
         list3.Add(this.GenerateWhileLoop(switchStatementAst.Label, () => loopTest, delegate (List<Expression> loopBody, LabelTarget breakTarget, LabelTarget continueTarget) {
             switchBodyGenerator(loopBody, line);
         }, null));
         BlockExpression body = Expression.Block(list3);
         BlockExpression @finally = Expression.Block(Expression.IfThen(Expression.NotEqual(expression4, ExpressionCache.NullConstant), Expression.Call(expression4.Cast(typeof(IDisposable)), CachedReflectionInfo.IDisposable_Dispose)), avs.RestoreAutomaticVar());
         ParameterExpression expression7 = this.NewTemp(typeof(Exception), "exception");
         BlockExpression expression8 = Expression.Block(body.Type, new Expression[] { Expression.Call(CachedReflectionInfo.CommandProcessorBase_CheckForSevereException, expression7), ThrowRuntimeErrorWithInnerException("FileReadError", ParserStrings.FileReadError, expression7, new Expression[] { Expression.Property(expression7, CachedReflectionInfo.Exception_Message) }) });
         expressions.Add(Expression.TryCatchFinally(body, @finally, new CatchBlock[] { Expression.Catch(typeof(FlowControlException), Expression.Rethrow(body.Type)), Expression.Catch(expression7, expression8) }));
         return Expression.Block(first.Concat<ParameterExpression>(avs.GetTemps()), expressions);
     }
     TryExpression expression9 = Expression.TryFinally(Expression.Block(avs.SaveAutomaticVar(), this.GenerateIteratorStatement(SpecialVariables.switchVarPath, () => this.UpdatePosition(switchStatementAst.Condition), this._switchTupleIndex, switchStatementAst, switchBodyGenerator)), avs.RestoreAutomaticVar());
     return Expression.Block(first.Concat<ParameterExpression>(avs.GetTemps()), new Expression[] { expression9 });
 }
コード例 #8
0
ファイル: Compiler.cs プロジェクト: nickchal/pash
 private Action<List<Expression>, Expression> GetSwitchBodyGenerator(SwitchStatementAst switchStatementAst, AutomaticVarSaver avs, ParameterExpression skipDefault)
 {
     return delegate (List<Expression> exprs, Expression newValue) {
         PSSwitchClauseEvalBinder binder = PSSwitchClauseEvalBinder.Get(switchStatementAst.Flags);
         exprs.Add(avs.SetNewValue(newValue));
         if (skipDefault != null)
         {
             exprs.Add(Expression.Assign(skipDefault, ExpressionCache.Constant(false)));
         }
         IsConstantValueVisitor visitor = new IsConstantValueVisitor();
         ConstantValueVisitor visitor2 = new ConstantValueVisitor();
         int count = switchStatementAst.Clauses.Count;
         for (int j = 0; j < count; j++)
         {
             Expression expression;
             Tuple<ExpressionAst, StatementBlockAst> tuple = switchStatementAst.Clauses[j];
             object obj2 = ((bool) tuple.Item1.Accept(visitor)) ? tuple.Item1.Accept(visitor2) : null;
             if (obj2 is ScriptBlock)
             {
                 MethodCallExpression expression2 = Expression.Call(Expression.Constant(obj2), CachedReflectionInfo.ScriptBlock_DoInvokeReturnAsIs, new Expression[] { ExpressionCache.Constant(true), Expression.Constant(ScriptBlock.ErrorHandlingBehavior.WriteToExternalErrorPipe), this.GetLocal(0).Convert(typeof(object)), ExpressionCache.AutomationNullConstant, ExpressionCache.AutomationNullConstant, ExpressionCache.NullObjectArray });
                 expression = Expression.Dynamic(PSConvertBinder.Get(typeof(bool)), typeof(bool), expression2);
             }
             else if (obj2 != null)
             {
                 SwitchFlags flags = switchStatementAst.Flags;
                 Expression expression3 = Expression.Constant(((obj2 is Regex) || (obj2 is WildcardPattern)) ? obj2 : obj2.ToString());
                 Expression expression4 = Expression.Dynamic(PSToStringBinder.Get(), typeof(string), this.GetLocal(0), _executionContextParameter);
                 if (((flags & SwitchFlags.Regex) != SwitchFlags.None) || (obj2 is Regex))
                 {
                     expression = Expression.Call(CachedReflectionInfo.SwitchOps_ConditionSatisfiedRegex, ExpressionCache.Constant((flags & SwitchFlags.CaseSensitive) != SwitchFlags.None), expression3, Expression.Constant(tuple.Item1.Extent), expression4, _executionContextParameter);
                 }
                 else if (((flags & SwitchFlags.Wildcard) != SwitchFlags.None) || (obj2 is WildcardPattern))
                 {
                     expression = Expression.Call(CachedReflectionInfo.SwitchOps_ConditionSatisfiedWildcard, ExpressionCache.Constant((flags & SwitchFlags.CaseSensitive) != SwitchFlags.None), expression3, expression4, _executionContextParameter);
                 }
                 else
                 {
                     expression = CallStringEquals(expression3, expression4, (flags & SwitchFlags.CaseSensitive) == SwitchFlags.None);
                 }
             }
             else
             {
                 Expression expression5 = this.Compile(tuple.Item1);
                 expression = Expression.Dynamic(binder, typeof(bool), expression5, this.GetLocal(0), _executionContextParameter);
             }
             exprs.Add(this.UpdatePosition(tuple.Item1));
             if (skipDefault != null)
             {
                 exprs.Add(Expression.IfThen(expression, Expression.Block(this.Compile(tuple.Item2), Expression.Assign(skipDefault, ExpressionCache.Constant(true)))));
             }
             else
             {
                 exprs.Add(Expression.IfThen(expression, this.Compile(tuple.Item2)));
             }
         }
         if (skipDefault != null)
         {
             exprs.Add(Expression.IfThen(Expression.Not(skipDefault), this.Compile(switchStatementAst.Default)));
         }
     };
 }