예제 #1
0
        private Expression InlineIfTrueIfFalse(Compiler.SemanticNodes.BlockNode trueBlock, Compiler.SemanticNodes.BlockNode falseBlock)
        {
            NameBinding nilBinding     = this.Context.GetBinding(SemanticConstants.Nil);
            Expression  testExpression = Expression.Convert(this.Receiver, typeof(bool));
            Expression  trueExpression;

            if (trueBlock != null)
            {
                trueExpression = trueBlock.Accept(new InlineBlockVisitor(this));
            }
            else
            {
                trueExpression = nilBinding.GenerateReadExpression(this);
            }
            Expression falseExpression;

            if (falseBlock != null)
            {
                falseExpression = falseBlock.Accept(new InlineBlockVisitor(this));
            }
            else
            {
                falseExpression = nilBinding.GenerateReadExpression(this);
            }

            Expression result = Expression.Condition(testExpression, trueExpression, falseExpression, typeof(object));

            this.SetResult(result);
            return(result);
        }
예제 #2
0
        private Expression InlineOr(Compiler.SemanticNodes.BlockNode block)
        {
            NameBinding trueBinding     = this.Context.GetBinding(SemanticConstants.True);
            Expression  testExpression  = Expression.Convert(this.Receiver, typeof(bool));
            Expression  blockExpression = block.Accept(new InlineBlockVisitor(this));
            Expression  result          = Expression.Condition(testExpression, trueBinding.GenerateReadExpression(this), blockExpression, typeof(object));

            this.SetResult(result);
            return(result);
        }
예제 #3
0
        private Expression InlineToByDo(Expression start, Expression stop, Expression step, Compiler.SemanticNodes.BlockNode block)
        {
            /// to:by:do:

            /* C# semantics of the inlining
             * if ((start is int) && (stop is int) && (step is int))
             * {
             *  int iStart, iStop, iStep;
             *  try
             *  {
             *      iStart = checked((int)start);
             *      iStop = checked((int)stop);
             *      iStep = checked((int)step);
             *      // This is to ensure the calculation below do not fail running unchecked
             *      int na = checked(iStart + iStep);
             *      na = checked(iStop + iStep);
             *  }
             *  catch (OverflowException)
             *  {
             *      goto Int32Overwlow;
             *  }
             *
             *  if (iStep == 0)
             *      throw new ArgumentOutOfRangeException();
             *
             *  if (iStep > 0)
             *  {
             *      do
             *      {
             *          if (iStart > iStop)
             *              goto Exit;
             *          block(iStart);
             *          iStart = iStart + iStep;
             *      } while (true);
             *  }
             *  else
             *  {
             *      do
             *      {
             *          if (iStop > iStart)
             *              goto Exit;
             *          block(iStart);
             *          iStart = iStart + iStep;
             *      } while (true);
             *  }
             * }
             * Int32Overwlow:
             * // We could implement BigInteger optimization here, but too much work and probably not much to gain
             * // Fallback to dynamic invocation
             * dynamic dStart = start;
             * dynamic dStep = step;
             * if (dStep == 0)
             *  throw new ArgumentOutOfRangeException();
             *
             * if (dStep > 0)
             * {
             *  do
             *  {
             *      if (dStart > stop)
             *          goto Exit;
             *      block(dStart);
             *      dStart = dStart + step;
             *  } while (true);
             * }
             * else
             * {
             *  do
             *  {
             *      if (stop > dStart)
             *          goto Exit;
             *      block(dStart);
             *      dStart = dStart + step;
             *  } while (true);
             * }
             * Exit:
             */

            NameBinding nilBinding    = this.Context.GetBinding(SemanticConstants.Nil);
            LabelTarget exitLabel     = Expression.Label(typeof(void));
            LabelTarget overflowLabel = Expression.Label(typeof(void));

            ParameterExpression iStart  = Expression.Variable(typeof(int), "iStart");
            ParameterExpression iStop   = Expression.Variable(typeof(int), "iStop");
            ParameterExpression iStep   = Expression.Variable(typeof(int), "iStep");
            ParameterExpression iNA     = Expression.Variable(typeof(int), "iNA");
            InlineBlockVisitor  visitor = new InlineBlockVisitor(this);

            if (block.Arguments.Count > 0)
            {
                visitor.DefineExternalArgument(block.Arguments[0].Token.Value, Expression.Convert(iStart, typeof(object)));
            }
            Expression integerOperation = block.Accept(visitor);

            Expression integerTest = Expression.AndAlso(Expression.AndAlso(
                                                            Expression.TypeIs(start, typeof(int)), Expression.TypeIs(stop, typeof(int))), Expression.TypeIs(step, typeof(int)));

            Expression integerBlock = Expression.Block(
                Expression.TryCatch(
                    Expression.Block(
                        Expression.Assign(iStart, Expression.ConvertChecked(start, typeof(int))),
                        Expression.Assign(iStop, Expression.ConvertChecked(stop, typeof(int))),
                        Expression.Assign(iStep, Expression.ConvertChecked(step, typeof(int))),
                        Expression.Assign(iNA, Expression.AddChecked(iStart, iStep)),
                        Expression.Assign(iNA, Expression.AddChecked(iStop, iStep))),
                    Expression.Catch(typeof(OverflowException), Expression.Goto(overflowLabel, typeof(int))),
                    Expression.Catch(typeof(InvalidCastException), Expression.Goto(overflowLabel, typeof(int)))),
                Expression.IfThen(
                    Expression.Equal(iStep, Expression.Constant(0)),
                    Expression.Throw(Expression.New(typeof(ArgumentOutOfRangeException)), typeof(object))),
                Expression.IfThenElse(
                    Expression.GreaterThan(iStep, Expression.Constant(0)),
                    Expression.Loop(
                        Expression.IfThenElse(
                            Expression.GreaterThan(iStart, iStop),
                            Expression.Break(exitLabel, nilBinding.GenerateReadExpression(this)),
                            Expression.Block(
                                integerOperation,
                                Expression.AddAssign(iStart, iStep)))),
                    Expression.Loop(
                        Expression.IfThenElse(
                            Expression.GreaterThan(iStop, iStart),
                            Expression.Break(exitLabel, nilBinding.GenerateReadExpression(this)),
                            Expression.Block(
                                integerOperation,
                                Expression.AddAssign(iStart, iStep))))));

            ParameterExpression dStart = Expression.Variable(typeof(object), "dStart");
            ParameterExpression dStep  = Expression.Variable(typeof(object), "dStep");

            visitor = new InlineBlockVisitor(this);
            if (block.Arguments.Count > 0)
            {
                visitor.DefineExternalArgument(block.Arguments[0].Token.Value, dStart);
            }
            Expression dynamicOperation = block.Accept(visitor);

            Expression dynamicBlock = Expression.Block(
                Expression.Assign(dStart, start),
                Expression.Assign(dStep, Expression.Convert(step, typeof(object))),
                Expression.IfThen(
                    Expression.IsTrue(Expression.Convert(this.Context.CompileDynamicCall(this, "=", dStep, PreboxedConstants.Int32_00000000_Expression), typeof(bool))),
                    Expression.Throw(Expression.New(typeof(ArgumentOutOfRangeException)), typeof(object))),
                Expression.IfThenElse(
                    Expression.IsTrue(Expression.Convert(this.Context.CompileDynamicCall(this, ">", dStep, PreboxedConstants.Int32_00000000_Expression), typeof(bool))),
                    Expression.Loop(
                        Expression.IfThenElse(
                            Expression.IsTrue(Expression.Convert(this.Context.CompileDynamicCall(this, ">", dStart, stop), typeof(bool))),
                            Expression.Break(exitLabel, nilBinding.GenerateReadExpression(this)),
                            Expression.Block(
                                dynamicOperation,
                                Expression.Assign(dStart, this.Context.CompileDynamicCall(this, "+", dStart, dStep))))),
                    Expression.Loop(
                        Expression.IfThenElse(
                            Expression.IsTrue(Expression.Convert(this.Context.CompileDynamicCall(this, ">", stop, dStart), typeof(bool))),
                            Expression.Break(exitLabel, nilBinding.GenerateReadExpression(this)),
                            Expression.Block(
                                dynamicOperation,
                                Expression.Assign(dStart, this.Context.CompileDynamicCall(this, "+", dStart, dStep)))))));

            return(Expression.Block(
                       new ParameterExpression[] { iStart, iStop, iStep, iNA, dStart, dStep },
                       integerBlock,
                       Expression.Label(overflowLabel),
                       dynamicBlock,
                       Expression.Label(exitLabel),
                       nilBinding.GenerateReadExpression(this)));
        }