private Expression CompileAssignment( AssignmentStatementAst assignmentStatementAst, MergeRedirectExprs generateRedirectExprs = null) { var arrayLHS = assignmentStatementAst.Left as ArrayLiteralAst; var parenExpressionAst = assignmentStatementAst.Left as ParenExpressionAst; if (parenExpressionAst != null) { arrayLHS = parenExpressionAst.Pipeline.GetPureExpression() as ArrayLiteralAst; } // If assigning to an array, then we prefer an enumerable result because we use an IList // to generate the assignments, no sense in converting to object[], or worse, returning a // single object. // We should not preserve the partial output if exception is thrown when evaluating right-hand-side expression. Expression rightExpr = CaptureStatementResults(assignmentStatementAst.Right, arrayLHS != null ? CaptureAstContext.Enumerable : CaptureAstContext.AssignmentWithoutResultPreservation, generateRedirectExprs); if (arrayLHS != null) { rightExpr = DynamicExpression.Dynamic(PSArrayAssignmentRHSBinder.Get(arrayLHS.Elements.Count), typeof(IList), rightExpr); } var exprs = new List<Expression> { // Set current position in case of errors. UpdatePosition(assignmentStatementAst), ReduceAssignment((ISupportsAssignment)assignmentStatementAst.Left, assignmentStatementAst.Operator, rightExpr) }; return Expression.Block(exprs); }
private Expression CaptureStatementResultsHelper( StatementAst stmt, CaptureAstContext context, MergeRedirectExprs generateRedirectExprs) { var commandExpressionAst = stmt as CommandExpressionAst; if (commandExpressionAst != null) { if (commandExpressionAst.Redirections.Count > 0) { return GetRedirectedExpression(commandExpressionAst, captureForInput: true); } return Compile(commandExpressionAst.Expression); } var assignmentStatementAst = stmt as AssignmentStatementAst; if (assignmentStatementAst != null) { var expr = Compile(assignmentStatementAst); if (stmt.Parent is StatementBlockAst) { expr = Expression.Block(expr, ExpressionCache.Empty); } return expr; } var pipelineAst = stmt as PipelineAst; if (pipelineAst != null) { var expr = pipelineAst.GetPureExpression(); if (expr != null) { return Compile(expr); } } return CaptureAstResults(stmt, context, generateRedirectExprs); }
private Expression CaptureStatementResults( StatementAst stmt, CaptureAstContext context, MergeRedirectExprs generateRedirectExprs = null) { var result = CaptureStatementResultsHelper(stmt, context, generateRedirectExprs); // If we're generating code for a condition and the condition contains some command invocation, // we want to be sure that $? is set to true even if the condition fails, e.g.: // if (get-command foo -ea SilentlyContinue) { foo } // $? # never $false here // Many conditions don't invoke commands though, and in trivial empty loops, setting $? = $true // does have a measurable impact, so only set $? = $true if the condition might change $? to $false. // We do this after evaluating the condition so that you could do something like: // if ((dir file1,file2 -ea SilentlyContinue) -and $?) { <# files both exist, otherwise $? would be $false if 0 or 1 files existed #> } if (context == CaptureAstContext.Condition && AstSearcher.FindFirst(stmt, ast => ast is CommandAst, searchNestedScriptBlocks: false) != null) { var tmp = NewTemp(result.Type, "condTmp"); result = Expression.Block(new[] { tmp }, Expression.Assign(tmp, result), s_setDollarQuestionToTrue, tmp); } return result; }
private Expression CaptureAstResults( Ast ast, CaptureAstContext context, MergeRedirectExprs generateRedirectExprs = null) { Expression result; // We'll generate code like: // try { // oldPipe = funcContext.OutputPipe; // resultList = new List<object>(); // resultListPipe = new Pipe(resultList); // funcContext.OutputPipe = resultListPipe; // <optionally add merge redirection expressions> // expression... // } finally { // FlushPipe(oldPipe, resultList); // funcContext.OutputPipe = oldPipe; // } var temps = new List<ParameterExpression>(); var exprs = new List<Expression>(); var catches = new List<CatchBlock>(); var finallyExprs = new List<Expression>(); var oldPipe = NewTemp(typeof(Pipe), "oldPipe"); var resultList = NewTemp(typeof(List<object>), "resultList"); temps.Add(resultList); temps.Add(oldPipe); exprs.Add(Expression.Assign(oldPipe, s_getCurrentPipe)); exprs.Add(Expression.Assign(resultList, Expression.New(CachedReflectionInfo.ObjectList_ctor))); exprs.Add(Expression.Assign(s_getCurrentPipe, Expression.New(CachedReflectionInfo.Pipe_ctor, resultList))); exprs.Add(Expression.Call(oldPipe, CachedReflectionInfo.Pipe_SetVariableListForTemporaryPipe, s_getCurrentPipe)); if (generateRedirectExprs != null) { // Add merge redirection expressions if delegate is provided. generateRedirectExprs(exprs, finallyExprs); } exprs.Add(Compile(ast)); switch (context) { case CaptureAstContext.AssignmentWithResultPreservation: case CaptureAstContext.AssignmentWithoutResultPreservation: result = Expression.Call(CachedReflectionInfo.PipelineOps_PipelineResult, resultList); // Clear the temporary pipe in case of exception, if we are not required to preserve the results if (context == CaptureAstContext.AssignmentWithoutResultPreservation) { var catchExprs = new List<Expression> { Expression.Call(CachedReflectionInfo.PipelineOps_ClearPipe, resultList), Expression.Rethrow(), Expression.Constant(null, typeof (object)) }; catches.Add(Expression.Catch(typeof(RuntimeException), Expression.Block(typeof(object), catchExprs))); } // PipelineResult might get skipped in some circumstances due to a FlowControlException thrown out, in which case // we write to the oldPipe. This can happen in cases like: // $(1;2;return 3) finallyExprs.Add(Expression.Call(CachedReflectionInfo.PipelineOps_FlushPipe, oldPipe, resultList)); break; case CaptureAstContext.Condition: result = DynamicExpression.Dynamic(PSPipelineResultToBoolBinder.Get(), typeof(bool), resultList); break; case CaptureAstContext.Enumerable: result = resultList; break; default: throw new ArgumentOutOfRangeException("context"); } finallyExprs.Add(Expression.Assign(s_getCurrentPipe, oldPipe)); exprs.Add(result); if (catches.Count > 0) { return Expression.Block( temps.ToArray(), Expression.TryCatchFinally(Expression.Block(exprs), Expression.Block(finallyExprs), catches.ToArray())); } return Expression.Block( temps.ToArray(), Expression.TryFinally(Expression.Block(exprs), Expression.Block(finallyExprs))); }
private Expression CompileAssignment(AssignmentStatementAst assignmentStatementAst, MergeRedirectExprs generateRedirectExprs = null) { ArrayLiteralAst left = assignmentStatementAst.Left as ArrayLiteralAst; if (assignmentStatementAst.Left is ParenExpressionAst) { left = ((ParenExpressionAst) assignmentStatementAst.Left).Pipeline.GetPureExpression() as ArrayLiteralAst; } Expression expression = this.CaptureStatementResults(assignmentStatementAst.Right, (left != null) ? CaptureAstContext.Enumerable : CaptureAstContext.Assignment, generateRedirectExprs); if (left != null) { expression = Expression.Dynamic(PSArrayAssignmentRHSBinder.Get(left.Elements.Count), typeof(IList), expression); } List<Expression> expressions = new List<Expression> { this.UpdatePosition(assignmentStatementAst), this.ReduceAssignment((ISupportsAssignment) assignmentStatementAst.Left, assignmentStatementAst.Operator, expression) }; return Expression.Block(expressions); }
private Expression CaptureStatementResultsHelper(StatementAst stmt, CaptureAstContext context, MergeRedirectExprs generateRedirectExprs) { CommandExpressionAst commandExpr = stmt as CommandExpressionAst; if (commandExpr != null) { if (commandExpr.Redirections.Any<RedirectionAst>()) { return this.GetRedirectedExpression(commandExpr, true); } return this.Compile(commandExpr.Expression); } AssignmentStatementAst ast = stmt as AssignmentStatementAst; if (ast != null) { Expression expression = this.Compile(ast); if (stmt.Parent is StatementBlockAst) { expression = Expression.Block(expression, ExpressionCache.Empty); } return expression; } PipelineAst ast3 = stmt as PipelineAst; if (ast3 != null) { ExpressionAst pureExpression = ast3.GetPureExpression(); if (pureExpression != null) { return this.Compile(pureExpression); } } return this.CaptureAstResults(stmt, context, generateRedirectExprs); }
private Expression CaptureStatementResults(StatementAst stmt, CaptureAstContext context, MergeRedirectExprs generateRedirectExprs = null) { Expression right = this.CaptureStatementResultsHelper(stmt, context, generateRedirectExprs); if ((context == CaptureAstContext.Condition) && (AstSearcher.FindFirst(stmt, ast => ast is CommandAst, false) != null)) { ParameterExpression left = this.NewTemp(right.Type, "condTmp"); right = Expression.Block(new ParameterExpression[] { left }, new Expression[] { Expression.Assign(left, right), _setDollarQuestionToTrue, left }); } return right; }
private Expression CaptureAstResults(Ast ast, CaptureAstContext context, MergeRedirectExprs generateRedirectExprs = null) { Expression expression; List<ParameterExpression> list = new List<ParameterExpression>(); List<Expression> exprs = new List<Expression>(); List<Expression> finallyExprs = new List<Expression>(); ParameterExpression item = this.NewTemp(typeof(Pipe), "oldPipe"); ParameterExpression expression3 = this.NewTemp(typeof(ArrayList), "arrayList"); list.Add(expression3); list.Add(item); exprs.Add(Expression.Assign(item, _getCurrentPipe)); exprs.Add(Expression.Assign(expression3, Expression.New(CachedReflectionInfo.ArrayList_ctor))); exprs.Add(Expression.Assign(_getCurrentPipe, Expression.New(CachedReflectionInfo.Pipe_ctor, new Expression[] { expression3 }))); if (generateRedirectExprs != null) { generateRedirectExprs(exprs, finallyExprs); } exprs.Add(this.Compile(ast)); switch (context) { case CaptureAstContext.Assignment: expression = Expression.Call(CachedReflectionInfo.PipelineOps_PipelineResult, expression3); finallyExprs.Add(Expression.Call(CachedReflectionInfo.PipelineOps_FlushPipe, item, expression3)); break; case CaptureAstContext.Condition: expression = Expression.Dynamic(PSPipelineResultToBoolBinder.Get(), typeof(bool), expression3); break; case CaptureAstContext.Enumerable: expression = expression3; break; default: throw new ArgumentOutOfRangeException("context"); } finallyExprs.Add(Expression.Assign(_getCurrentPipe, item)); exprs.Add(expression); return Expression.Block(list.ToArray(), new Expression[] { Expression.TryFinally(Expression.Block(exprs), Expression.Block(finallyExprs)) }); }