private Expression RewriteCallable <TException>(TException node, Expression[] arguments, Converter <TException, Expression> visitor, Func <TException, Expression[], TException> updater)
            where TException : Expression
        {
            var codeInsertionPoint = context.CurrentStatement.PrologueCodeInserter();
            var newNode            = visitor(node);

            if (newNode is TException typedExpr)
            {
                node = typedExpr;
            }
            else
            {
                return(newNode);
            }
            var hasAwait = false;

            for (var i = arguments.LongLength - 1L; i >= 0L; i--)
            {
                ref Expression arg = ref arguments[i];
                if (hasAwait |= ExpressionAttributes.Get(arg)?.ContainsAwait ?? false)
                {
                    var tempVar = NewStateSlot(arg.Type);
                    codeInsertionPoint(Expression.Assign(tempVar, arg));
                    arg = tempVar;
                }
            }
Esempio n. 2
0
 private void AttachLabel(LabelTarget?target)
 {
     if (target is not null)
     {
         ExpressionAttributes.Get(CurrentStatement)?.Labels.Add(target);
         target.GetUserData().GetOrSet(StateIdPlaceholder).StateId = stateId;
     }
 }
Esempio n. 3
0
 private void ContainsAwait()
 {
     foreach (var attr in attributes)
     {
         if (ReferenceEquals(ExpressionAttributes.Get(CurrentStatement), attr))
         {
             return;
         }
         attr.ContainsAwait = true;
     }
 }
Esempio n. 4
0
        protected override Expression VisitChildren(ExpressionVisitor visitor)
        {
            var filter = visitor.Visit(this.filter);

            if (ExpressionAttributes.Get(filter)?.ContainsAwait ?? false)
            {
                throw new NotSupportedException(ExceptionMessages.FilterHasAwait);
            }
            var handler = visitor.Visit(Content);

            handler = handler.AddPrologue(false, prologue).AddEpilogue(false, epilogue).AddEpilogue(false, FaultLabel.Goto());
            return(IfThen(filter, handler));
        }
        protected override Expression VisitConditional(ConditionalExpression node)
        {
            if (node.Type == typeof(void))
            {
                node = node.Update(node.Test, Statement.Wrap(node.IfTrue), Statement.Wrap(node.IfFalse));
                return(context.Rewrite(node, base.VisitConditional));
            }
            else if (node.IfTrue is BlockExpression && node.IfFalse is BlockExpression)
            {
                throw new NotSupportedException(ExceptionMessages.UnsupportedConditionalExpr);
            }
            else
            {
                /*
                 *  x = a ? await b() : c();
                 *  --transformed into--
                 *  var temp;
                 *  if(a)
                 *      temp = await b();
                 *  else
                 *      temp = c();
                 *  x = temp;
                 */
                var prologue = context.CurrentStatement.PrologueCodeInserter();
                {
                    var result = context.Rewrite(node, base.VisitConditional);
                    if (result is ConditionalExpression conditional)
                    {
                        node = conditional;
                    }
                    else
                    {
                        return(result);
                    }
                }

                if ((ExpressionAttributes.Get(node.IfTrue)?.ContainsAwait ?? false) || (ExpressionAttributes.Get(node.IfFalse)?.ContainsAwait ?? false))
                {
                    var tempVar = NewStateSlot(node.Type);
                    prologue(Expression.Condition(node.Test, Expression.Assign(tempVar, node.IfTrue), Expression.Assign(tempVar, node.IfFalse), typeof(void)));
                    return(tempVar);
                }
                else
                {
                    return(node);
                }
            }
        }
        private Expression RewriteBinary(BinaryExpression node)
        {
            var codeInsertionPoint = context.CurrentStatement.PrologueCodeInserter();
            var newNode            = base.VisitBinary(node);

            if (newNode is BinaryExpression binary)
            {
                node = binary;
            }
            else
            {
                return(newNode);
            }

            // do not place left operand at statement level because it has no side effects
            if (node.Left is ParameterExpression || node.Left is ConstantExpression || IsAssignment(node))
            {
                return(node);
            }
            var leftIsAsync  = ExpressionAttributes.Get(node.Left)?.ContainsAwait ?? false;
            var rightIsAsync = ExpressionAttributes.Get(node.Right)?.ContainsAwait ?? false;

            // left operand should be computed before right, so bump it before await expression
            if (rightIsAsync && !leftIsAsync)
            {
                /*
                 *  Method() + await a;
                 *  --transformed into--
                 *  state.field = Method();
                 *  state.awaiter = a.GetAwaiter();
                 *  MoveNext(state.awaiter, newState);
                 *  return;
                 *  newState: state.field + state.awaiter.GetResult();
                 */
                var leftTemp = NewStateSlot(node.Left.Type);
                codeInsertionPoint(Expression.Assign(leftTemp, node.Left));
                node = node.Update(leftTemp, node.Conversion, node.Right);
            }

            return(node);
        }
Esempio n. 7
0
        internal IReadOnlyCollection <Expression> CreateJumpPrologue(GotoExpression @goto, ExpressionVisitor visitor)
        {
            var state  = @goto.Target.GetUserData().GetOrSet(StateIdPlaceholder);
            var result = new LinkedList <Expression>();

            // iterate through snapshot of statements because collection can be modified
            var statements = this.statements.ToArray();

            foreach (var lookup in statements)
            {
                if (ExpressionAttributes.Get(lookup)?.Labels.Contains(@goto.Target) ?? false)
                {
                    break;
                }
                if (lookup is TryCatchFinallyStatement statement)
                {
                    result.AddLast(statement.InlineFinally(visitor, state));
                }
            }

            Array.Clear(statements, 0, statements.Length);
            return(result);
        }