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))); }
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))); } }; }
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())); }
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); }
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()) }); }
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)) }); }
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 }); }
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))); } }; }