예제 #1
0
        // when [<expr>, ...] *<array>
        //
        // generates this code:
        //
        // IEnumerator<object>/*!*/ enumVar = RubyOps.Unsplat(<array>).GetEnumerator();
        // bool result = false;
        // while (enumVar.MoveNext()) {
        //     if (<MakeTest>(enumVar.Current)) {
        //         result = true;
        //         break;
        //     }
        // }
        private static MSA.Expression /*!*/ MakeArrayTest(AstGenerator /*!*/ gen, MSA.Expression /*!*/ array, MSA.Expression value)
        {
            MSA.Expression enumVariable   = gen.CurrentScope.DefineHiddenVariable("#case-enumerator", typeof(IEnumerator <object>));
            MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#case-compare-result", typeof(bool));

            MSA.LabelTarget label = Ast.Label();
            return(AstFactory.Block(
                       Ast.Assign(enumVariable, Ast.Call(
                                      Methods.Unsplat.OpCall(AstFactory.Box(array)),
                                      Methods.IEnumerable_Of_Object_GetEnumerator
                                      )),

                       Ast.Assign(resultVariable, Ast.Constant(false)),

                       AstUtils.While(
                           Ast.Call(enumVariable, Methods.IEnumerator_MoveNext),
                           AstUtils.If(
                               MakeTest(gen, Ast.Call(enumVariable, Methods.IEnumerator_get_Current), value),
                               Ast.Block(
                                   Ast.Assign(resultVariable, Ast.Constant(true)),
                                   Ast.Break(label),
                                   Ast.Empty()
                                   )
                               ),
                           null,
                           label,
                           null
                           ),
                       resultVariable
                       ));
        }
예제 #2
0
 internal override MSAst.Expression Transform(MSAst.Expression body)
 {
     return(GlobalParent.AddDebugInfoAndVoid(
                AstUtils.If(
                    GlobalParent.Convert(typeof(bool), ConversionResultKind.ExplicitCast, Test),
                    body
                    ),
                Span
                ));
 }
        protected override Expression VisitTry(TryExpression node)
        {
            MSAst.Expression b = Visit(node.Body);
            ReadOnlyCollection <CatchBlock> h = Visit(node.Handlers, VisitCatchBlock);

            MSAst.Expression y = Visit(node.Finally);
            MSAst.Expression f;

            _insideConditionalBlock = true;
            try {
                f = Visit(node.Fault);
            } finally {
                _insideConditionalBlock = false;
            }

            node = Ast.MakeTry(node.Type, b, y, f, h);

            List <MSAst.CatchBlock> newHandlers = null;

            MSAst.Expression newFinally = null;

            // If the TryStatement has any Catch blocks we need to insert the exception
            // event as a first statement so that we can be notified of first-chance exceptions.
            if (node.Handlers != null && node.Handlers.Count > 0)
            {
                newHandlers = new List <CatchBlock>();

                foreach (var catchBlock in node.Handlers)
                {
                    ParameterExpression exceptionVar = catchBlock.Variable ?? Ast.Parameter(catchBlock.Test, null);

                    Expression debugMarker, thread;
                    if (_transformToGenerator)
                    {
                        debugMarker = Ast.Call(
                            typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.GetCurrentSequencePointForGeneratorFrame)),
                            _frame
                            );

                        thread = Ast.Call(typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.GetThread)), _frame);
                    }
                    else
                    {
                        debugMarker = _debugMarker;
                        thread      = _thread;
                    }

                    MSAst.Expression exceptionEvent = Ast.Block(
                        // Rethrow ForceToGeneratorLoopException
                        AstUtils.If(
                            Ast.TypeIs(
                                exceptionVar,
                                typeof(ForceToGeneratorLoopException)
                                ),
                            Ast.Throw(exceptionVar)
                            ),
                        AstUtils.If(
                            Ast.Equal(_globalDebugMode, AstUtils.Constant((int)DebugMode.FullyEnabled)),
                            _pushFrame ?? Ast.Empty(),
                            Ast.Call(
                                typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.OnTraceEvent)),
                                thread,
                                debugMarker,
                                exceptionVar
                                )
                            )
                        );

                    newHandlers.Add(Ast.MakeCatchBlock(
                                        catchBlock.Test,
                                        exceptionVar,
                                        Ast.Block(
                                            exceptionEvent,
                                            catchBlock.Body
                                            ),
                                        catchBlock.Filter
                                        ));
                }
            }

            if (!_transformToGenerator && node.Finally != null)
            {
                // Prevent the user finally block from running if the frame is currently remapping to generator
                newFinally = AstUtils.If(
                    Ast.Not(
                        Ast.Call(
                            typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.IsCurrentLeafFrameRemappingToGenerator)),
                            _thread
                            )
                        ),
                    node.Finally
                    );
            }

            if (newHandlers != null || newFinally != null)
            {
                node = Ast.MakeTry(
                    node.Type,
                    node.Body,
                    newFinally ?? node.Finally,
                    node.Fault,
                    newHandlers != null ? (IEnumerable <CatchBlock>)newHandlers : node.Handlers
                    );
            }

            return(node);
        }
예제 #4
0
        // see Ruby Language.doc/Runtime/Control Flow Implementation/While-Until
        internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen)
        {
            MSA.Expression          resultVariable = gen.CurrentScope.DefineHiddenVariable("#loop-result", typeof(object));
            MSA.Expression          redoVariable   = gen.CurrentScope.DefineHiddenVariable("#skip-condition", typeof(bool));
            MSA.ParameterExpression blockUnwinder  = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(BlockUnwinder));
            MSA.ParameterExpression evalUnwinder   = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(EvalUnwinder));

            bool isInnerLoop = gen.CurrentLoop != null;

            MSA.LabelTarget breakLabel    = Ast.Label();
            MSA.LabelTarget continueLabel = Ast.Label();

            gen.EnterLoop(redoVariable, resultVariable, breakLabel, continueLabel);
            MSA.Expression transformedBody      = gen.TransformStatements(_statements, ResultOperation.Ignore);
            MSA.Expression transformedCondition = AstFactory.IsTrue(_condition.TransformRead(gen));
            gen.LeaveLoop();

            MSA.Expression conditionPositiveStmt, conditionNegativeStmt;
            if (_isWhileLoop)
            {
                conditionPositiveStmt = Ast.Empty();
                conditionNegativeStmt = Ast.Break(breakLabel);
            }
            else
            {
                conditionPositiveStmt = Ast.Break(breakLabel);
                conditionNegativeStmt = Ast.Empty();
            }

            // make the loop first:
            MSA.Expression loop = Ast.Block(
                Ast.Assign(redoVariable, Ast.Constant(_isPostTest)),

                AstFactory.Infinite(breakLabel, continueLabel,
                                    AstUtils.Try(

                                        AstUtils.If(redoVariable,
                                                    Ast.Assign(redoVariable, Ast.Constant(false))
                                                    ).ElseIf(transformedCondition,
                                                             conditionPositiveStmt
                                                             ).Else(
                                            conditionNegativeStmt
                                            ),

                                        transformedBody

                                        ).Catch(blockUnwinder,
                                                // redo = u.IsRedo
                                                Ast.Assign(redoVariable, Ast.Field(blockUnwinder, BlockUnwinder.IsRedoField))

                                                ).Filter(evalUnwinder, Ast.Equal(Ast.Field(evalUnwinder, EvalUnwinder.ReasonField), AstFactory.BlockReturnReasonBreak),
                                                         // result = unwinder.ReturnValue
                                                         Ast.Assign(resultVariable, Ast.Field(evalUnwinder, EvalUnwinder.ReturnValueField)),
                                                         Ast.Break(breakLabel)
                                                         )
                                    ),
                Ast.Empty()
                );

            // wrap it to try finally that updates RFC state:
            if (!isInnerLoop)
            {
                loop = AstUtils.Try(
                    Ast.Assign(Ast.Field(gen.CurrentRfcVariable, RuntimeFlowControl.InLoopField), Ast.Constant(true)),
                    loop
                    ).Finally(
                    Ast.Assign(Ast.Field(gen.CurrentRfcVariable, RuntimeFlowControl.InLoopField), Ast.Constant(false))
                    );
            }

            return(AstFactory.Block(loop, resultVariable));
        }