Пример #1
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.CurrentScopeVariable));
            }

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

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

            // method:
            return(Methods.MethodRedo.OpCall(gen.CurrentScopeVariable));
        }
Пример #2
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())));
        }
Пример #3
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.CurrentScopeVariable, AstUtils.Box(transformedReturnValue)));
            }

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

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

            // method:
            return(Methods.MethodNext.OpCall(gen.CurrentScopeVariable, AstUtils.Box(transformedReturnValue)));
        }
Пример #4
0
                protected override bool Walk(ReturnStatement node)
                {
                    Variable var;
                    var      mce = node.Expression as MethodCallExpression;

                    if (mce != null && IsTCE(mce, out var))
                    {
                        if (!(Current.Body is LabeledStatement))
                        {
                            Current.Body = Ast.Labeled(Current.Body);
                        }

                        var ee    = new List <Expression>();
                        int i     = 0;
                        var temps = new List <Variable>();
                        foreach (var par in Current.Parameters)
                        {
                            var v = Current.CreateLocalVariable((SymbolId)Builtins.GenSym(par.Name), par.Type);
                            ee.Add(Ast.Assign(v, mce.Arguments[i++]));
                            temps.Add(v);
                        }
                        i = 0;
                        foreach (var par in Current.Parameters)
                        {
                            ee.Add(Ast.Assign(par, Ast.Read(temps[i++])));
                        }
                        ee.Add(Ast.Void(Ast.Continue(mce.Span)));
                        node.Expression = Ast.Comma(ee);

                        if (var != null)
                        {
                            var.Lift = false;
                            fixups.Add(var.Block);
                        }

                        Current.Bind();
                    }

                    return(base.Walk(node));
                }
Пример #5
0
        private MSA.Expression /*!*/ TransformExceptionHandling(AstGenerator /*!*/ gen, ResultOperation resultOperation)
        {
            Assert.NotNull(gen);

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

            MSA.ParameterExpression unwinder, exceptionVariable;
            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, AstUtils.Constant(null))
                            ),
                        Ast.Throw(oldExceptionVariable)
                        )
                    );
            }
            else
            {
                // rethrow:
                transformedEnsure = AstUtils.IfThen(
                    Ast.AndAlso(
                        exceptionRethrowVariable,
                        Ast.NotEqual(
                            Ast.Assign(oldExceptionVariable, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)),
                            AstUtils.Constant(null, typeof(Exception)))
                        ),
                    Ast.Throw(oldExceptionVariable)
                    );
            }

            if (_elseStatements != null)
            {
                transformedElse = gen.TransformStatements(_elseStatements, resultOperation);
            }
            else
            {
                transformedElse = AstUtils.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 enterRescue = null, leaveRescue = null;
            var            retryLabel = Ast.Label("retry");

            // make rescue clause:
            MSA.Expression transformedRescue;
            if (_rescueClauses != null)
            {
                // outer-most EH blocks sets and clears runtime flag RuntimeFlowControl.InTryRescue:
                if (gen.CurrentRescue == null)
                {
                    enterRescue = Methods.EnterRescue.OpCall(gen.CurrentScopeVariable);
                    leaveRescue = Methods.LeaveRescue.OpCall(gen.CurrentScopeVariable);
                }
                else
                {
                    enterRescue = leaveRescue = AstUtils.Empty();
                }

                gen.EnterRescueClause(retryingVariable, retryLabel);

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

                transformedRescue =
                    AstUtils.Try(
                        enterRescue,
                        AstUtils.If(handlers, Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(true)))
                        ).Filter(unwinder = Ast.Parameter(typeof(EvalUnwinder), "#u"),
                                 Ast.Equal(Ast.Field(unwinder, EvalUnwinder.ReasonField), AstUtils.Constant(BlockReturnReason.Retry)),

                                 Ast.Block(
                                     Ast.Assign(retryingVariable, AstUtils.Constant(true)),
                                     Ast.Continue(retryLabel),
                                     AstUtils.Empty()
                                     )
                                 );


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

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

            var result = Ast.Block(
                Ast.Label(retryLabel),
                AstUtils.Try(
                    Ast.Assign(exceptionThrownVariable, AstUtils.Constant(false)),
                    Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(false)),
                    Ast.Assign(retryingVariable, AstUtils.Constant(false)),

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

                    AstUtils.Try(
                        Ast.Block(transformedBody, AstUtils.Empty())
                        ).Filter(exceptionVariable = Ast.Parameter(typeof(Exception), "#e"),
                                 Methods.CanRescue.OpCall(gen.CurrentScopeVariable, exceptionVariable),

                                 Ast.Assign(exceptionThrownVariable, AstUtils.Constant(true)),
                                 transformedRescue,
                                 AstUtils.Empty()
                                 ).FinallyIf((_rescueClauses != null),
                                             // restore previous exception if the current one has been handled:
                                             AstUtils.Unless(exceptionRethrowVariable,
                                                             Methods.SetCurrentException.OpCall(gen.CurrentScopeVariable, oldExceptionVariable)
                                                             ),
                                             leaveRescue
                                             ),

                    // unless (exception_thrown) do <else-statements> end
                    transformedElse,
                    AstUtils.Empty()
                    ).FilterIf((_rescueClauses != null || _elseStatements != null),
                               exceptionVariable = Ast.Parameter(typeof(Exception), "#e"),
                               Methods.CanRescue.OpCall(gen.CurrentScopeVariable, exceptionVariable),

                               Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(true)),
                               AstUtils.Empty()
                               ).FinallyWithJumps(
                    AstUtils.Unless(retryingVariable, transformedEnsure)
                    )
                );

            return(result);
        }
Пример #6
0
                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);
                }
Пример #7
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)
                       ));
        }