Пример #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
        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));
        }
Пример #3
0
        private Expression EncodeInlineWhile(BlockNode conditionBlock, BlockNode valueBlock, bool whileFalse)
        {
            NameBinding nilBinding          = this.Context.GetBinding(SemanticConstants.Nil);
            Expression  conditionExpression = Expression.Convert(conditionBlock.Accept(new InlineBlockVisitor(this)), typeof(bool));

            // No, it's not an error ... if the <conditionExpression> evaluates to true, we terminate
            if (whileFalse)
            {
                conditionExpression = Expression.IsTrue(conditionExpression);
            }
            else
            {
                conditionExpression = Expression.IsFalse(conditionExpression);
            }
            LabelTarget    exitLabel = Expression.Label(typeof(object));
            GotoExpression exitLoop  = Expression.Break(exitLabel, nilBinding.GenerateReadExpression(this));

            Expression loop;

            if (valueBlock == null)
            {
                loop = Expression.IfThen(conditionExpression, exitLoop);
            }
            else
            {
                loop = Expression.IfThenElse(conditionExpression, exitLoop, valueBlock.Accept(new InlineBlockVisitor(this)));
            }

            return(Expression.Loop(loop, exitLabel));
        }
Пример #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
        public override Expression VisitVariableReferencele(VariableReferenceleNode node)
        {
            NameBinding target = this.Context.GetBinding(node.Token.Value);

            if (target.IsErrorBinding)
            {
                throw new BindingCodeGeneraionException(target, node);
            }
            this.IsSuperSend = (node.Token.Value == SemanticConstants.Super);
            this.IsConstant  = target.IsConstantValueBinding;
            return(target.GenerateReadExpression(this));
        }
Пример #6
0
        protected override List <Expression> GenerateExpressions(InitializerNode node, out StatementVisitor visitor)
        {
            List <Expression> expressions = base.GenerateExpressions(node, out visitor);

            if (expressions.Count == 0)
            {
                NameBinding binding = this.Context.GetBinding(SemanticConstants.Self);
                if (binding.IsErrorBinding)
                {
                    binding = this.Context.GetBinding(SemanticConstants.Nil);
                }
                expressions.Add(binding.GenerateReadExpression(this));
            }

            return(expressions);
        }
Пример #7
0
        protected override List <Expression> GenerateExpressions(MethodNode node, out StatementVisitor visitor)
        {
            List <Expression> expressions = new List <Expression>();

            if (node.Primitive != null)
            {
                expressions.AddRange(node.Primitive.Accept(new PrimitiveCallVisitor(this, (node.Statements != null))));
            }

            expressions.AddRange(base.GenerateExpressions(node, out visitor));

            if ((node.Primitive == null) && ((expressions.Count == 0) || !visitor.HasReturned))
            {
                // If no explicit return, a method must return self.
                NameBinding binding = this.Context.GetBinding(SemanticConstants.Self);
                expressions.Add(binding.GenerateReadExpression(this));
            }

            return(expressions);
        }
        /// <summary>
        /// Visits the Primitive Call node.
        /// </summary>
        /// <param name="node">The node to visit.</param>
        /// <remarks>
        /// This is the place where primitive calls are encoded to expressions and where most of the interop to the .Net framework happens.
        /// </remarks>
        public override List <Expression> VisitPrimitiveCall(Compiler.SemanticNodes.PrimitiveCallNode node)
        {
            // Large case with the API conventions we support;
            // Each generates an Expression to perform the primitive call.
            Expression primitiveCall;

            try
            {
                primitiveCall = this.GeneratePrimitiveExpression(node);
            }
            catch (CodeGenerationException ex)
            {
                ex.SetErrorLocation(node);
                throw;
            }

            // We need to handle void returns, because Smalltalk always needs a valid receiver.
            NameBinding selfBinding = this.MethodVisitor.Context.GetBinding(SemanticConstants.Self);

            if (primitiveCall.Type == typeof(void))
            {
                primitiveCall = Expression.Block(primitiveCall, selfBinding.GenerateReadExpression(this));
            }
            else if (primitiveCall.Type != typeof(object))
            {
                primitiveCall = Expression.Convert(primitiveCall, typeof(object));
            }
            // A successful primitive call must return directly without executing any other statements.
            primitiveCall = this.Context.Return(primitiveCall);

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

            if (this.HasFallbackCode)
            {
                // This is the case, where some Smalltalk fall-back code follows the primitive call.
                // In this case, we encapsulate the primitive call in a try-catch block, similar to:
                //      object _exception;          // optional ... defined by the Smalltalk method
                //      try
                //      {
                //          return (object) primitiveCall();
                //      } catch (Exception exception) {
                //          _exception = exception;         // optional ... only if "_exception" variable is declared.
                //      };
                Expression handler;
                // This is the special hardcoded temp variable we are looking for.
                NameBinding         exceptionVariable = this.MethodVisitor.GetLocalVariable("_exception");
                ParameterExpression expetionParam     = Expression.Parameter(typeof(Exception), "exception");
                if (!exceptionVariable.IsErrorBinding && (exceptionVariable is IAssignableBinding))
                {
                    // Case of handler block that sets the "_exception" temporary variable and has "self" as the last statement.
                    handler = Expression.Block(
                        ((IAssignableBinding)exceptionVariable).GenerateAssignExpression(expetionParam, this),
                        Expression.Convert(selfBinding.GenerateReadExpression(this), typeof(object)));
                }
                else
                {
                    // Case of handler block that has "self" as the one and only statement
                    handler = Expression.Convert(selfBinding.GenerateReadExpression(this), typeof(object));
                }
                // Create the try/catch block.
                result.Add(Expression.TryCatch(primitiveCall,
                                               Expression.Catch(typeof(BlockResult), Expression.Rethrow(typeof(object))),
                                               Expression.Catch(expetionParam, handler)));
            }
            else
            {
                // This is the case, where none Smalltalk fall-back code follows the primitive call.
                // The API call is called directly without any encapsulation in a try-catch block, similar to:
                //      return (object) primitiveCall();
                // If it fails, it fails and an exception is thrown. The sender of the Smalltalk method
                // is responsible for handling exceptions manually.
                result.Add(primitiveCall);
            }

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