Exemple #1
0
        private MSA.Expression /*!*/ MakeParametersInitialization(AstGenerator /*!*/ gen, MSA.Expression[] /*!*/ parameters)
        {
            Assert.NotNull(gen);
            Assert.NotNullItems(parameters);

            var result = AstFactory.CreateExpressionArray(
                _parameters.LeftValues.Count +
                (_parameters.UnsplattedValue != null ? 1 : 0) +
                1
                );

            int resultIndex = 0;

            bool paramsInArray = HasFormalParametersInArray;

            for (int i = 0; i < _parameters.LeftValues.Count; i++)
            {
                var parameter = paramsInArray ?
                                Ast.ArrayAccess(parameters[HiddenParameterCount], Ast.Constant(i)) :
                                parameters[HiddenParameterCount + i];

                result[resultIndex++] = _parameters.LeftValues[i].TransformWrite(gen, parameter);
            }

            if (_parameters.UnsplattedValue != null)
            {
                // the last parameter is unsplat:
                var parameter = parameters[parameters.Length - 1];
                result[resultIndex++] = _parameters.UnsplattedValue.TransformWrite(gen, parameter);
            }

            result[resultIndex++] = Ast.Empty();
            Debug.Assert(resultIndex == result.Length);
            return(AstFactory.Block(result));
        }
Exemple #2
0
        // see Ruby Language.doc/Runtime/Control Flow Implementation/Break
        internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen)
        {
            MSA.Expression transformedReturnValue = TransformReturnValue(gen);

            // eval:
            if (gen.CompilerOptions.IsEval)
            {
                return(Methods.EvalBreak.OpCall(gen.CurrentRfcVariable, AstFactory.Box(transformedReturnValue)));
            }

            // loop:
            if (gen.CurrentLoop != null)
            {
                return(Ast.Block(
                           Ast.Assign(
                               gen.CurrentLoop.ResultVariable,
                               Ast.Convert(transformedReturnValue, gen.CurrentLoop.ResultVariable.Type)
                               ),
                           Ast.Break(gen.CurrentLoop.BreakLabel),
                           Ast.Empty()
                           ));
            }

            // block:
            if (gen.CurrentBlock != null)
            {
                return(gen.Return(Methods.BlockBreak.OpCall(gen.CurrentBlock.BfcVariable, AstFactory.Box(transformedReturnValue))));
            }

            // primary frame:
            return(Methods.MethodBreak.OpCall(AstFactory.Box(transformedReturnValue)));
        }
Exemple #3
0
        internal MSA.Expression /*!*/ TransformOptionalsInitialization(AstGenerator /*!*/ gen)
        {
            Assert.NotNull(gen);

            if (_optional == null)
            {
                return(Ast.Empty());
            }

            MSA.Expression singleton = gen.CurrentScope.DefineHiddenVariable("#default", typeof(object));

            MSA.Expression result = Ast.Empty();
            for (int i = 0; i < _optional.Count; i++)
            {
                result = AstUtils.IfThen(Ast.Equal(_optional[i].Left.TransformRead(gen), singleton),
                                         result,
                                         _optional[i].TransformRead(gen)
                                         );
            }

            return(Ast.Block(
                       Ast.Assign(singleton, Ast.Field(null, Fields.RubyOps_DefaultArgumentField)),
                       result,
                       Ast.Empty()
                       ));
        }
Exemple #4
0
        internal static MSA.Expression /*!*/ TransformRetry(AstGenerator /*!*/ gen)
        {
            // eval:
            if (gen.CompilerOptions.IsEval)
            {
                return(Methods.EvalRetry.OpCall(gen.CurrentRfcVariable));
            }

            // rescue clause:
            if (gen.CurrentRescue != null)
            {
                return(Ast.Block(
                           Ast.Assign(gen.CurrentRescue.RetryingVariable, Ast.Constant(true)),
                           Ast.Continue(gen.CurrentRescue.ContinueLabel),
                           Ast.Empty()
                           ));
            }

            // block:
            if (gen.CurrentBlock != null)
            {
                return(gen.Return(Methods.BlockRetry.OpCall(gen.CurrentBlock.BfcVariable)));
            }

            // primary frame:
            return(gen.Return(Methods.MethodRetry.OpCall(gen.CurrentRfcVariable, gen.MakeMethodBlockParameterRead())));
        }
        // 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
                       ));
        }
Exemple #6
0
        // see Ruby Language.doc/Runtime/Control Flow Implementation/Redo
        internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen)
        {
            // eval:
            if (gen.CompilerOptions.IsEval)
            {
                return(Methods.EvalRedo.OpCall(gen.CurrentRfcVariable));
            }

            // loop:
            if (gen.CurrentLoop != null)
            {
                return(Ast.Block(
                           Ast.Assign(gen.CurrentLoop.RedoVariable, Ast.Constant(true)),
                           Ast.Continue(gen.CurrentLoop.ContinueLabel),
                           Ast.Empty()
                           ));
            }

            // block:
            if (gen.CurrentBlock != null)
            {
                return(Ast.Continue(gen.CurrentBlock.RedoLabel));
            }

            // method:
            return(Methods.MethodRedo.OpCall(gen.CurrentRfcVariable));
        }
Exemple #7
0
        public Expression CreateRule()
        {
            if (_binding == null)
            {
                if (_test == null)
                {
                    throw Error.MissingTest();
                }
                if (_target == null)
                {
                    throw Error.MissingTarget();
                }

                _binding = Expression.Block(
                    _temps != null ? _temps.ToArray() : new ParameterExpression[0],
                    Expression.Condition(
                        _test,
                        AstUtils.Convert(_target, typeof(void)),
                        Ast.Empty()
                        )
                    );
            }

            return(_binding);
        }
Exemple #8
0
        // see Ruby Language.doc/Runtime/Control Flow Implementation/Next
        internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen)
        {
            MSA.Expression transformedReturnValue = TransformReturnValue(gen);

            // eval:
            if (gen.CompilerOptions.IsEval)
            {
                return(Methods.EvalNext.OpCall(gen.CurrentRfcVariable, AstFactory.Box(transformedReturnValue)));
            }

            // loop:
            if (gen.CurrentLoop != null)
            {
                return(Ast.Block(
                           transformedReturnValue, // evaluate for side-effects
                           Ast.Continue(gen.CurrentLoop.ContinueLabel),
                           Ast.Empty()
                           ));
            }

            // block:
            if (gen.CurrentBlock != null)
            {
                return(gen.Return(transformedReturnValue));
            }

            // method:
            return(Methods.MethodNext.OpCall(gen.CurrentRfcVariable, AstFactory.Box(transformedReturnValue)));
        }
        internal sealed override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen)
        {
            string debugString = (IsSingletonDeclaration) ? "SINGLETON" : ((this is ClassDeclaration) ? "CLASS" : "MODULE") + " " + QualifiedName.Name;

            ScopeBuilder outerLocals = gen.CurrentScope;

            // definition needs to take place outside the defined lexical scope:
            MSA.Expression definition   = MakeDefinitionExpression(gen);
            MSA.Expression selfVariable = outerLocals.DefineHiddenVariable("#module", typeof(RubyModule));
            MSA.Expression rfcVariable  = gen.CurrentRfcVariable;
            MSA.Expression parentScope  = gen.CurrentScopeVariable;

            // inner locals:
            ScopeBuilder scope = new ScopeBuilder();

            MSA.Expression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyScope));

            gen.EnterModuleDefinition(
                scope,
                selfVariable,
                scopeVariable,
                IsSingletonDeclaration
                );

            // first, transform locals defined within the module body:
            DefinedScope.TransformLocals(scope);

            // second, transform body:
            MSA.Expression transformedBody = Body.TransformRead(gen);

            // outer local:
            MSA.Expression resultVariable = outerLocals.DefineHiddenVariable("#result", transformedBody.Type);

            // begin with new scope
            //   self = DefineModule/Class(... parent scope here ...)
            //   <body>
            // end
            MSA.Expression result = AstFactory.Block(
                gen.DebugMarker(debugString),
                Ast.Assign(selfVariable, definition),
                scope.CreateScope(
                    Ast.Block(
                        Ast.Assign(scopeVariable,
                                   Methods.CreateModuleScope.OpCall(scope.VisibleVariables(), parentScope, rfcVariable, selfVariable)),
                        Ast.Assign(resultVariable, transformedBody),
                        Ast.Empty()
                        )
                    ),
                gen.DebugMarker("END OF " + debugString),
                resultVariable
                );

            gen.LeaveModuleDefinition();

            return(result);
        }
Exemple #10
0
 internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen)
 {
     MSA.Expression[] result = new MSA.Expression[_items.Count + 1];
     for (int i = 0; i < _items.Count; i++)
     {
         result[i] = Methods.UndefineMethod.OpCall(gen.CurrentScopeVariable, AstUtils.Constant(_items[i].Name));
     }
     result[_items.Count] = Ast.Empty();
     return(Ast.Block(result));
 }
Exemple #11
0
        public static MSA.Expression /*!*/ Block(List <MSA.Expression /*!*/> /*!*/ expressions)
        {
            switch (expressions.Count)
            {
            case 0: return(Ast.Empty());

            case 1: return(expressions[0]);

            default: return(Ast.Block(new ReadOnlyCollection <MSA.Expression>(expressions.ToArray())));
            }
        }
Exemple #12
0
        public static MSA.Expression /*!*/ Block(params MSA.Expression /*!*/[] /*!*/ expressions)
        {
            switch (expressions.Length)
            {
            case 0: return(Ast.Empty());

            case 1: return(expressions[0]);

            default: return(Ast.Block(new ReadOnlyCollection <MSA.Expression>(expressions)));
            }
        }
Exemple #13
0
        internal static MSA.Expression /*!*/ MakeUserMethodBody(AstGenerator gen, int lastLine,
                                                                MSA.Expression /*!*/ blockParameter, MSA.Expression /*!*/ rfcVariable,
                                                                MSA.ParameterExpression /*!*/ methodUnwinder, MSA.Expression /*!*/ bodyStatement, ResultOperation resultOperation,
                                                                int profileTickIndex, MSA.ParameterExpression stampVariable, MSA.LabelTarget returnLabel)
        {
            Assert.NotNull(blockParameter, rfcVariable, bodyStatement, methodUnwinder);
            Debug.Assert(!resultOperation.IsIgnore, "return value should not be ignored");
            Debug.Assert(returnLabel != null || resultOperation.Variable != null, "return label needed");

            MSA.Expression resultExpression = Ast.Field(methodUnwinder, MethodUnwinder.ReturnValueField);
            if (resultOperation.Variable != null)
            {
                resultExpression = Ast.Assign(resultOperation.Variable, resultExpression);
            }
            else
            {
                resultExpression = Ast.Return(returnLabel, resultExpression);
            }

            // TODO: move this to the caller:
            MSA.Expression profileStart, profileEnd;
            if (stampVariable != null)
            {
                profileStart = Ast.Assign(stampVariable, Methods.Stopwatch_GetTimestamp.OpCall());
                profileEnd   = Methods.UpdateProfileTicks.OpCall(Ast.Constant(profileTickIndex), stampVariable);
            }
            else
            {
                profileStart = profileEnd = Ast.Empty();
            }

            return(AstUtils.Try(
                       // initialize frame (RFC):
                       profileStart,
                       Ast.Assign(rfcVariable, Methods.CreateRfcForMethod.OpCall(AstUtils.Convert(blockParameter, typeof(Proc)))),
                       bodyStatement
                       ).Filter(methodUnwinder, Ast.Equal(Ast.Field(methodUnwinder, MethodUnwinder.TargetFrameField), rfcVariable),

                                // return unwinder.ReturnValue;
                                resultExpression

                                ).Finally(
                       Ast.Assign(Ast.Field(rfcVariable, RuntimeFlowControl.IsActiveMethodField), Ast.Constant(false)),
                       profileEnd,
                       gen != null && gen.TraceEnabled ? Methods.TraceMethodReturn.OpCall(
                           gen.CurrentScopeVariable,
                           Ast.Convert(Ast.Constant(gen.SourceUnit.Path), typeof(string)),
                           Ast.Constant(lastLine)
                           ) : Ast.Empty()
                       ));
        }
Exemple #14
0
        internal static MSA.Expression /*!*/ MakeCallWithBlockRetryable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ invoke,
                                                                        MSA.Expression blockArgVariable, MSA.Expression transformedBlock, bool isBlockDefinition)
        {
            Assert.NotNull(invoke);
            Debug.Assert((blockArgVariable == null) == (transformedBlock == null));

            // see Ruby Language.doc/Control Flow Implementation/Method Call With a Block
            MSA.Expression          resultVariable = gen.CurrentScope.DefineHiddenVariable("#method-result", typeof(object));
            MSA.ParameterExpression evalUnwinder   = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(EvalUnwinder));

            MSA.LabelTarget label = Ast.Label();

            return(AstFactory.Block(
                       Ast.Assign(blockArgVariable, Ast.Convert(transformedBlock, blockArgVariable.Type)),
                       AstFactory.Infinite(label, null,
                                           (!isBlockDefinition) ?
                                           (MSA.Expression)Ast.Empty() :
                                           (MSA.Expression)Methods.InitializeBlock.OpCall(blockArgVariable),

                                           AstUtils.Try(
                                               Ast.Assign(resultVariable, invoke)
                                               ).Catch(evalUnwinder,
                                                       Ast.Assign(
                                                           resultVariable,
                                                           Ast.Field(evalUnwinder, EvalUnwinder.ReturnValueField)
                                                           )
                                                       ),

                                           // if result != RetrySingleton then break end
                                           AstUtils.Unless(Methods.IsRetrySingleton.OpCall(AstFactory.Box(resultVariable)), Ast.Break(label)),

                                           // if blockParam == #block then retry end
                                           (gen.CurrentMethod.IsTopLevelCode) ? Ast.Empty() :
                                           AstUtils.IfThen(Ast.Equal(gen.MakeMethodBlockParameterRead(), blockArgVariable), RetryStatement.TransformRetry(gen))

                                           ),
                       resultVariable
                       ));
        }
        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);
        }
Exemple #16
0
        internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen)
        {
            MSA.Expression parentScope = gen.CurrentScopeVariable;
            ScopeBuilder   scope       = new ScopeBuilder();

            // define hidden parameters and RHS-placeholders (#1..#n will be used as RHS of a parallel assignment):
            MSA.Expression            blockParameter, selfParameter;
            MSA.ParameterExpression[] parameters = DefineParameters(out selfParameter, out blockParameter);

            MSA.Expression  scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyBlockScope));
            MSA.LabelTarget redoLabel     = Ast.Label();

            gen.EnterBlockDefinition(
                scope,
                blockParameter,
                selfParameter,
                scopeVariable,
                redoLabel
                );

            if (_definedScope != null)
            {
                _definedScope.TransformLocals(scope);
            }

            MSA.Expression          paramInit     = MakeParametersInitialization(gen, parameters);
            MSA.ParameterExpression blockUnwinder = scope.DefineHiddenVariable("#unwinder", typeof(BlockUnwinder));

            MSA.Expression loop = AstFactory.Infinite(null, redoLabel,
                                                      AstUtils.Try(
                                                          gen.TransformStatements(_body, ResultOperation.Return)
                                                          ).Catch(blockUnwinder,
                                                                  // redo:
                                                                  AstUtils.IfThen(Ast.Field(blockUnwinder, BlockUnwinder.IsRedoField), Ast.Continue(redoLabel)),

                                                                  // next:
                                                                  gen.Return(Ast.Field(blockUnwinder, BlockUnwinder.ReturnValueField))
                                                                  )
                                                      );

            if (gen.TraceEnabled)
            {
                int firstStatementLine = _body.Count > 0 ? _body[0].Location.Start.Line : Location.End.Line;
                int lastStatementLine  = _body.Count > 0 ? _body[_body.Count - 1].Location.End.Line : Location.End.Line;

                loop = Ast.TryFinally(
                    Ast.Block(
                        Methods.TraceBlockCall.OpCall(scopeVariable, blockParameter, Ast.Convert(Ast.Constant(gen.SourceUnit.Path), typeof(string)), Ast.Constant(firstStatementLine)),
                        loop
                        ),
                    Methods.TraceBlockReturn.OpCall(scopeVariable, blockParameter, Ast.Convert(Ast.Constant(gen.SourceUnit.Path), typeof(string)), Ast.Constant(lastStatementLine))
                    );
            }

            MSA.Expression body = Ast.Block(
                Ast.Assign(scopeVariable,
                           Methods.CreateBlockScope.OpCall(scope.VisibleVariables(), parentScope, blockParameter, selfParameter)
                           ),

                paramInit,

                loop,

                Ast.Empty()
                );

            body = gen.AddReturnTarget(scope.CreateScope(body));
            gen.LeaveBlockDefinition();

            int parameterCount = _parameters.LeftValues.Count;

            var attributes = _parameters.GetBlockSignatureAttributes();

            return(Methods.DefineBlock.OpCall(
                       gen.CurrentScopeVariable,
                       gen.CurrentRfcVariable,
                       gen.CurrentSelfVariable,
                       Ast.Lambda(
                           BlockDispatcher.GetDelegateType(parameterCount, attributes),
                           body,
                           gen.EncodeMethodName(gen.CurrentMethod.MethodName, Location),
                           new ReadOnlyCollection <MSA.ParameterExpression>(parameters)
                           ),
                       Ast.Constant(parameterCount),
                       Ast.Constant(attributes)
                       ));
        }
        private MSAst.LambdaExpression CreateOuterLambda(Type lambdaType, MSAst.Expression debuggableBody)
        {
            List <MSAst.Expression> bodyExpressions    = new List <MSAst.Expression>();
            List <MSAst.Expression> tryExpressions     = new List <MSAst.Expression>();
            List <MSAst.Expression> finallyExpressions = new List <MSAst.Expression>();

            Type returnType = lambdaType.GetMethod("Invoke").ReturnType;

            MSAst.LabelTarget returnLabelTarget = Ast.Label(returnType);

            // Init $funcInfo
            tryExpressions.Add(
                Ast.Assign(
                    _funcInfo,
                    Ast.Convert(_functionInfo, typeof(FunctionInfo))
                    )
                );

            // Init $traceLocations
            // $TODO: only do this if we're in TracePoints mode
            tryExpressions.Add(
                Ast.Assign(
                    _traceLocations,
                    Ast.Call(typeof(RuntimeOps).GetMethod("GetTraceLocations"), _funcInfo)
                    )
                );

            // Init sourceFile locals
            foreach (var entry in _sourceFilesMap)
            {
                tryExpressions.Add(
                    Ast.Assign(
                        entry.Value,
                        Ast.Constant(entry.Key, typeof(DebugSourceFile))
                        )
                    );
            }

            if (_noPushFrameOptimization)
            {
                tryExpressions.Add(_pushFrame);
            }

            tryExpressions.Add(Ast.Call(
                                   typeof(RuntimeOps).GetMethod("OnFrameEnterTraceEvent"),
                                   _thread
                                   ));

            var frameExit = AstUtils.If(
                Ast.Equal(
                    _debugMarkerLocationMap.Length > 0 ?
                    Ast.Property(_sourceFilesMap[_debugMarkerLocationMap[0].SourceFile], "Mode") :
                    _globalDebugMode,
                    AstUtils.Constant((int)DebugMode.FullyEnabled)
                    ),
                Ast.Call(
                    typeof(RuntimeOps).GetMethod("OnFrameExitTraceEvent"),
                    _thread,
                    _debugMarker,
                    _retVal != null ? (MSAst.Expression)Ast.Convert(_retVal, typeof(object)) : Ast.Constant(null)
                    )
                );

            // normal exit
            tryExpressions.Add(
                Ast.Block(
                    _retVal != null ? Ast.Assign(_retVal, debuggableBody) : debuggableBody,
                    Ast.Assign(_frameExitException, Ast.Constant(true)),
                    frameExit)
                );

            tryExpressions.Add(
                _retVal != null ? (MSAst.Expression)Ast.Return(returnLabelTarget, _retVal) : Ast.Empty()
                );

            MSAst.Expression[] popFrame = new MSAst.Expression[] {
                AstUtils.If(
                    // Fire thead-exit event if PopFrame returns true
                    Ast.AndAlso(
                        Ast.Equal(Ast.Call(typeof(RuntimeOps).GetMethod("PopFrame"), _thread), Ast.Constant(true)),
                        Ast.Equal(_globalDebugMode, AstUtils.Constant((int)DebugMode.FullyEnabled))
                        ),
                    Ast.Call(
                        typeof(RuntimeOps).GetMethod("OnThreadExitEvent"),
                        _thread
                        )
                    )
            };

            if (_noPushFrameOptimization)
            {
                finallyExpressions.AddRange(popFrame);
            }
            else
            {
                finallyExpressions.Add(
                    AstUtils.If(
                        Ast.Equal(_framePushed, Ast.Constant(true)),
                        popFrame
                        )
                    );
            }

            MSAst.ParameterExpression caughtException;

            // Run the function body
            bodyExpressions.Add(Ast.TryCatchFinally(
                                    Ast.TryCatch(
                                        Ast.Block(
                                            ArrayUtils.Append(tryExpressions.ToArray(), Ast.Default(returnType))
                                            ),
                                        Ast.Catch(
                                            caughtException = Ast.Variable(typeof(Exception), "$caughtException"),
                                            Ast.Block(
                                                // The expressions below will always throw.
                                                // If the exception needs to be cancelled then OnTraceEvent will throw ForceToGeneratorLoopException.
                                                // If the exception is not being cancelled then we'll just rethrow at the end of the catch block.
                                                AstUtils.If(
                                                    Ast.Not(
                                                        Ast.TypeIs(
                                                            caughtException,
                                                            typeof(ForceToGeneratorLoopException)
                                                            )
                                                        ),
                                                    AstUtils.If(
                                                        Ast.NotEqual(_globalDebugMode, AstUtils.Constant((int)DebugMode.Disabled)),
                                                        _noPushFrameOptimization ? Ast.Empty() : _conditionalPushFrame,
                                                        Ast.Call(
                                                            typeof(RuntimeOps).GetMethod("OnTraceEventUnwind"),
                                                            _thread,
                                                            _debugMarker,
                                                            caughtException
                                                            )
                                                        ),
                                                    // exception exit
                                                    AstUtils.If(
                                                        Ast.Not(_frameExitException),
                                                        frameExit
                                                        )
                                                    ),

                                                Ast.Rethrow(),

                                                // Ensuring that the catch block is of the same type as the try block
                                                Ast.Default(returnType)
                                                )
                                            )
                                        ),
                                    Ast.Block(finallyExpressions),
                                    Ast.Catch(
                                        typeof(ForceToGeneratorLoopException),
                                        Ast.TryFinally(
                                            // Handle ForceToGeneratorLoopException
                                            Ast.Block(
                                                returnType != typeof(void) ? Ast.Block(
                                                    Ast.Assign(
                                                        _retValFromGeneratorLoop,
                                                        Ast.Call(
                                                            typeof(RuntimeOps).GetMethod("GeneratorLoopProc"),
                                                            _thread
                                                            )
                                                        ),
                                                    AstUtils.If(
                                                        Ast.NotEqual(
                                                            _retValFromGeneratorLoop,
                                                            Ast.Constant(null)
                                                            ),
                                                        Ast.Assign(_retVal, Ast.Convert(_retValFromGeneratorLoop, returnType)),
                                                        Ast.Return(
                                                            returnLabelTarget,
                                                            Ast.Convert(_retValFromGeneratorLoop, returnType)
                                                            )
                                                        ).Else(
                                                        Ast.Assign(_retVal, Ast.Default(returnType)),
                                                        Ast.Return(
                                                            returnLabelTarget,
                                                            Ast.Default(returnType)
                                                            )
                                                        )
                                                    ) :
                                                Ast.Block(
                                                    Ast.Call(
                                                        typeof(RuntimeOps).GetMethod("GeneratorLoopProc"),
                                                        _thread
                                                        ),
                                                    Ast.Return(returnLabelTarget)
                                                    )
                                                ,
                                                // Ensuring that the catch block is of the same type as the try block
                                                Ast.Default(returnType)
                                                ),
                                            // Make sure that the debugMarker is up-to-date after the generator loop
                                            Ast.Assign(
                                                _debugMarker,
                                                Ast.Call(
                                                    typeof(RuntimeOps).GetMethod("GetCurrentSequencePointForLeafGeneratorFrame"),
                                                    _thread
                                                    )
                                                )
                                            )
                                        )
                                    ));

            MSAst.Expression body = Ast.Block(bodyExpressions);

            if (body.Type == typeof(void) && returnType != typeof(void))
            {
                body = Ast.Block(body, Ast.Default(returnType));
            }

            return(Ast.Lambda(
                       lambdaType,
                       Ast.Block(
                           _lambdaVars,
                           Ast.Label(returnLabelTarget, body)
                           ),
                       _alias,
                       _lambdaParams));
        }
Exemple #18
0
        internal MSA.Expression /*!*/ TransformStatements(MSA.Expression prologue, List <Expression> /*!*/ statements, MSA.Expression epilogue,
                                                          ResultOperation resultOperation)
        {
            Assert.NotNullItems(statements);

            int count = statements.Count + (prologue != null ? 1 : 0) + (epilogue != null ? 1 : 0);

            if (count == 0)
            {
                if (resultOperation.IsIgnore)
                {
                    return(Ast.Empty());
                }
                else if (resultOperation.Variable != null)
                {
                    return(Ast.Assign(resultOperation.Variable, Ast.Constant(null, resultOperation.Variable.Type)));
                }
                else
                {
                    return(Ast.Return(CurrentFrame.ReturnLabel, Ast.Constant(null)));
                }
            }
            else if (count == 1)
            {
                if (prologue != null)
                {
                    return(prologue);
                }

                if (epilogue != null)
                {
                    return(epilogue);
                }

                if (resultOperation.IsIgnore)
                {
                    return(statements[0].Transform(this));
                }
                else
                {
                    return(statements[0].TransformResult(this, resultOperation));
                }
            }
            else
            {
                var result      = new MSA.Expression[count + 1];
                int resultIndex = 0;

                if (prologue != null)
                {
                    result[resultIndex++] = prologue;
                }

                // transform all but the last statement if it is an expression stmt:
                for (int i = 0; i < statements.Count - 1; i++)
                {
                    result[resultIndex++] = statements[i].Transform(this);
                }

                if (statements.Count > 0)
                {
                    if (resultOperation.IsIgnore)
                    {
                        result[resultIndex++] = statements[statements.Count - 1].Transform(this);
                    }
                    else
                    {
                        result[resultIndex++] = statements[statements.Count - 1].TransformResult(this, resultOperation);
                    }
                }

                if (epilogue != null)
                {
                    result[resultIndex++] = epilogue;
                }

                result[resultIndex++] = MSA.Expression.Empty();
                Debug.Assert(resultIndex == result.Length);

                return(Ast.Block(new ReadOnlyCollection <MSA.Expression>(result)));
            }
        }
Exemple #19
0
 internal MSA.Expression /*!*/ DebugMarker(string /*!*/ marker)
 {
     return(_debugCompiler ? Methods.X.OpCall(Ast.Constant(marker)) : (MSA.Expression)Ast.Empty());
 }
Exemple #20
0
 public override MSA.Expression /*!*/ Reduce()
 {
     return(Ast.Empty());
 }
Exemple #21
0
        internal MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen, bool isLambda)
        {
            ScopeBuilder scope = DefineLocals(gen.CurrentScope);

            // define hidden parameters and RHS-placeholders (#1..#n will be used as RHS of a parallel assignment):
            MSA.ParameterExpression blockParameter, selfParameter;
            var parameters = DefineParameters(out selfParameter, out blockParameter);

            MSA.ParameterExpression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyBlockScope));
            MSA.LabelTarget         redoLabel     = Ast.Label();

            gen.EnterBlockDefinition(
                scope,
                blockParameter,
                selfParameter,
                scopeVariable,
                redoLabel
                );

            MSA.Expression          paramInit = MakeParametersInitialization(gen, parameters);
            MSA.ParameterExpression blockUnwinder, filterVariable;

            MSA.Expression traceCall, traceReturn;
            if (gen.TraceEnabled)
            {
                int firstStatementLine = _body.Count > 0 ? _body.First.Location.Start.Line : Location.End.Line;
                int lastStatementLine  = _body.Count > 0 ? _body.Last.Location.End.Line : Location.End.Line;

                traceCall   = Methods.TraceBlockCall.OpCall(scopeVariable, blockParameter, gen.SourcePathConstant, AstUtils.Constant(firstStatementLine));
                traceReturn = Methods.TraceBlockReturn.OpCall(scopeVariable, blockParameter, gen.SourcePathConstant, AstUtils.Constant(lastStatementLine));
            }
            else
            {
                traceCall = traceReturn = Ast.Empty();
            }

            MSA.Expression body = AstUtils.Try(
                paramInit,
                traceCall,
                Ast.Label(redoLabel),
                AstUtils.Try(
                    gen.TransformStatements(_body, ResultOperation.Return)
                    ).Catch(blockUnwinder = Ast.Parameter(typeof(BlockUnwinder), "#u"),
                            // redo:
                            AstUtils.IfThen(Ast.Field(blockUnwinder, BlockUnwinder.IsRedoField), Ast.Goto(redoLabel)),

                            // next:
                            gen.Return(Ast.Field(blockUnwinder, BlockUnwinder.ReturnValueField))
                            )
                ).Filter(filterVariable = Ast.Parameter(typeof(Exception), "#e"),
                         Methods.FilterBlockException.OpCall(scopeVariable, filterVariable)
                         ).Finally(
                traceReturn,
                Ast.Empty()
                );

            body = gen.AddReturnTarget(
                scope.CreateScope(
                    scopeVariable,
                    Methods.CreateBlockScope.OpCall(new AstExpressions {
                scope.MakeLocalsStorage(),
                scope.GetVariableNamesExpression(),
                blockParameter,
                selfParameter,
                EnterInterpretedFrameExpression.Instance
            }),
                    body
                    )
                );

            gen.LeaveBlockDefinition();

            int parameterCount = ParameterCount;
            var attributes = _parameters.GetBlockSignatureAttributes();

            var dispatcher = Ast.Constant(
                BlockDispatcher.Create(parameterCount, attributes, gen.SourcePath, Location.Start.Line), typeof(BlockDispatcher)
                );

            return(Ast.Coalesce(
                       (isLambda ? Methods.InstantiateLambda : Methods.InstantiateBlock).OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable, dispatcher),
                       (isLambda ? Methods.DefineLambda : Methods.DefineBlock).OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable, dispatcher,
                                                                                      BlockDispatcher.CreateLambda(
                                                                                          body,
                                                                                          RubyStackTraceBuilder.EncodeMethodName(gen.CurrentMethod.MethodName, gen.SourcePath, Location, gen.DebugMode),
                                                                                          parameters,
                                                                                          parameterCount,
                                                                                          attributes
                                                                                          )
                                                                                      )
                       ));
        }
Exemple #22
0
        internal MSA.LambdaExpression /*!*/ TransformBody(AstGenerator /*!*/ gen, RubyScope /*!*/ declaringScope, RubyModule /*!*/ declaringModule)
        {
            string encodedName = RubyStackTraceBuilder.EncodeMethodName(_name, gen.SourcePath, Location, gen.DebugMode);

            AstParameters parameters;
            ScopeBuilder  scope = DefineLocals(out parameters);

            var scopeVariable  = scope.DefineHiddenVariable("#scope", typeof(RubyMethodScope));
            var selfParameter  = parameters[0];
            var blockParameter = parameters[1];

            // exclude block parameter even if it is explicitly specified:
            int visiblePrameterCountAndSignatureFlags = (parameters.Count - 2) << 2;

            if (_parameters.Block != null)
            {
                visiblePrameterCountAndSignatureFlags |= RubyMethodScope.HasBlockFlag;
            }
            if (_parameters.Unsplat != null)
            {
                visiblePrameterCountAndSignatureFlags |= RubyMethodScope.HasUnsplatFlag;
            }

            gen.EnterMethodDefinition(
                scope,
                selfParameter,
                scopeVariable,
                blockParameter,
                _name,
                _parameters
                );

            // profiling:
            MSA.Expression profileStart, profileEnd;
            if (gen.Profiler != null)
            {
                int profileTickIndex = gen.Profiler.GetTickIndex(encodedName);
                var stampVariable    = scope.DefineHiddenVariable("#stamp", typeof(long));
                profileStart = Ast.Assign(stampVariable, Methods.Stopwatch_GetTimestamp.OpCall());
                profileEnd   = Methods.UpdateProfileTicks.OpCall(AstUtils.Constant(profileTickIndex), stampVariable);
            }
            else
            {
                profileStart = profileEnd = AstUtils.Empty();
            }

            // tracing:
            MSA.Expression traceCall, traceReturn;
            if (gen.TraceEnabled)
            {
                traceCall = Methods.TraceMethodCall.OpCall(
                    scopeVariable,
                    gen.SourcePathConstant,
                    AstUtils.Constant(Location.Start.Line)
                    );

                traceReturn = Methods.TraceMethodReturn.OpCall(
                    gen.CurrentScopeVariable,
                    gen.SourcePathConstant,
                    AstUtils.Constant(Location.End.Line)
                    );
            }
            else
            {
                traceCall = traceReturn = AstUtils.Empty();
            }

            MSA.ParameterExpression unwinder;

            MSA.Expression body = AstUtils.Try(
                profileStart,
                _parameters.TransformOptionalsInitialization(gen),
                traceCall,
                Body.TransformResult(gen, ResultOperation.Return)
                ).Filter(unwinder = Ast.Parameter(typeof(Exception), "#u"), Methods.IsMethodUnwinderTargetFrame.OpCall(scopeVariable, unwinder),
                         Ast.Return(gen.ReturnLabel, Methods.GetMethodUnwinderReturnValue.OpCall(unwinder))
                         ).Finally(
                // leave frame:
                Methods.LeaveMethodFrame.OpCall(scopeVariable),
                Ast.Empty(),
                profileEnd,
                traceReturn
                );

            body = gen.AddReturnTarget(
                scope.CreateScope(
                    scopeVariable,
                    Methods.CreateMethodScope.OpCall(new AstExpressions {
                scope.MakeLocalsStorage(),
                scope.GetVariableNamesExpression(),
                Ast.Constant(visiblePrameterCountAndSignatureFlags),
                Ast.Constant(declaringScope, typeof(RubyScope)),
                Ast.Constant(declaringModule, typeof(RubyModule)),
                Ast.Constant(_name),
                selfParameter, blockParameter,
                EnterInterpretedFrameExpression.Instance
            }),
                    body
                    )
                );

            gen.LeaveMethodDefinition();

            return(CreateLambda(encodedName, parameters, body));
        }
Exemple #23
0
        internal MSA.Expression <T> /*!*/ Transform <T>(AstGenerator /*!*/ gen)
        {
            Debug.Assert(gen != null);

            ScopeBuilder scope = DefineLocals();

            MSA.ParameterExpression[] parameters;
            MSA.ParameterExpression   selfVariable;
            MSA.ParameterExpression   runtimeScopeVariable;
            MSA.ParameterExpression   blockParameter;

            if (gen.CompilerOptions.FactoryKind == TopScopeFactoryKind.None ||
                gen.CompilerOptions.FactoryKind == TopScopeFactoryKind.ModuleEval)
            {
                parameters = new MSA.ParameterExpression[4];

                runtimeScopeVariable = parameters[0] = Ast.Parameter(typeof(RubyScope), "#scope");
                selfVariable         = parameters[1] = Ast.Parameter(typeof(object), "#self");
                parameters[2]        = Ast.Parameter(typeof(RubyModule), "#module");
                blockParameter       = parameters[3] = Ast.Parameter(typeof(Proc), "#block");
            }
            else
            {
                parameters = new MSA.ParameterExpression[2];

                runtimeScopeVariable = parameters[0] = Ast.Parameter(typeof(RubyScope), "#scope");
                selfVariable         = parameters[1] = Ast.Parameter(typeof(object), "#self");

                blockParameter = null;
            }

            gen.EnterSourceUnit(
                scope,
                selfVariable,
                runtimeScopeVariable,
                blockParameter,
                gen.CompilerOptions.TopLevelMethodName, // method name for blocks
                null                                    // parameters for super calls
                );

            MSA.Expression body;

            if (_statements.Count > 0)
            {
                if (gen.PrintInteractiveResult)
                {
                    var resultVariable = scope.DefineHiddenVariable("#result", typeof(object));

                    var epilogue = Methods.PrintInteractiveResult.OpCall(runtimeScopeVariable,
                                                                         AstUtils.LightDynamic(ConvertToSAction.Make(gen.Context), typeof(MutableString),
                                                                                               CallSiteBuilder.InvokeMethod(gen.Context, "inspect", RubyCallSignature.WithScope(0),
                                                                                                                            gen.CurrentScopeVariable, resultVariable
                                                                                                                            )
                                                                                               )
                                                                         );

                    body = gen.TransformStatements(null, _statements, epilogue, ResultOperation.Store(resultVariable));
                }
                else
                {
                    body = gen.TransformStatements(_statements, ResultOperation.Return);
                }

                // TODO:
                var exceptionVariable = Ast.Parameter(typeof(Exception), "#exception");
                body = AstUtils.Try(
                    body
                    ).Filter(exceptionVariable, Methods.TraceTopLevelCodeFrame.OpCall(runtimeScopeVariable, exceptionVariable),
                             Ast.Empty()
                             );
            }
            else
            {
                body = AstUtils.Constant(null);
            }

            // scope initialization:
            MSA.Expression prologue;
            switch (gen.CompilerOptions.FactoryKind)
            {
            case TopScopeFactoryKind.None:
            case TopScopeFactoryKind.ModuleEval:
                prologue = Methods.InitializeScopeNoLocals.OpCall(runtimeScopeVariable, EnterInterpretedFrameExpression.Instance);
                break;

            case TopScopeFactoryKind.Hosted:
            case TopScopeFactoryKind.File:
            case TopScopeFactoryKind.WrappedFile:
                prologue = Methods.InitializeScope.OpCall(
                    runtimeScopeVariable, scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(),
                    EnterInterpretedFrameExpression.Instance
                    );
                break;

            case TopScopeFactoryKind.Main:
                prologue = Methods.InitializeScope.OpCall(
                    runtimeScopeVariable, scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(),
                    EnterInterpretedFrameExpression.Instance
                    );
                if (_dataOffset >= 0)
                {
                    prologue = Ast.Block(
                        prologue,
                        Methods.SetDataConstant.OpCall(
                            runtimeScopeVariable,
                            gen.SourcePathConstant,
                            AstUtils.Constant(_dataOffset)
                            )
                        );
                }
                break;

            default:
                throw Assert.Unreachable;
            }

            // BEGIN blocks:
            if (gen.FileInitializers != null)
            {
                var b = new AstBlock();
                b.Add(prologue);
                b.Add(gen.FileInitializers);
                b.Add(body);
                body = b;
            }

            body = gen.AddReturnTarget(scope.CreateScope(body));

            gen.LeaveSourceUnit();

            return(Ast.Lambda <T>(body, GetEncodedName(gen), parameters));
        }
                static Statement Rewrite(Statement body)
                {
                    if (body is LabeledStatement)
                    {
                        var ls = (LabeledStatement)body;
                        return(ls.Mark(Rewrite(ls.Statement)));
                    }

                    if (body is BlockStatement)
                    {
                        var node    = body as BlockStatement;
                        var newbody = new List <Statement>();

                        foreach (var stmt in node.Statements)
                        {
                            var ns = Rewrite(stmt);
                            if (ns is BlockStatement)
                            {
                                newbody.AddRange(((BlockStatement)ns).Statements);
                            }
                            else
                            {
                                newbody.Add(ns);
                            }
                        }
                        return(Ast.Block(newbody));
                    }

                    if (body is WriteStatement)
                    {
                        var ws = (WriteStatement)body;

                        if (ws.Value is CommaExpression)
                        {
                            var ce    = ws.Value as CommaExpression;
                            var block = RewriteExpressions(ce.Expressions, x => Ast.Write(ws.Variable, x));
                            return(Rewrite(Ast.Block(block)));
                        }
                        else if (ws.Value == null)
                        {
                            var cb = ws.Variable.Block;
                            if (cb != null)
                            {
                                cb.RemoveVariables(new List <Variable>(new[] { ws.Variable }));
                                cb.Bind();
                            }
                            return(Ast.Empty());
                        }
                        else if (ws.Variable.Block == null)
                        {
                            //var cb = ws.Variable.Block;
                            //cb.RemoveVariables(new List<Variable>(new[] { ws.Variable }));
                            //cb.Bind();
                            return(Ast.Empty());
                        }
                        else if (ws.HasNoRef)
                        {
                            //var cb = ws.Variable.Block;
                            //cb.RemoveVariables(new List<Variable>(new[] { ws.Variable }));
                            //cb.Bind();
                            //return Ast.Empty();
                        }
                    }

                    if (body is ReturnStatement)
                    {
                        var rs = body as ReturnStatement;

                        if (rs.Expression is UnaryExpression && rs.Expression.NodeType == AstNodeType.Convert)
                        {
                            var ux = (UnaryExpression)rs.Expression;
                            var op = ux.Operand;

                            if (op is VoidExpression)
                            {
                                return(Rewrite(op as VoidExpression));
                            }
                            if (op is CommaExpression)
                            {
                                var ce = op as CommaExpression;

                                var block = RewriteExpressions(ce.Expressions,
                                                               x => Ast.Return(Ast.ConvertHelper(x, ux.Type)));

                                return(Rewrite(Ast.Block(block)));
                            }
                        }

                        if (rs.Expression is CommaExpression)
                        {
                            var ce = rs.Expression as CommaExpression;
                            var le = ce.Expressions[ce.Expressions.Count - 1];
                            if (le is VoidExpression && ((VoidExpression)le).Statement is ContinueStatement)
                            {
                                var block = RewriteExpressions(ce.Expressions, x => Ast.Continue());
                                return(Rewrite(Ast.Block(block)));
                            }
                            else
                            {
                                var block = RewriteExpressions(ce.Expressions, Ast.Return);
                                return(Rewrite(Ast.Block(block)));
                            }
                        }

                        if (rs.Expression is VoidExpression)
                        {
                            var ve = rs.Expression as VoidExpression;
                            return(Rewrite(ve));
                        }

                        if (rs.Expression is MethodCallExpression)
                        {
                            var mce = rs.Expression as MethodCallExpression;
                            var uce = Unwrap(mce.Instance);
                            if (uce is CommaExpression)
                            {
                                var ce    = uce as CommaExpression;
                                var block = RewriteExpressions(ce.Expressions,
                                                               x =>
                                {
                                    if (mce.Arguments.Count == 1 && mce.Arguments[0].Type == typeof(object[]))
                                    {
                                        var mc      = Ast.SimpleCallHelper(x, mce.Method, mce.Arguments.ToArray());
                                        mc.TailCall = mce.TailCall;
                                        return(Ast.Return(mc));
                                    }
                                    else
                                    {
                                        //var args = Array.ConvertAll(mce.Arguments.ToArray(), y => Ast.ConvertHelper(y, typeof(object)));
                                        var mc      = Ast.SimpleCallHelper(x, mce.Method, mce.Arguments.ToArray());
                                        mc.TailCall = mce.TailCall;
                                        return(Ast.Return(mc));
                                    }
                                });
                                return(Rewrite(Ast.Block(block)));
                            }
                        }
                    }

                    if (body is ExpressionStatement)
                    {
                        var es  = (ExpressionStatement)body;
                        var trs = TryRewriteExpression(es.Expression);
                        if (trs != null)
                        {
                            return(trs);
                        }
                    }

                    if (body is IfStatement)
                    {
                        var ifs = (IfStatement)body;
                        if (ifs.ElseStatement == null)
                        {
                            return(Ast.If(ifs.Tests[0].Test, Rewrite(ifs.Tests[0].Body)).ToStatement());
                        }
                        else
                        {
                            return(Ast.If(ifs.Tests[0].Test, Rewrite(ifs.Tests[0].Body)).Else(Rewrite(ifs.ElseStatement)));
                        }
                    }

                    return(body);
                }
Exemple #25
0
 internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen)
 {
     TransformBody(gen);
     return(Ast.Empty());
 }
Exemple #26
0
        private MSA.Expression /*!*/ TransformExceptionHandling(AstGenerator /*!*/ gen, ResultOperation resultOperation)
        {
            Assert.NotNull(gen);

            MSA.Expression          exceptionThrownVariable  = gen.CurrentScope.DefineHiddenVariable("#exception-thrown", typeof(bool));
            MSA.ParameterExpression exceptionVariable        = gen.CurrentScope.DefineHiddenVariable("#exception", typeof(Exception));
            MSA.Expression          exceptionRethrowVariable = gen.CurrentScope.DefineHiddenVariable("#exception-rethrow", typeof(bool));
            MSA.Expression          retryingVariable         = gen.CurrentScope.DefineHiddenVariable("#retrying", typeof(bool));
            MSA.ParameterExpression evalUnwinder             = gen.CurrentScope.DefineHiddenVariable("#unwinder", typeof(EvalUnwinder));
            MSA.Expression          oldExceptionVariable     = gen.CurrentScope.DefineHiddenVariable("#old-exception", typeof(Exception));

            MSA.Expression transformedBody;
            MSA.Expression transformedEnsure;
            MSA.Expression transformedElse;

            if (_ensureStatements != null)
            {
                transformedEnsure = Ast.Block(
                    // ensure:
                    Ast.Assign(oldExceptionVariable, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)),
                    gen.TransformStatements(_ensureStatements, ResultOperation.Ignore),
                    Methods.SetCurrentException.OpCall(gen.CurrentScopeVariable, oldExceptionVariable),

                    // rethrow:
                    AstUtils.IfThen(
                        Ast.AndAlso(
                            exceptionRethrowVariable,
                            Ast.NotEqual(oldExceptionVariable, Ast.Constant(null))
                            ),
                        Ast.Throw(oldExceptionVariable)
                        ),
                    Ast.Empty()
                    );
            }
            else
            {
                // rethrow:
                transformedEnsure = AstUtils.IfThen(
                    Ast.AndAlso(
                        exceptionRethrowVariable,
                        Ast.NotEqual(
                            Ast.Assign(oldExceptionVariable, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)),
                            Ast.Constant(null, typeof(Exception)))
                        ),
                    Ast.Throw(oldExceptionVariable)
                    );
            }

            if (_elseStatements != null)
            {
                transformedElse = gen.TransformStatements(_elseStatements, resultOperation);
            }
            else
            {
                transformedElse = Ast.Empty();
            }

            // body should do return, but else-clause is present => we cannot do return from the guarded statements:
            // (the value of the last expression in the body cannot be the last executed expression statement => we can ignore it):
            transformedBody = gen.TransformStatements(_statements, (_elseStatements != null) ? ResultOperation.Ignore : resultOperation);

            MSA.Expression setInRescueFlag = null, clearInRescueFlag = null;
            var            breakLabel    = Ast.Label();
            var            continueLabel = Ast.Label();

            // make rescue clause:
            MSA.Expression transformedRescue;
            if (_rescueClauses != null)
            {
                // outer-most EH blocks sets and clears runtime flag RuntimeFlowControl.InTryRescue:
                if (gen.CurrentRescue == null)
                {
                    setInRescueFlag   = Ast.Assign(Ast.Field(gen.CurrentRfcVariable, RuntimeFlowControl.InRescueField), Ast.Constant(true));
                    clearInRescueFlag = Ast.Assign(Ast.Field(gen.CurrentRfcVariable, RuntimeFlowControl.InRescueField), Ast.Constant(false));
                }
                else
                {
                    setInRescueFlag = clearInRescueFlag = Ast.Empty();
                }

                gen.EnterRescueClause(retryingVariable, breakLabel, continueLabel);

                var handlers = new IfStatementTest[_rescueClauses.Count];
                for (int i = 0; i < handlers.Length; i++)
                {
                    handlers[i] = _rescueClauses[i].Transform(gen, resultOperation);
                }

                transformedRescue = Ast.Block(
                    setInRescueFlag,
                    AstUtils.Try(
                        AstUtils.If(handlers, Ast.Assign(exceptionRethrowVariable, Ast.Constant(true)))
                        ).Filter(evalUnwinder, Ast.Equal(Ast.Field(evalUnwinder, EvalUnwinder.ReasonField), Ast.Constant(BlockReturnReason.Retry)),
                                 Ast.Block(
                                     Ast.Assign(retryingVariable, Ast.Constant(true)),
                                     Ast.Continue(continueLabel),
                                     Ast.Empty()
                                     )
                                 )
                    );

                gen.LeaveRescueClause();
            }
            else
            {
                transformedRescue = Ast.Assign(exceptionRethrowVariable, Ast.Constant(true));
            }

            if (_elseStatements != null)
            {
                transformedElse = AstUtils.Unless(exceptionThrownVariable, transformedElse);
            }

            var result = AstFactory.Infinite(breakLabel, continueLabel,
                                             Ast.Assign(exceptionThrownVariable, Ast.Constant(false)),
                                             Ast.Assign(exceptionRethrowVariable, Ast.Constant(false)),
                                             Ast.Assign(retryingVariable, Ast.Constant(false)),

                                             AstUtils.Try(
                                                 // save exception (old_$! is not used unless there is a rescue clause):
                                                 Ast.Block(
                                                     (_rescueClauses == null) ? (MSA.Expression)Ast.Empty() :
                                                     Ast.Assign(oldExceptionVariable, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)),

                                                     AstUtils.Try(
                                                         transformedBody
                                                         ).Filter(exceptionVariable, Methods.CanRescue.OpCall(gen.CurrentRfcVariable, exceptionVariable),
                                                                  Ast.Assign(exceptionThrownVariable, Ast.Constant(true)),
                                                                  Methods.SetCurrentExceptionAndStackTrace.OpCall(gen.CurrentScopeVariable, exceptionVariable),
                                                                  transformedRescue
                                                                  ).FinallyIf((_rescueClauses != null),
                                                                              // restore previous exception if the current one has been handled:
                                                                              AstUtils.Unless(exceptionRethrowVariable,
                                                                                              Methods.SetCurrentException.OpCall(gen.CurrentScopeVariable, oldExceptionVariable)
                                                                                              ),
                                                                              clearInRescueFlag
                                                                              ),

                                                     // unless (exception_thrown) do <else-statements> end
                                                     transformedElse,
                                                     Ast.Empty()
                                                     )
                                                 ).FilterIf((_rescueClauses != null || _elseStatements != null),
                                                            exceptionVariable, Methods.CanRescue.OpCall(gen.CurrentRfcVariable, exceptionVariable),
                                                            Ast.Block(
                                                                Methods.SetCurrentExceptionAndStackTrace.OpCall(gen.CurrentScopeVariable, exceptionVariable),
                                                                Ast.Assign(exceptionRethrowVariable, Ast.Constant(true)),
                                                                Ast.Empty()
                                                                )
                                                            ).Finally(
                                                 AstUtils.Unless(retryingVariable, transformedEnsure)
                                                 ),

                                             Ast.Break(breakLabel)
                                             );

            return(result);
        }
Exemple #27
0
 internal override MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen)
 {
     return(AstUtils.IfThenElse(TransformCondition(gen), _body.Transform(gen),
                                _elseStatement != null ? _elseStatement.Transform(gen) : Ast.Empty()
                                ));
 }
        protected override MSAst.Expression VisitDebugInfo(MSAst.DebugInfoExpression node)
        {
            if (!node.IsClear)
            {
                MSAst.Expression transformedExpression;

                // Verify that DebugInfoExpression has valid SymbolDocumentInfo
                if (node.Document == null)
                {
                    throw new InvalidOperationException(
                              string.Format(
                                  CultureInfo.CurrentCulture,
                                  ErrorStrings.DebugInfoWithoutSymbolDocumentInfo,
                                  _locationCookie));
                }

                DebugSourceFile sourceFile = _debugContext.GetDebugSourceFile(
                    String.IsNullOrEmpty(node.Document.FileName) ? "<compile>" : node.Document.FileName);

                // Update the location cookie
                int locationCookie = _locationCookie++;
                if (!_transformToGenerator)
                {
                    MSAst.Expression tracebackCall = null;
                    if (locationCookie == 0)
                    {
                        tracebackCall = Ast.Empty();
                    }
                    else
                    {
                        tracebackCall = Ast.Call(
                            typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.OnTraceEvent)),
                            _thread,
                            AstUtils.Constant(locationCookie),
                            Ast.Convert(Ast.Constant(null), typeof(Exception))
                            );
                    }

                    transformedExpression = Ast.Block(
                        Ast.Assign(
                            _debugMarker,
                            AstUtils.Constant(locationCookie)
                            ),
                        Ast.IfThen(
                            Ast.GreaterThan(
                                Ast.Property(_sourceFilesToVariablesMap[sourceFile], "Mode"),
                                Ast.Constant((int)DebugMode.ExceptionsOnly)
                                ),
                            Ast.IfThen(
                                Ast.OrElse(
                                    Ast.Equal(
                                        Ast.Property(_sourceFilesToVariablesMap[sourceFile], "Mode"),
                                        Ast.Constant((int)DebugMode.FullyEnabled)
                                        ),
                                    Ast.ArrayIndex(
                                        _traceLocations,
                                        AstUtils.Constant(locationCookie)
                                        )
                                    ),
                                Ast.Block(
                                    _pushFrame ?? Ast.Empty(),
                                    tracebackCall
                                    )
                                )
                            )
                        );
                }
                else
                {
                    Debug.Assert(_generatorLabelTarget != null);

                    transformedExpression = Ast.Block(
                        AstUtils.YieldReturn(
                            _generatorLabelTarget,
                            _debugYieldValue,
                            locationCookie
                            )
                        );

                    // Update the variable scope map
                    if (_currentLocals.Count > 0)
                    {
                        BlockExpression curentBlock = _currentLocals.Peek();
                        if (!_variableScopeMapCache.TryGetValue(curentBlock, out IList <VariableInfo> scopedVaribles))
                        {
                            scopedVaribles = new List <VariableInfo>();
                            BlockExpression[] blocks = _currentLocals.ToArray();
                            for (int i = blocks.Length - 1; i >= 0; i--)
                            {
                                foreach (var variable in blocks[i].Variables)
                                {
                                    scopedVaribles.Add(_localsToVarInfos[variable]);
                                }
                            }

                            _variableScopeMapCache.Add(curentBlock, scopedVaribles);
                        }

                        _variableScopeMap.Add(locationCookie, scopedVaribles);
                    }

                    DebugSourceSpan span = new DebugSourceSpan(
                        sourceFile,
                        node.StartLine,
                        node.StartColumn,
                        node.EndLine,
                        node.EndColumn);

                    // Update the location-span map
                    _markerLocationMap.Add(locationCookie, span);
                }

                return(transformedExpression);
            }

            return(Ast.Empty());
        }
Exemple #29
0
        /// <summary>
        /// WithStatement is translated to the DLR AST equivalent to
        /// the following Python code snippet (from with statement spec):
        ///
        /// mgr = (EXPR)
        /// exit = mgr.__exit__  # Not calling it yet
        /// value = mgr.__enter__()
        /// exc = True
        /// try:
        ///     VAR = value  # Only if "as VAR" is present
        ///     BLOCK
        /// except:
        ///     # The exceptional case is handled here
        ///     exc = False
        ///     if not exit(*sys.exc_info()):
        ///         raise
        ///     # The exception is swallowed if exit() returns true
        /// finally:
        ///     # The normal and non-local-goto cases are handled here
        ///     if exc:
        ///         exit(None, None, None)
        ///
        /// </summary>
        public override MSAst.Expression Reduce()
        {
            // Five statements in the result...
            ReadOnlyCollectionBuilder <MSAst.Expression>          statements = new ReadOnlyCollectionBuilder <MSAst.Expression>(6);
            ReadOnlyCollectionBuilder <MSAst.ParameterExpression> variables  = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>(6);

            MSAst.ParameterExpression lineUpdated = Ast.Variable(typeof(bool), "$lineUpdated_with");
            variables.Add(lineUpdated);

            //******************************************************************
            // 1. mgr = (EXPR)
            //******************************************************************
            MSAst.ParameterExpression manager = Ast.Variable(typeof(object), "with_manager");
            variables.Add(manager);
            statements.Add(
                GlobalParent.AddDebugInfo(
                    Ast.Assign(
                        manager,
                        _contextManager
                        ),
                    new SourceSpan(Start, _header)
                    )
                );

            //******************************************************************
            // 2. exit = mgr.__exit__  # Not calling it yet
            //******************************************************************
            MSAst.ParameterExpression exit = Ast.Variable(typeof(object), "with_exit");
            variables.Add(exit);
            statements.Add(
                MakeAssignment(
                    exit,
                    GlobalParent.Get(
                        "__exit__",
                        manager
                        )
                    )
                );

            //******************************************************************
            // 3. value = mgr.__enter__()
            //******************************************************************
            MSAst.ParameterExpression value = Ast.Variable(typeof(object), "with_value");
            variables.Add(value);
            statements.Add(
                GlobalParent.AddDebugInfoAndVoid(
                    MakeAssignment(
                        value,
                        Parent.Invoke(
                            new CallSignature(0),
                            Parent.LocalContext,
                            GlobalParent.Get(
                                "__enter__",
                                manager
                                )
                            )
                        ),
                    new SourceSpan(Start, _header)
                    )
                );

            //******************************************************************
            // 4. exc = True
            //******************************************************************
            MSAst.ParameterExpression exc = Ast.Variable(typeof(bool), "with_exc");
            variables.Add(exc);
            statements.Add(
                MakeAssignment(
                    exc,
                    AstUtils.Constant(true)
                    )
                );

            //******************************************************************
            //  5. The final try statement:
            //
            //  try:
            //      VAR = value  # Only if "as VAR" is present
            //      BLOCK
            //  except:
            //      # The exceptional case is handled here
            //      exc = False
            //      if not exit(*sys.exc_info()):
            //          raise
            //      # The exception is swallowed if exit() returns true
            //  finally:
            //      # The normal and non-local-goto cases are handled here
            //      if exc:
            //          exit(None, None, None)
            //******************************************************************

            MSAst.ParameterExpression exception;
            MSAst.ParameterExpression nestedFrames = Ast.Variable(typeof(List <DynamicStackFrame>), "$nestedFrames");
            variables.Add(nestedFrames);
            statements.Add(
                // try:
                AstUtils.Try(
                    AstUtils.Try(// try statement body
                        PushLineUpdated(false, lineUpdated),
                        _var != null ?
                        (MSAst.Expression)Ast.Block(
                            // VAR = value
                            _var.TransformSet(SourceSpan.None, value, PythonOperationKind.None),
                            // BLOCK
                            _body,
                            AstUtils.Empty()
                            ) :
                        // BLOCK
                        (MSAst.Expression)_body // except:, // try statement location
                        ).Catch(exception = Ast.Variable(typeof(Exception), "exception"),
                                                // Python specific exception handling code
                                TryStatement.GetTracebackHeader(
                                    this,
                                    exception,
                                    GlobalParent.AddDebugInfoAndVoid(
                                        Ast.Block(
                                            // exc = False
                                            MakeAssignment(
                                                exc,
                                                AstUtils.Constant(false)
                                                ),
                                            Ast.Assign(
                                                nestedFrames,
                                                Ast.Call(AstMethods.GetAndClearDynamicStackFrames)
                                                ),
                                            //  if not exit(*sys.exc_info()):
                                            //      raise
                                            AstUtils.IfThen(
                                                GlobalParent.Convert(
                                                    typeof(bool),
                                                    ConversionResultKind.ExplicitCast,
                                                    GlobalParent.Operation(
                                                        typeof(bool),
                                                        PythonOperationKind.IsFalse,
                                                        MakeExitCall(exit, exception)
                                                        )
                                                    ),
                                                UpdateLineUpdated(true),
                                                Ast.Call(
                                                    AstMethods.SetDynamicStackFrames,
                                                    nestedFrames
                                                    ),
                                                Ast.Throw(
                                                    Ast.Call(
                                                        AstMethods.MakeRethrowExceptionWorker,
                                                        exception
                                                        )
                                                    )
                                                )
                                            ),
                                        _body.Span
                                        )
                                    ),
                                Ast.Call(
                                    AstMethods.SetDynamicStackFrames,
                                    nestedFrames
                                    ),
                                PopLineUpdated(lineUpdated),
                                Ast.Empty()
                                )
                    // finally:
                    ).Finally(
                    //  if exc:
                    //      exit(None, None, None)
                    AstUtils.IfThen(
                        exc,
                        GlobalParent.AddDebugInfoAndVoid(
                            Ast.Block(
                                Ast.Dynamic(
                                    GlobalParent.PyContext.Invoke(
                                        new CallSignature(3)        // signature doesn't include function
                                        ),
                                    typeof(object),
                                    new MSAst.Expression[] {
                Parent.LocalContext,
                exit,
                AstUtils.Constant(null),
                AstUtils.Constant(null),
                AstUtils.Constant(null)
            }
                                    ),
                                Ast.Empty()
                                ),
                            _contextManager.Span
                            )
                        )
                    )
                );

            statements.Add(AstUtils.Empty());
            return(Ast.Block(variables.ToReadOnlyCollection(), statements.ToReadOnlyCollection()));
        }
Exemple #30
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));
        }