示例#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
 protected virtual void DefineArguments(Compiler.SemanticNodes.BlockNode node)
 {
     for (int i = 0; i < node.Arguments.Count; i++)
     {
         this.Context.DefineArgument(node.Arguments[i].Token.Value);
     }
 }
示例#3
0
        public override Expression VisitBlock(Compiler.SemanticNodes.BlockNode node)
        {
            for (int i = 0; i < node.Arguments.Count; i++)
            {
                string name = node.Arguments[i].Token.Value;
                // This is used by the inlined blocks.
                // If already defined, do not define it twice ... because it's given externally.
                // See: DefineExternalArgument
                if (this.Context.LocalScope.GetBinding(name) != null)
                {
                    continue;
                }
                this.Context.DefineArgument(name);
            }

            foreach (TemporaryVariableNode tmp in node.Temporaries)
            {
                this.Context.DefineTemporary(tmp.Token.Value);
            }

            List <Expression> expressions = new List <Expression>();

            NameBinding nilBinding = this.Context.GetBinding(SemanticConstants.Nil);

            // On each execution init all temp-vars with nil
            foreach (TemporaryBinding tmp in this.Context.Temporaries)
            {
                expressions.Add(tmp.GenerateAssignExpression(nilBinding.GenerateReadExpression(this), this));
            }

            StatementVisitor visitor = new StatementVisitor(this);

            if (node.Statements != null)
            {
                expressions.AddRange(node.Statements.Accept(visitor));
            }

            if (expressions.Count == 0)
            {
                expressions.Add(nilBinding.GenerateReadExpression(this));
            }

#if DEBUG
            if (expressions.Count == 0)
            {
                throw new InternalCodeGenerationException("We did expect at least ONE expression");
            }

            foreach (var expr in expressions)
            {
                if (expr.Type != typeof(object))
                {
                    throw new InternalCodeGenerationException(String.Format("Expression does not return object! \n{0}", expr));
                }
            }
#endif

            return(this.Context.GeneratePrologAndEpilogue(expressions));
        }
示例#4
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);
        }
示例#5
0
 private Expression InlineTimesRepeat(Compiler.SemanticNodes.BlockNode block)
 {
     /// timesRepeat: aBlock
     /// Inlines to:
     ///     1 to: self by: 1 do: aBlock
     return(this.InlineToByDo(
                Expression.Constant(1, typeof(int)),
                this.Receiver,
                Expression.Constant(1, typeof(int)),
                block));
 }
示例#6
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)));
        }
示例#7
0
 private Expression InlineToByDo(Compiler.SemanticNodes.KeywordArgumentNode stop, Compiler.SemanticNodes.KeywordArgumentNode by, Compiler.SemanticNodes.BlockNode block)
 {
     return(this.InlineToByDo(this.Receiver, stop.Accept(this), by.Accept(this), block));
 }
示例#8
0
 private Expression InlineToDo(Compiler.SemanticNodes.KeywordArgumentNode stop, Compiler.SemanticNodes.BlockNode block)
 {
     /// to: stop do: aBlock
     /// Inlines to:
     ///     self to: stop by: 1 do: aBlock
     return(this.InlineToByDo(this.Receiver, stop.Accept(this), Expression.Constant(1, typeof(int)), block));
 }
示例#9
0
 private Expression InlineMessageSend(Compiler.SemanticNodes.KeywordMessageSequenceNode node)
 {
     if (this.CascadeReceiver != null)
     {
         return(null);
     }
     if (this.IsSuperSend)
     {
         return(null);
     }
     if ((node.Message.SelectorTokens.Count == 1) && (node.Message.Arguments.Count == 1))
     {
         Compiler.SemanticNodes.BlockNode block = node.Message.Arguments[0].Primary as Compiler.SemanticNodes.BlockNode;
         if ((block != null) && (block.Arguments.Count == 0) && (node.Message.Arguments[0].Messages == null))
         {
             if (node.Message.SelectorTokens[0].Value == "ifTrue:")
             {
                 return(this.InlineIfTrueIfFalse(block, null));
             }
             if (node.Message.SelectorTokens[0].Value == "ifFalse:")
             {
                 return(this.InlineIfTrueIfFalse(null, block));
             }
             if (node.Message.SelectorTokens[0].Value == "and:")
             {
                 return(this.InlineAnd(block));
             }
             if (node.Message.SelectorTokens[0].Value == "or:")
             {
                 return(this.InlineOr(block));
             }
             if (node.Message.SelectorTokens[0].Value == "timesRepeat:")
             {
                 return(this.InlineTimesRepeat(block));
             }
         }
     }
     else if ((node.Message.SelectorTokens.Count == 2) && (node.Message.Arguments.Count == 2))
     {
         Compiler.SemanticNodes.BlockNode block1 = node.Message.Arguments[0].Primary as Compiler.SemanticNodes.BlockNode;
         Compiler.SemanticNodes.BlockNode block2 = node.Message.Arguments[1].Primary as Compiler.SemanticNodes.BlockNode;
         if ((block1 != null) && (block1.Arguments.Count == 0) && (node.Message.Arguments[0].Messages == null))
         {
             if ((block2 != null) && (block2.Arguments.Count == 0) && (node.Message.Arguments[1].Messages == null))
             {
                 if ((node.Message.SelectorTokens[0].Value == "ifTrue:") && (node.Message.SelectorTokens[1].Value == "ifFalse:"))
                 {
                     return(this.InlineIfTrueIfFalse(block1, block2));
                 }
                 if ((node.Message.SelectorTokens[0].Value == "ifFalse:") && (node.Message.SelectorTokens[1].Value == "ifTrue:"))
                 {
                     return(this.InlineIfTrueIfFalse(block2, block1));
                 }
             }
         }
         if ((block2 != null) && (block2.Arguments.Count == 1) && (node.Message.Arguments[1].Messages == null))
         {
             if ((node.Message.SelectorTokens[0].Value == "to:") && (node.Message.SelectorTokens[1].Value == "do:"))
             {
                 return(this.InlineToDo(node.Message.Arguments[0], block2));
             }
         }
     }
     else if ((node.Message.SelectorTokens.Count == 3) && (node.Message.Arguments.Count == 3))
     {
         Compiler.SemanticNodes.BlockNode block = node.Message.Arguments[2].Primary as Compiler.SemanticNodes.BlockNode;
         if ((block != null) && (block.Arguments.Count == 1) && (node.Message.Arguments[2].Messages == null))
         {
             if ((node.Message.SelectorTokens[0].Value == "to:") && (node.Message.SelectorTokens[1].Value == "by:") && (node.Message.SelectorTokens[2].Value == "do:"))
             {
                 return(this.InlineToByDo(node.Message.Arguments[0], node.Message.Arguments[1], block));
             }
         }
     }
     return(null);
 }