예제 #1
0
        private BoundBlock BuildBlock(BoundStatement node)
        {
            var block = node as BoundBlock;
            if (block != null)
                return block;

            var builder = new BlockBuilder(this);

            builder.Add(node);

            return builder.BuildBlock(node.Location);
        }
예제 #2
0
        private BoundBlock BuildBlock(SyntaxNode syntax, SourceLocation location)
        {
            IEnumerable<SyntaxNode> items;
            var block = syntax as BlockSyntax;
            if (block != null)
                items = block.Statements;
            else
                items = new[] { syntax };

            var builder = new BlockBuilder(this);

            foreach (var item in items)
            {
                var node = item.Accept(this);

                var statement =
                    node as BoundStatement ??
                    new BoundExpressionStatement((BoundExpression)node, GetLocation(item));

                builder.Add(statement);
            }

            return builder.BuildBlock(location ?? SourceLocation.Missing);
        }
예제 #3
0
        //
        // rescue stmts                     ... if (StandardError === $!) { stmts; } 
        // rescue <types> stmts             ... temp1 = type1; ...; if (<temp1> === $! || ...) { stmts; }
        // rescue <types> => <lvalue> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { <lvalue> = $!; stmts; }
        // 
        internal IfStatementTest/*!*/ Transform(AstGenerator/*!*/ gen, ResultOperation resultOperation) {
            Assert.NotNull(gen);

            MSA.Expression condition;
            if (_types.Length != 0 || _splatType != null) {
                var comparisonSiteStorage = Ast.Constant(new BinaryOpStorage(gen.Context));

                if (_types.Length == 0) {
                    // splat only:
                    condition = MakeCompareSplattedExceptions(gen, comparisonSiteStorage, TransformSplatType(gen));
                } else if (_types.Length == 1 && _splatType == null) {
                    condition = MakeCompareException(gen, comparisonSiteStorage, _types[0].TransformRead(gen));
                } else {

                    // forall{i}: <temps[i]> = evaluate type[i]
                    var temps = new MSA.Expression[_types.Length + (_splatType != null ? 1 : 0)];
                    var exprs = new BlockBuilder();
                    
                    int i = 0;
                    while (i < _types.Length) {
                        var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, typeof(object));
                        temps[i] = tmp;
                        exprs.Add(Ast.Assign(tmp, _types[i].TransformRead(gen)));
                        i++;
                    }

                    if (_splatType != null) {
                        var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, typeof(IList));
                        temps[i] = tmp;
                        exprs.Add(Ast.Assign(tmp, TransformSplatType(gen)));

                        i++;
                    }

                    Debug.Assert(i == temps.Length);

                    // CompareException(<temps[0]>) || ... CompareException(<temps[n]>) || CompareSplattedExceptions(<splatTypes>)
                    i = 0;
                    condition = MakeCompareException(gen, comparisonSiteStorage, temps[i++]);
                    while (i < _types.Length) {
                        condition = Ast.OrElse(condition, MakeCompareException(gen, comparisonSiteStorage, temps[i++]));
                    }

                    if (_splatType != null) {
                        condition = Ast.OrElse(condition, MakeCompareSplattedExceptions(gen, comparisonSiteStorage, temps[i++]));
                    }

                    Debug.Assert(i == temps.Length);

                    // (temps[0] = type[0], ..., temps[n] == type[n], condition)
                    exprs.Add(condition);
                    condition = exprs;
                }

            } else {
                condition = Methods.CompareDefaultException.OpCall(gen.CurrentScopeVariable);
            }

            return AstUtils.IfCondition(condition,
                gen.TransformStatements(
                    // <lvalue> = e;
                    (_target != null) ? _target.TransformWrite(gen, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)) : null,

                    // body:
                    _statements,

                    resultOperation
                )
            );
        }
예제 #4
0
        private MSAst.Expression ReduceWorker(bool optimizeDynamicConvert) {
            MSAst.Expression result;

            if (_tests.Length > 100) {
                // generate:
                // if(x) {
                //   body
                //   goto end
                // } else { 
                // }
                // elseBody
                // end:
                //
                // to avoid deeply recursive trees which can stack overflow.
                BlockBuilder builder = new BlockBuilder();
                var label = Ast.Label();
                for (int i = 0; i < _tests.Length; i++) {
                    IfStatementTest ist = _tests[i];

                    builder.Add(
                        Ast.Condition(
                            optimizeDynamicConvert ?
                                TransformAndDynamicConvert(ist.Test, typeof(bool)) :
                                GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, ist.Test),
                            Ast.Block(
                                TransformMaybeSingleLineSuite(ist.Body, GlobalParent.IndexToLocation(ist.Test.StartIndex)),
                                Ast.Goto(label)
                            ),
                            Utils.Empty()
                        )
                    );
                }

                if (_else != null) {
                    builder.Add(_else);
                }

                builder.Add(Ast.Label(label));
                result = builder.ToExpression();
            } else {
                // Now build from the inside out
                if (_else != null) {
                    result = _else;
                } else {
                    result = AstUtils.Empty();
                }

                int i = _tests.Length;
                while (i-- > 0) {
                    IfStatementTest ist = _tests[i];

                    result = GlobalParent.AddDebugInfoAndVoid(
                        Ast.Condition(
                            optimizeDynamicConvert ?
                                TransformAndDynamicConvert(ist.Test, typeof(bool)) :
                                GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, ist.Test),
                            TransformMaybeSingleLineSuite(ist.Body, GlobalParent.IndexToLocation(ist.Test.StartIndex)),
                            result
                        ),
                        new SourceSpan(GlobalParent.IndexToLocation(ist.StartIndex), GlobalParent.IndexToLocation(ist.HeaderIndex))
                    );
                }
            }

            return result;
        }
예제 #5
0
        private MSAst.Expression ReduceWorker(bool optimizeDynamicConvert)
        {
            MSAst.Expression result;

            if (_tests.Length > 100)
            {
                // generate:
                // if(x) {
                //   body
                //   goto end
                // } else {
                // }
                // elseBody
                // end:
                //
                // to avoid deeply recursive trees which can stack overflow.
                BlockBuilder builder = new BlockBuilder();
                var          label   = Ast.Label();
                for (int i = 0; i < _tests.Length; i++)
                {
                    IfStatementTest ist = _tests[i];

                    builder.Add(
                        Ast.Condition(
                            optimizeDynamicConvert ?
                            TransformAndDynamicConvert(ist.Test, typeof(bool)) :
                            GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, ist.Test),
                            Ast.Block(
                                TransformMaybeSingleLineSuite(ist.Body, GlobalParent.IndexToLocation(ist.Test.StartIndex)),
                                Ast.Goto(label)
                                ),
                            Utils.Empty()
                            )
                        );
                }

                if (_else != null)
                {
                    builder.Add(_else);
                }

                builder.Add(Ast.Label(label));
                result = builder.ToExpression();
            }
            else
            {
                // Now build from the inside out
                if (_else != null)
                {
                    result = _else;
                }
                else
                {
                    result = AstUtils.Empty();
                }

                int i = _tests.Length;
                while (i-- > 0)
                {
                    IfStatementTest ist = _tests[i];

                    result = GlobalParent.AddDebugInfoAndVoid(
                        Ast.Condition(
                            optimizeDynamicConvert ?
                            TransformAndDynamicConvert(ist.Test, typeof(bool)) :
                            GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, ist.Test),
                            TransformMaybeSingleLineSuite(ist.Body, GlobalParent.IndexToLocation(ist.Test.StartIndex)),
                            result
                            ),
                        new SourceSpan(GlobalParent.IndexToLocation(ist.StartIndex), GlobalParent.IndexToLocation(ist.HeaderIndex))
                        );
                }
            }

            return(result);
        }
예제 #6
0
        //
        // rescue stmts                     ... if (StandardError === $!) { stmts; }
        // rescue <types> stmts             ... temp1 = type1; ...; if (<temp1> === $! || ...) { stmts; }
        // rescue <types> => <lvalue> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { <lvalue> = $!; stmts; }
        //
        /*!*/
        internal IfStatementTest Transform(AstGenerator/*!*/ gen, ResultOperation resultOperation)
        {
            Assert.NotNull(gen);

            MSA.Expression condition;
            if (_types.Length != 0) {
                var comparisonSiteStorage = Ast.Constant(new BinaryOpStorage(gen.Context));

                if (_types.Length == 1) {
                    condition = MakeCompareException(gen, comparisonSiteStorage, _types[0].TransformRead(gen), _types[0] is SplattedArgument);
                } else {
                    // forall{i}: <temps[i]> = evaluate type[i]
                    var temps = new MSA.Expression[_types.Length];
                    var exprs = new BlockBuilder();

                    for (int i = 0; i < _types.Length; i++) {
                        var t = _types[i].TransformRead(gen);
                        var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, t.Type);
                        temps[i] = tmp;
                        exprs.Add(Ast.Assign(tmp, t));
                    }

                    // CompareException(<temps[0]>) || ... CompareException(<temps[n]>) || CompareSplattedExceptions(<splatTypes>)
                    condition = MakeCompareException(gen, comparisonSiteStorage, temps[0], _types[0] is SplattedArgument);
                    for (int i = 1; i < _types.Length; i++) {
                        condition = Ast.OrElse(condition, MakeCompareException(gen, comparisonSiteStorage, temps[i], _types[i] is SplattedArgument));
                    }

                    // (temps[0] = type[0], ..., temps[n] == type[n], condition)
                    exprs.Add(condition);
                    condition = exprs;
                }
            } else {
                condition = Methods.CompareDefaultException.OpCall(gen.CurrentScopeVariable);
            }

            return AstUtils.IfCondition(condition,
                gen.TransformStatements(
                    // <lvalue> = e;
                    (_target != null) ? _target.TransformWrite(gen, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)) : null,

                    // body:
                    _statements,

                    resultOperation
                )
            );
        }
예제 #7
0
        //
        // rescue stmts                     ... if (StandardError === $!) { stmts; }
        // rescue <types> stmts             ... temp1 = type1; ...; if (<temp1> === $! || ...) { stmts; }
        // rescue <types> => <lvalue> stmts ... temp1 = type1; ...; if (<temp1> === $! || ...) { <lvalue> = $!; stmts; }
        //
        internal IfStatementTest /*!*/ Transform(AstGenerator /*!*/ gen, ResultOperation resultOperation)
        {
            Assert.NotNull(gen);

            MSA.Expression condition;
            if (_types.Length != 0 || _splatType != null)
            {
                var comparisonSiteStorage = Ast.Constant(new BinaryOpStorage(gen.Context));

                if (_types.Length == 0)
                {
                    // splat only:
                    condition = MakeCompareSplattedExceptions(gen, comparisonSiteStorage, TransformSplatType(gen));
                }
                else if (_types.Length == 1 && _splatType == null)
                {
                    condition = MakeCompareException(gen, comparisonSiteStorage, _types[0].TransformRead(gen));
                }
                else
                {
                    // forall{i}: <temps[i]> = evaluate type[i]
                    var temps = new MSA.Expression[_types.Length + (_splatType != null ? 1 : 0)];
                    var exprs = new BlockBuilder();

                    int i = 0;
                    while (i < _types.Length)
                    {
                        var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, typeof(object));
                        temps[i] = tmp;
                        exprs.Add(Ast.Assign(tmp, _types[i].TransformRead(gen)));
                        i++;
                    }

                    if (_splatType != null)
                    {
                        var tmp = gen.CurrentScope.DefineHiddenVariable("#type_" + i, typeof(IList));
                        temps[i] = tmp;
                        exprs.Add(Ast.Assign(tmp, TransformSplatType(gen)));

                        i++;
                    }

                    Debug.Assert(i == temps.Length);

                    // CompareException(<temps[0]>) || ... CompareException(<temps[n]>) || CompareSplattedExceptions(<splatTypes>)
                    i         = 0;
                    condition = MakeCompareException(gen, comparisonSiteStorage, temps[i++]);
                    while (i < _types.Length)
                    {
                        condition = Ast.OrElse(condition, MakeCompareException(gen, comparisonSiteStorage, temps[i++]));
                    }

                    if (_splatType != null)
                    {
                        condition = Ast.OrElse(condition, MakeCompareSplattedExceptions(gen, comparisonSiteStorage, temps[i++]));
                    }

                    Debug.Assert(i == temps.Length);

                    // (temps[0] = type[0], ..., temps[n] == type[n], condition)
                    exprs.Add(condition);
                    condition = exprs;
                }
            }
            else
            {
                condition = Methods.CompareDefaultException.OpCall(gen.CurrentScopeVariable);
            }

            return(AstUtils.IfCondition(condition,
                                        gen.TransformStatements(
                                            // <lvalue> = e;
                                            (_target != null) ? _target.TransformWrite(gen, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)) : null,

                                            // body:
                                            _statements,

                                            resultOperation
                                            )
                                        ));
        }
예제 #8
0
        private BoundIf BuildSetWithScope(BlockBuilder builder, WithScope withScope, IIdentifier fallback, BoundTemporary value)
        {
            var withLocal = builder.CreateTemporary();

            builder.Add(new BoundSetVariable(
                withLocal,
                new BoundGetVariable(_withIdentifiers[withScope.Identifier]), SourceLocation.Missing
            ));

            var setter = new BoundSetMember(
                new BoundGetVariable(withLocal),
                BoundConstant.Create(fallback.Name),
                new BoundGetVariable(value),
                SourceLocation.Missing
            );

            BoundBlock @else;

            if (withScope.Parent == null)
            {
                @else = BuildBlock(BuildSet(
                    fallback,
                    new BoundGetVariable(value)
                ));
            }
            else
            {
                @else = BuildBlock(BuildSetWithScope(
                    builder,
                    withScope.Parent,
                    fallback,
                    value
                ));
            }

            return new BoundIf(
                new BoundHasMember(
                    new BoundGetVariable(withLocal),
                    fallback.Name
                ),
                BuildBlock(setter),
                @else,
                SourceLocation.Missing
            );
        }
예제 #9
0
        private BoundStatement BuildSet(IIdentifier identifier, BoundExpression value)
        {
            switch (identifier.Type)
            {
                case IdentifierType.Parameter:
                    return new BoundSetVariable(
                        _scope.GetArgument(identifier),
                        value,
                        SourceLocation.Missing
                    );

                case IdentifierType.Scoped:
                    var builder = new BlockBuilder(this);

                    var valueTemporary = builder.CreateTemporary();

                    builder.Add(new BoundSetVariable(
                        valueTemporary,
                        value,
                        SourceLocation.Missing
                    ));

                    builder.Add(BuildSetWithScope(builder, identifier.WithScope, identifier.Fallback, valueTemporary));

                    return builder.BuildBlock(SourceLocation.Missing);

                case IdentifierType.Local:
                case IdentifierType.Global:
                    if (identifier.Type == IdentifierType.Global)
                        _scope.IsGlobalScopeReferenced = true;

                    if (identifier.Closure == null)
                        return new BoundSetVariable(_scope.GetLocal(identifier), value, SourceLocation.Missing);

                    return new BoundSetVariable(
                        _scope.GetClosureField(identifier),
                        value,
                        SourceLocation.Missing
                    );

                    /*
                    // These are handled upstream.
                case IdentifierType.This:
                case IdentifierType.Null:
                case IdentifierType.Undefined:
                case IdentifierType.Arguments:
                     */

                default:
                    throw new InvalidOperationException("Cannot find variable of argument");
            }
        }
예제 #10
0
        private BoundIf BuildGetWithScope(BlockBuilder builder, WithScope withScope, IIdentifier fallback, BoundTemporary result, BoundTemporary withTarget)
        {
            var withLocal = builder.CreateTemporary();

            builder.Add(new BoundSetVariable(
                withLocal,
                new BoundGetVariable(_withIdentifiers[withScope.Identifier]),
                SourceLocation.Missing
            ));

            var getter = new BlockBuilder(this);

            if (withTarget != null)
            {
                getter.Add(new BoundSetVariable(
                    withTarget,
                    new BoundGetVariable(withLocal),
                    SourceLocation.Missing
                ));
            }

            getter.Add(new BoundSetVariable(
                result,
                BuildGetMember(
                    new BoundGetVariable(withLocal),
                    BoundConstant.Create(fallback.Name)
                ),
                SourceLocation.Missing
            ));

            BoundBlock @else;

            if (withScope.Parent == null)
            {
                @else = BuildBlock(new BoundSetVariable(
                    result,
                    BuildGet(
                        fallback,
                        null
                    ),
                    SourceLocation.Missing
                ));
            }
            else
            {
                @else = BuildBlock(BuildGetWithScope(
                    builder,
                    withScope.Parent,
                    fallback,
                    result,
                    withTarget
                ));
            }

            return new BoundIf(
                new BoundHasMember(
                    new BoundGetVariable(withLocal),
                    fallback.Name
                ),
                getter.BuildBlock(SourceLocation.Missing),
                @else,
                SourceLocation.Missing
            );
        }
예제 #11
0
        private BoundExpression BuildGet(IIdentifier identifier, BoundTemporary withTarget)
        {
            switch (identifier.Type)
            {
                case IdentifierType.Null: return new BoundGetVariable(BoundMagicVariable.Null);
                case IdentifierType.Undefined: return new BoundGetVariable(BoundMagicVariable.Undefined);

                case IdentifierType.This:
                    _scope.IsThisReferenced = true;
                    return new BoundGetVariable(BoundMagicVariable.This);

                case IdentifierType.Arguments:
                    _scope.IsArgumentsReferenced = true;
                    return new BoundGetVariable(BoundMagicVariable.Arguments);

                case IdentifierType.Parameter:
                    return new BoundGetVariable(_scope.GetArgument(identifier));

                case IdentifierType.Scoped:
                    var builder = new BlockBuilder(this);
                    var result = builder.CreateTemporary();

                    builder.Add(
                        BuildGetWithScope(builder, identifier.WithScope, identifier.Fallback, result, withTarget)
                    );

                    return builder.BuildExpression(result, SourceLocation.Missing);

                case IdentifierType.Local:
                case IdentifierType.Global:
                    if (identifier.Closure != null)
                        return new BoundGetVariable(_scope.GetClosureField(identifier));

                    return new BoundGetVariable(_scope.GetLocal(identifier));

                default:
                    throw new InvalidOperationException("Cannot find variable of argument");
            }
        }