Ejemplo n.º 1
0
        internal Expression Rewrite(Expression expr)
        {
            if (expr is LambdaExpression lambda)
            {
                // just re-write the body, no need for an outer return label
                return(Expression.Lambda(
                           Rewrite(lambda.Body),
                           lambda.Name,
                           lambda.TailCall,
                           lambda.Parameters
                           ));
            }

            // add a label so we can branch when we're propagating out the exception value
            expr = Visit(expr);
            if (expr.Type == typeof(void))
            {
                expr = Expression.Block(expr, Utils.Constant(null));
            }
            else if (expr.Type != typeof(object))
            {
                expr = Expression.Convert(expr, typeof(object));
            }

            return(new LightExceptionRewrittenCode(_returnLabel, expr));
        }
Ejemplo n.º 2
0
        private void MakePropertyRule(SetOrDeleteMemberInfo memInfo, DynamicMetaObject instance, DynamicMetaObject target, Type targetType, MemberGroup properties, DynamicMetaObject errorSuggestion)
        {
            PropertyTracker info = (PropertyTracker)properties[0];

            MethodInfo setter = info.GetSetMethod(true);

            // Allow access to protected getters TODO: this should go, it supports IronPython semantics.
            if (setter != null && !setter.IsPublic && !setter.IsProtected())
            {
                if (!PrivateBinding)
                {
                    setter = null;
                }
            }

            if (setter != null)
            {
                setter = CompilerHelpers.GetCallableMethod(setter, PrivateBinding);

                if (info.IsStatic != (instance == null))
                {
                    memInfo.Body.FinishCondition(
                        errorSuggestion ?? MakeError(
                            MakeStaticPropertyInstanceAccessError(
                                info,
                                true,
                                instance,
                                target
                                ),
                            typeof(object)
                            )
                        );
                }
                else if (info.IsStatic && info.DeclaringType != targetType)
                {
                    memInfo.Body.FinishCondition(
                        errorSuggestion ?? MakeError(
                            MakeStaticAssignFromDerivedTypeError(targetType, instance, info, target, memInfo.ResolutionFactory),
                            typeof(object)
                            )
                        );
                }
                else if (setter.ContainsGenericParameters)
                {
                    memInfo.Body.FinishCondition(
                        MakeGenericPropertyExpression(memInfo)
                        );
                }
                else if (setter.IsPublic && !setter.DeclaringType.IsValueType)
                {
                    if (instance == null)
                    {
                        memInfo.Body.FinishCondition(
                            Ast.Block(
                                AstUtils.SimpleCallHelper(
                                    setter,
                                    ConvertExpression(
                                        target.Expression,
                                        setter.GetParameters()[0].ParameterType,
                                        ConversionResultKind.ExplicitCast,
                                        memInfo.ResolutionFactory
                                        )
                                    ),
                                Ast.Constant(null)
                                )
                            );
                    }
                    else
                    {
                        memInfo.Body.FinishCondition(
                            MakeReturnValue(
                                MakeCallExpression(memInfo.ResolutionFactory, setter, instance, target),
                                target
                                )
                            );
                    }
                }
                else
                {
                    // TODO: Should be able to do better w/ value types.
                    memInfo.Body.FinishCondition(
                        MakeReturnValue(
                            Ast.Call(
                                AstUtils.Constant(((ReflectedPropertyTracker)info).Property), // TODO: Private binding on extension properties
                                typeof(PropertyInfo).GetMethod("SetValue", new Type[] { typeof(object), typeof(object), typeof(object[]) }),
                                instance == null ? AstUtils.Constant(null) : AstUtils.Convert(instance.Expression, typeof(object)),
                                AstUtils.Convert(
                                    ConvertExpression(
                                        target.Expression,
                                        setter.GetParameters()[0].ParameterType,
                                        ConversionResultKind.ExplicitCast,
                                        memInfo.ResolutionFactory
                                        ),
                                    typeof(object)
                                    ),
                                Ast.NewArrayInit(typeof(object))
                                ),
                            target
                            )
                        );
                }
            }
            else
            {
                memInfo.Body.FinishCondition(
                    errorSuggestion ?? MakeError(
                        MakeMissingMemberErrorForAssignReadOnlyProperty(targetType, instance, memInfo.Name), typeof(object)
                        )
                    );
            }
        }
Ejemplo n.º 3
0
        private Expression MakeIncorrectArgumentCountError(BindingTarget target)
        {
            IList <int> available = target.ExpectedArgumentCount;
            int         expected;

            if (available.Count > 0)
            {
                int minGreater = Int32.MaxValue;
                int maxLesser  = Int32.MinValue;
                int max        = Int32.MinValue;
                foreach (int arity in available)
                {
                    if (arity > target.ActualArgumentCount)
                    {
                        minGreater = Math.Min(minGreater, arity);
                    }
                    else
                    {
                        maxLesser = Math.Max(maxLesser, arity);
                    }

                    max = Math.Max(max, arity);
                }

                expected = (target.ActualArgumentCount < maxLesser ? maxLesser : Math.Min(minGreater, max));
            }
            else
            {
                // no overload is callable:
                expected = 0;
            }

            return(Methods.MakeWrongNumberOfArgumentsError.OpCall(AstUtils.Constant(target.ActualArgumentCount), AstUtils.Constant(expected)));
        }
Ejemplo n.º 4
0
        public override Expression /*!*/ Convert(DynamicMetaObject /*!*/ metaObject, Type restrictedType, ParameterInfo info, Type /*!*/ toType)
        {
            Expression expr     = metaObject.Expression;
            Type       fromType = restrictedType ?? expr.Type;

            // block:
            if (fromType == typeof(MissingBlockParam))
            {
                Debug.Assert(toType == typeof(BlockParam) || toType == typeof(MissingBlockParam));
                return(AstUtils.Constant(null));
            }

            if (fromType == typeof(BlockParam) && toType == typeof(MissingBlockParam))
            {
                return(AstUtils.Constant(null));
            }

            // protocol conversions:
            if (info != null && info.IsDefined(typeof(DefaultProtocolAttribute), false))
            {
                var action = RubyConversionAction.TryGetDefaultConversionAction(Context, toType);
                if (action != null)
                {
                    // TODO: inline implicit conversions:
                    return(AstUtils.LightDynamic(action, toType, expr));
                }

                // Do not throw an exception here to allow generic type parameters to be used with D.P. attribute.
                // The semantics should be to use DP if available for the current instantiation and ignore it otherwise.
            }

            if (restrictedType != null)
            {
                if (restrictedType == typeof(DynamicNull))
                {
                    if (!toType.IsValueType() || toType.IsGenericType() && toType.GetGenericTypeDefinition() == typeof(Nullable <>))
                    {
                        return(AstUtils.Constant(null, toType));
                    }
                    else if (toType == typeof(bool))
                    {
                        return(AstUtils.Constant(false));
                    }
                }

                if (toType.IsAssignableFrom(restrictedType))
                {
                    // expr can be converted to restrictedType, which can be converted toType => we can convert expr to toType:
                    return(AstUtils.Convert(expr, CompilerHelpers.GetVisibleType(toType)));
                }

                // if there is a simple conversion from restricted type, convert the expression to the restricted type and use that conversion:
                Type visibleRestrictedType = CompilerHelpers.GetVisibleType(restrictedType);
                if (Converter.CanConvertFrom(metaObject, visibleRestrictedType, toType, false, NarrowingLevel.None, false, false).IsConvertible)
                {
                    expr = AstUtils.Convert(expr, visibleRestrictedType);
                }
            }

            return(Converter.ConvertExpression(expr, toType, _args.RubyContext, _args.MetaContext.Expression, _implicitProtocolConversions));
        }
Ejemplo n.º 5
0
        private SwitchExpression MakeYieldRouter(Type type, int start, int end, LabelTarget newTarget)
        {
            Debug.Assert(end > start);
            var cases = new SwitchCase[end - start];

            for (int i = start; i < end; i++)
            {
                YieldMarker y = _yields[i];
                cases[i - start] = Expression.SwitchCase(Expression.Goto(y.Label, type), AstUtils.Constant(y.State));
                // Any jumps from outer switch statements should go to the this
                // router, not the original label (which they cannot legally jump to)
                y.Label = newTarget;
            }
            return(Expression.Switch(_gotoRouter, Expression.Default(type), cases));
        }
Ejemplo n.º 6
0
 public override MSAst.Expression GetConstant(object value)
 {
     return(AstUtils.Constant(value));
 }
Ejemplo n.º 7
0
        /// <summary>
        /// Translates our CallSignature into a DLR Argument list and gives the simple MetaObject's which are extracted
        /// from the tuple or dictionary parameters being splatted.
        /// </summary>
        private void TranslateArguments(DynamicMetaObject target, DynamicMetaObject /*!*/[] /*!*/ args, out CallInfo /*!*/ callInfo, out List <Expression /*!*/> /*!*/ metaArgs, out Expression test, out BindingRestrictions restrictions)
        {
            Argument[] argInfo = _signature.GetArgumentInfos();

            List <string> namedArgNames = new List <string>();

            metaArgs = new List <Expression>();
            metaArgs.Add(target.Expression);
            Expression splatArgTest   = null;
            Expression splatKwArgTest = null;

            restrictions = BindingRestrictions.Empty;

            for (int i = 0; i < argInfo.Length; i++)
            {
                Argument ai = argInfo[i];

                switch (ai.Kind)
                {
                case ArgumentType.Dictionary:
                    PythonDictionary iac      = (PythonDictionary)args[i].Value;
                    List <string>    argNames = new List <string>();

                    foreach (KeyValuePair <object, object> kvp in iac)
                    {
                        string key = (string)kvp.Key;
                        namedArgNames.Add(key);
                        argNames.Add(key);

                        metaArgs.Add(
                            Expression.Call(
                                AstUtils.Convert(args[i].Expression, typeof(PythonDictionary)),
                                typeof(PythonDictionary).GetMethod("get_Item", new[] { typeof(object) }),
                                AstUtils.Constant(key)
                                )
                            );
                    }

                    restrictions   = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[i].Expression, args[i].GetLimitType()));
                    splatKwArgTest = Expression.Call(
                        typeof(PythonOps).GetMethod(nameof(PythonOps.CheckDictionaryMembers)),
                        AstUtils.Convert(args[i].Expression, typeof(PythonDictionary)),
                        AstUtils.Constant(argNames.ToArray())
                        );
                    break;

                case ArgumentType.List:
                    IList <object> splattedArgs = (IList <object>)args[i].Value;
                    splatArgTest = Expression.Equal(
                        Expression.Property(AstUtils.Convert(args[i].Expression, args[i].GetLimitType()), typeof(ICollection <object>).GetProperty("Count")),
                        AstUtils.Constant(splattedArgs.Count)
                        );

                    for (int splattedArg = 0; splattedArg < splattedArgs.Count; splattedArg++)
                    {
                        metaArgs.Add(
                            Expression.Call(
                                AstUtils.Convert(args[i].Expression, typeof(IList <object>)),
                                typeof(IList <object>).GetMethod("get_Item"),
                                AstUtils.Constant(splattedArg)
                                )
                            );
                    }

                    restrictions = restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(args[i].Expression, args[i].GetLimitType()));
                    break;

                case ArgumentType.Named:
                    namedArgNames.Add(ai.Name);
                    metaArgs.Add(args[i].Expression);
                    break;

                case ArgumentType.Simple:
                    metaArgs.Add(args[i].Expression);
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }

            callInfo = new CallInfo(metaArgs.Count - 1, namedArgNames.ToArray());

            test = splatArgTest;
            if (splatKwArgTest != null)
            {
                test = test != null?Expression.AndAlso(test, splatKwArgTest) : splatKwArgTest;
            }
        }
Ejemplo n.º 8
0
        private DynamicMetaObject /*!*/ MakeDynamicMemberAccess(DynamicMetaObjectBinder /*!*/ member, string /*!*/ name, MemberAccess access, DynamicMetaObject /*!*/[] /*!*/ args)
        {
            DynamicMetaObject self = Restrict(typeof(OldInstance));
            Expression        target;

            ParameterExpression tmp = Ast.Variable(typeof(object), "result");

            switch (access)
            {
            case MemberAccess.Invoke:

                target = Ast.Block(
                    new ParameterExpression[] { tmp },
                    Ast.Condition(
                        Expression.Not(
                            Expression.TypeIs(
                                Expression.Assign(
                                    tmp,
                                    Ast.Call(
                                        typeof(PythonOps).GetMethod("OldInstanceTryGetBoundCustomMember"),
                                        AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext),
                                        self.Expression,
                                        AstUtils.Constant(name)
                                        )
                                    ),
                                typeof(OperationFailed)
                                )
                            ),
                        ((InvokeMemberBinder)member).FallbackInvoke(new DynamicMetaObject(tmp, BindingRestrictions.Empty), args, null).Expression,
                        AstUtils.Convert(
                            ((InvokeMemberBinder)member).FallbackInvokeMember(this, args).Expression,
                            typeof(object)
                            )
                        )
                    );
                break;

            case MemberAccess.Get:
                target = Ast.Block(
                    new ParameterExpression[] { tmp },
                    Ast.Condition(
                        Expression.Not(
                            Expression.TypeIs(
                                Expression.Assign(
                                    tmp,
                                    Ast.Call(
                                        typeof(PythonOps).GetMethod("OldInstanceTryGetBoundCustomMember"),
                                        AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext),
                                        self.Expression,
                                        AstUtils.Constant(name)
                                        )
                                    ),
                                typeof(OperationFailed)
                                )
                            ),
                        tmp,
                        AstUtils.Convert(
                            FallbackGet(member, args),
                            typeof(object)
                            )
                        )
                    );
                break;

            case MemberAccess.Set:
                target = Ast.Call(
                    typeof(PythonOps).GetMethod("OldInstanceSetCustomMember"),
                    AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext),
                    self.Expression,
                    AstUtils.Constant(name),
                    AstUtils.Convert(args[1].Expression, typeof(object))
                    );
                break;

            case MemberAccess.Delete:
                target = Ast.Call(
                    typeof(PythonOps).GetMethod("OldInstanceDeleteCustomMember"),
                    AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext),
                    self.Expression,
                    AstUtils.Constant(name)
                    );
                break;

            default:
                throw new InvalidOperationException();
            }

            return(new DynamicMetaObject(
                       target,
                       self.Restrictions.Merge(BindingRestrictions.Combine(args))
                       ));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// WithStatement is translated to the DLR AST equivalent to
        /// the following Python code snippet (from with statement spec):
        ///
        /// mgr = (EXPR)
        /// exit = mgr.__exit__  # Not calling it yet
        /// value = mgr.__enter__()
        /// exc = True
        /// try:
        ///     VAR = value  # Only if "as VAR" is present
        ///     BLOCK
        /// except:
        ///     # The exceptional case is handled here
        ///     exc = False
        ///     if not exit(*sys.exc_info()):
        ///         raise
        ///     # The exception is swallowed if exit() returns true
        /// finally:
        ///     # The normal and non-local-goto cases are handled here
        ///     if exc:
        ///         exit(None, None, None)
        ///
        /// </summary>
        public override MSAst.Expression Reduce()
        {
            // Five statements in the result...
            ReadOnlyCollectionBuilder <MSAst.Expression>          statements = new ReadOnlyCollectionBuilder <MSAst.Expression>(6);
            ReadOnlyCollectionBuilder <MSAst.ParameterExpression> variables  = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>(6);

            MSAst.ParameterExpression lineUpdated = Ast.Variable(typeof(bool), "$lineUpdated_with");
            variables.Add(lineUpdated);

            //******************************************************************
            // 1. mgr = (EXPR)
            //******************************************************************
            MSAst.ParameterExpression manager = Ast.Variable(typeof(object), "with_manager");
            variables.Add(manager);
            statements.Add(
                GlobalParent.AddDebugInfo(
                    Ast.Assign(
                        manager,
                        _contextManager
                        ),
                    new SourceSpan(GlobalParent.IndexToLocation(StartIndex), GlobalParent.IndexToLocation(_headerIndex))
                    )
                );

            //******************************************************************
            // 2. exit = mgr.__exit__  # Not calling it yet
            //******************************************************************
            MSAst.ParameterExpression exit = Ast.Variable(typeof(object), "with_exit");
            variables.Add(exit);
            statements.Add(
                MakeAssignment(
                    exit,
                    GlobalParent.Get(
                        "__exit__",
                        manager
                        )
                    )
                );

            //******************************************************************
            // 3. value = mgr.__enter__()
            //******************************************************************
            MSAst.ParameterExpression value = Ast.Variable(typeof(object), "with_value");
            variables.Add(value);
            statements.Add(
                GlobalParent.AddDebugInfoAndVoid(
                    MakeAssignment(
                        value,
                        Parent.Invoke(
                            new CallSignature(0),
                            Parent.LocalContext,
                            GlobalParent.Get(
                                "__enter__",
                                manager
                                )
                            )
                        ),
                    new SourceSpan(GlobalParent.IndexToLocation(StartIndex), GlobalParent.IndexToLocation(_headerIndex))
                    )
                );

            //******************************************************************
            // 4. exc = True
            //******************************************************************
            MSAst.ParameterExpression exc = Ast.Variable(typeof(bool), "with_exc");
            variables.Add(exc);
            statements.Add(
                MakeAssignment(
                    exc,
                    AstUtils.Constant(true)
                    )
                );

            //******************************************************************
            //  5. The final try statement:
            //
            //  try:
            //      VAR = value  # Only if "as VAR" is present
            //      BLOCK
            //  except:
            //      # The exceptional case is handled here
            //      exc = False
            //      if not exit(*sys.exc_info()):
            //          raise
            //      # The exception is swallowed if exit() returns true
            //  finally:
            //      # The normal and non-local-goto cases are handled here
            //      if exc:
            //          exit(None, None, None)
            //******************************************************************

            MSAst.ParameterExpression exception;
            statements.Add(
                // try:
                AstUtils.Try(
                    AstUtils.Try(// try statement body
                        PushLineUpdated(false, lineUpdated),
                        _var != null ?
                        (MSAst.Expression)Ast.Block(
                            // VAR = value
                            _var.TransformSet(SourceSpan.None, value, PythonOperationKind.None),
                            // BLOCK
                            _body,
                            AstUtils.Empty()
                            ) :
                        // BLOCK
                        (MSAst.Expression)_body // except:, // try statement location
                        ).Catch(exception = Ast.Variable(typeof(Exception), "exception"),
                                                // Python specific exception handling code
                                TryStatement.GetTracebackHeader(
                                    this,
                                    exception,
                                    GlobalParent.AddDebugInfoAndVoid(
                                        Ast.Block(
                                            // exc = False
                                            MakeAssignment(
                                                exc,
                                                AstUtils.Constant(false)
                                                ),
                                            //  if not exit(*sys.exc_info()):
                                            //      raise
                                            AstUtils.IfThen(
                                                GlobalParent.Convert(
                                                    typeof(bool),
                                                    ConversionResultKind.ExplicitCast,
                                                    GlobalParent.Operation(
                                                        typeof(bool),
                                                        PythonOperationKind.IsFalse,
                                                        MakeExitCall(exit, exception)
                                                        )
                                                    ),
                                                UpdateLineUpdated(true),
                                                Ast.Throw(
                                                    Ast.Call(
                                                        AstMethods.MakeRethrowExceptionWorker,
                                                        exception
                                                        )
                                                    )
                                                )
                                            ),
                                        _body.Span
                                        )
                                    ),
                                PopLineUpdated(lineUpdated),
                                Ast.Empty()
                                )
                    // finally:
                    ).Finally(
                    //  if exc:
                    //      exit(None, None, None)
                    AstUtils.IfThen(
                        exc,
                        GlobalParent.AddDebugInfoAndVoid(
                            Ast.Block(
                                MSAst.DynamicExpression.Dynamic(
                                    GlobalParent.PyContext.Invoke(
                                        new CallSignature(3)        // signature doesn't include function
                                        ),
                                    typeof(object),
                                    new MSAst.Expression[] {
                Parent.LocalContext,
                exit,
                AstUtils.Constant(null),
                AstUtils.Constant(null),
                AstUtils.Constant(null)
            }
                                    ),
                                Ast.Empty()
                                ),
                            _contextManager.Span
                            )
                        )
                    )
                );

            statements.Add(AstUtils.Empty());
            return(Ast.Block(variables.ToReadOnlyCollection(), statements.ToReadOnlyCollection()));
        }
Ejemplo n.º 10
0
 internal override MSA.Expression TransformDefinedCondition(AstGenerator /*!*/ gen)
 {
     // block_given semantics:
     return(Ast.NotEqual(gen.MakeMethodBlockParameterRead(), AstUtils.Constant(null)));
 }
Ejemplo n.º 11
0
 internal override MSA.Expression /*!*/ TransformWriteVariable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ rightValue)
 {
     if (_definitionLexicalDepth >= 0)
     {
         // static lookup:
         return(Ast.Assign(gen.CurrentScope.GetVariableAccessor(_definitionLexicalDepth, _closureIndex), AstUtils.Box(rightValue)));
     }
     else
     {
         // dynamic lookup:
         return(Methods.SetLocalVariable.OpCall(AstUtils.Box(rightValue), gen.CurrentScopeVariable, AstUtils.Constant(Name)));
     }
 }
        protected override Expression VisitTry(TryExpression node)
        {
            // Visit finally/fault block first
            BlockInfo block = new BlockInfo {
                InFinally = true
            };

            _blocks.Push(block);
            Expression @finally = Visit(node.Finally);
            Expression fault    = Visit(node.Fault);

            block.InFinally = false;

            LabelTarget finallyEnd = block.FlowLabel;

            if (finallyEnd != null)
            {
                // Make a new target, which will be emitted after the try
                block.FlowLabel = Expression.Label();
            }

            Expression         @try     = Visit(node.Body);
            IList <CatchBlock> handlers = Visit(node.Handlers, VisitCatchBlock);

            _blocks.Pop();

            if (@try == node.Body &&
                handlers == node.Handlers &&
                @finally == node.Finally &&
                fault == node.Fault)
            {
                return(node);
            }

            if (!block.HasFlow)
            {
                return(Expression.MakeTry(null, @try, @finally, fault, handlers));
            }

            if (node.Type != typeof(void))
            {
                // This is not hard to support in principle, but not needed by anyone yet.
                throw new NotSupportedException("FinallyFlowControlExpression does not support TryExpressions of non-void type.");
            }

            //  If there is a control flow in finally, emit outer:
            //  try {
            //      // try block body and all catch handling
            //  } catch (Exception all) {
            //      saved = all;
            //  } finally {
            //      finally_body
            //      if (saved != null) {
            //          throw saved;
            //      }
            //  }
            //
            //  If we have a fault handler we turn this into the better:
            //  try {
            //      // try block body and all catch handling
            //  } catch (Exception all) {
            //      fault_body
            //      throw all
            //  }

            if (handlers.Count > 0)
            {
                @try = Expression.MakeTry(null, @try, null, null, handlers);
            }

            var saved = Expression.Variable(typeof(Exception), "$exception");
            var all   = Expression.Variable(typeof(Exception), "e");

            if (@finally != null)
            {
                handlers = new[] {
                    Expression.Catch(
                        all,
                        Expression.Block(
                            Expression.Assign(saved, all),
                            Utils.Default(node.Type)
                            )
                        )
                };
                @finally = Expression.Block(
                    @finally,
                    Expression.Condition(
                        Expression.NotEqual(saved, AstUtils.Constant(null, saved.Type)),
                        Expression.Throw(saved),
                        Utils.Empty()
                        )
                    );

                if (finallyEnd != null)
                {
                    @finally = Expression.Label(finallyEnd, @finally);
                }
            }
            else
            {
                Debug.Assert(fault != null);

                fault = Expression.Block(fault, Expression.Throw(all));
                if (finallyEnd != null)
                {
                    fault = Expression.Label(finallyEnd, fault);
                }
                handlers = new[] { Expression.Catch(all, fault) };
                fault    = null;
            }

            // Emit flow control
            return(Expression.Block(
                       new[] { saved },
                       Expression.MakeTry(null, @try, @finally, fault, handlers),
                       Expression.Label(block.FlowLabel),
                       MakeFlowControlSwitch(block)
                       ));
        }
Ejemplo n.º 13
0
        internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op)
        {
            // if we just have a simple named multi-assignment  (e.g. a, b = 1,2)
            // then go ahead and step over the entire statement at once.  If we have a
            // more complex statement (e.g. a.b, c.d = 1, 2) then we'll step over the
            // sets individually as they could be property sets the user wants to step
            // into.  TODO: Enable stepping of the right hand side?
            bool emitIndividualSets = false;

            foreach (Expression e in _items)
            {
                if (IsComplexAssignment(e))
                {
                    emitIndividualSets = true;
                    break;
                }
            }

            SourceSpan rightSpan = SourceSpan.None;
            SourceSpan leftSpan  =
                (Span.Start.IsValid && span.IsValid) ?
                new SourceSpan(Span.Start, span.End) :
                SourceSpan.None;

            SourceSpan totalSpan = SourceSpan.None;

            if (emitIndividualSets)
            {
                rightSpan = span;
                leftSpan  = SourceSpan.None;
                totalSpan = (Span.Start.IsValid && span.IsValid) ?
                            new SourceSpan(Span.Start, span.End) :
                            SourceSpan.None;
            }

            // 1. Evaluate the expression and assign the value to the temp.
            MSAst.ParameterExpression right_temp = Ast.Variable(typeof(object), "unpacking");

            // 2. Add the assignment "right_temp = right" into the suite/block
            MSAst.Expression assignStmt1 = MakeAssignment(right_temp, right);

            // 3. Call GetEnumeratorValues on the right side (stored in temp)
            MSAst.Expression enumeratorValues = Expression.Convert(LightExceptions.CheckAndThrow(
                                                                       Expression.Call(
                                                                           emitIndividualSets ?
                                                                           AstMethods.GetEnumeratorValues :
                                                                           AstMethods.GetEnumeratorValuesNoComplexSets, // method
                                                                           // arguments
                                                                           Parent.LocalContext,
                                                                           right_temp,
                                                                           AstUtils.Constant(_items.Length)
                                                                           )
                                                                       ), typeof(object[]));

            // 4. Create temporary variable for the array
            MSAst.ParameterExpression array_temp = Ast.Variable(typeof(object[]), "array");

            // 5. Assign the value of the method call (mce) into the array temp
            // And add the assignment "array_temp = Ops.GetEnumeratorValues(...)" into the block
            MSAst.Expression assignStmt2 = MakeAssignment(
                array_temp,
                enumeratorValues,
                rightSpan
                );

            ReadOnlyCollectionBuilder <MSAst.Expression> sets = new ReadOnlyCollectionBuilder <MSAst.Expression>(_items.Length + 1);

            for (int i = 0; i < _items.Length; i++)
            {
                // target = array_temp[i]

                Expression target = _items[i];
                if (target == null)
                {
                    continue;
                }

                // 6. array_temp[i]
                MSAst.Expression element = Ast.ArrayAccess(
                    array_temp,                             // array expression
                    AstUtils.Constant(i)                    // index
                    );

                // 7. target = array_temp[i], and add the transformed assignment into the list of sets
                MSAst.Expression set = target.TransformSet(
                    emitIndividualSets ?                    // span
                    target.Span :
                    SourceSpan.None,
                    element,
                    PythonOperationKind.None
                    );
                sets.Add(set);
            }
            // 9. add the sets as their own block so they can be marked as a single span, if necessary.
            sets.Add(AstUtils.Empty());
            MSAst.Expression itemSet = GlobalParent.AddDebugInfo(Ast.Block(sets.ToReadOnlyCollection()), leftSpan);

            // 10. Return the suite statement (block)
            return(GlobalParent.AddDebugInfo(Ast.Block(new[] { array_temp, right_temp }, assignStmt1, assignStmt2, itemSet, AstUtils.Empty()), totalSpan));
        }
Ejemplo n.º 14
0
        // Ruby binders:
        internal CallArguments(RubyContext context, DynamicMetaObject /*!*/ scopeOrContextOrTargetOrArgArray, DynamicMetaObject /*!*/[] /*!*/ args, RubyCallSignature signature)
        {
            Assert.NotNull(scopeOrContextOrTargetOrArgArray);
            Assert.NotNullItems(args);

            ArgumentArray argArray = scopeOrContextOrTargetOrArgArray.Value as ArgumentArray;

            if (argArray != null)
            {
                Debug.Assert(args.Length == 0 && argArray.Count >= 1);

                // build meta-objects for arguments wrapped in the array:
                args = new DynamicMetaObject[argArray.Count - 1];
                for (int i = 0; i < args.Length; i++)
                {
                    args[i] = argArray.GetMetaObject(scopeOrContextOrTargetOrArgArray.Expression, 1 + i);
                }
                scopeOrContextOrTargetOrArgArray = argArray.GetMetaObject(scopeOrContextOrTargetOrArgArray.Expression, 0);
            }

            Debug.Assert(signature.HasScope == scopeOrContextOrTargetOrArgArray.Value is RubyScope);
            Debug.Assert((context == null && !signature.HasScope) == scopeOrContextOrTargetOrArgArray.Value is RubyContext);

            if (context != null)
            {
                // bound site:
                _context = new DynamicMetaObject(AstUtils.Constant(context), BindingRestrictions.Empty, context);
                if (signature.HasScope)
                {
                    _scope = scopeOrContextOrTargetOrArgArray;
                    _hasScopeOrContextArg = true;
                }
                else
                {
                    _target = scopeOrContextOrTargetOrArgArray;
                }
            }
            else if (signature.HasScope)
            {
                // unbound site with scope:
                _context = new DynamicMetaObject(
                    Methods.GetContextFromScope.OpCall(scopeOrContextOrTargetOrArgArray.Expression), BindingRestrictions.Empty,
                    ((RubyScope)scopeOrContextOrTargetOrArgArray.Value).RubyContext
                    );
                _scope = scopeOrContextOrTargetOrArgArray;
                _hasScopeOrContextArg = true;
                _target = null;
            }
            else
            {
                // unbound site with context:
                _context = scopeOrContextOrTargetOrArgArray;
                _hasScopeOrContextArg = true;
                _target = null;
            }

            Debug.Assert(_target != null || args.Length > 0);

            _args            = args;
            _copyArgsOnWrite = true;
            _signature       = signature;

            Debug.Assert(!signature.HasSplattedArgument || GetSplattedArgument() != null);
        }
Ejemplo n.º 15
0
        private void MakeFieldRule(SetOrDeleteMemberInfo memInfo, DynamicMetaObject instance, DynamicMetaObject target, Type targetType, MemberGroup fields, DynamicMetaObject errorSuggestion)
        {
            FieldTracker field = (FieldTracker)fields[0];

            // TODO: Tmp variable for target
            if (instance != null && field.DeclaringType.IsGenericType && field.DeclaringType.GetGenericTypeDefinition() == typeof(StrongBox <>))
            {
                // work around a CLR bug where we can't access generic fields from dynamic methods.
                Type[] generic = field.DeclaringType.GetGenericArguments();
                memInfo.Body.FinishCondition(
                    MakeReturnValue(
                        Ast.Assign(
                            Ast.Field(
                                AstUtils.Convert(instance.Expression, field.DeclaringType),
                                field.DeclaringType.GetField("Value")
                                ),
                            AstUtils.Convert(target.Expression, generic[0])
                            ),
                        target
                        )
                    );
            }
            else if (field.IsInitOnly || field.IsLiteral)
            {
                memInfo.Body.FinishCondition(
                    errorSuggestion ?? MakeError(
                        MakeReadOnlyMemberError(targetType, memInfo.Name),
                        typeof(object)
                        )
                    );
            }
            else if (field.IsStatic && targetType != field.DeclaringType)
            {
                memInfo.Body.FinishCondition(
                    errorSuggestion ?? MakeError(
                        MakeStaticAssignFromDerivedTypeError(targetType, instance, field, target, memInfo.ResolutionFactory),
                        typeof(object)
                        )
                    );
            }
            else if (field.DeclaringType.IsValueType && !field.IsStatic)
            {
                memInfo.Body.FinishCondition(
                    errorSuggestion ?? MakeError(
                        MakeSetValueTypeFieldError(field, instance, target),
                        typeof(object)
                        )
                    );
            }
            else if (field.IsPublic && field.DeclaringType.IsVisible)
            {
                if (!field.IsStatic && instance == null)
                {
                    memInfo.Body.FinishCondition(
                        Ast.Throw(
                            Ast.New(
                                typeof(ArgumentException).GetConstructor(new Type[] { typeof(string) }),
                                AstUtils.Constant("assignment to instance field w/o instance")
                                ),
                            typeof(object)
                            )
                        );
                }
                else
                {
                    memInfo.Body.FinishCondition(
                        MakeReturnValue(
                            Ast.Assign(
                                Ast.Field(
                                    field.IsStatic ?
                                    null :
                                    AstUtils.Convert(instance.Expression, field.DeclaringType),
                                    field.Field
                                    ),
                                ConvertExpression(target.Expression, field.FieldType, ConversionResultKind.ExplicitCast, memInfo.ResolutionFactory)
                                ),
                            target
                            )
                        );
                }
            }
            else
            {
                Debug.Assert(field.IsStatic || instance != null);

                memInfo.Body.FinishCondition(
                    MakeReturnValue(
                        Ast.Call(
                            AstUtils.Convert(AstUtils.Constant(field.Field), typeof(FieldInfo)),
                            typeof(FieldInfo).GetMethod("SetValue", new Type[] { typeof(object), typeof(object) }),
                            field.IsStatic ?
                            AstUtils.Constant(null) :
                            (Expression)AstUtils.Convert(instance.Expression, typeof(object)),
                            AstUtils.Convert(target.Expression, typeof(object))
                            ),
                        target
                        )
                    );
            }
        }
Ejemplo n.º 16
0
        private DynamicMetaObject /*!*/ InvokeWorker(DynamicMetaObjectBinder /*!*/ invoke, Expression /*!*/ codeContext, DynamicMetaObject /*!*/[] args)
        {
            PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass Invoke");

            DynamicMetaObject self = Restrict(typeof(OldInstance));

            Expression[] exprArgs = new Expression[args.Length + 1];
            for (int i = 0; i < args.Length; i++)
            {
                exprArgs[i + 1] = args[i].Expression;
            }

            ParameterExpression tmp = Ast.Variable(typeof(object), "callFunc");

            exprArgs[0] = tmp;
            return(new DynamicMetaObject(
                       // we could get better throughput w/ a more specific rule against our current custom old class but
                       // this favors less code generation.

                       Ast.Block(
                           new ParameterExpression[] { tmp },
                           Ast.Condition(
                               Expression.Not(
                                   Expression.TypeIs(
                                       Expression.Assign(
                                           tmp,
                                           Ast.Call(
                                               typeof(PythonOps).GetMethod("OldInstanceTryGetBoundCustomMember"),
                                               codeContext,
                                               self.Expression,
                                               AstUtils.Constant("__call__")
                                               )
                                           ),
                                       typeof(OperationFailed)
                                       )
                                   ),
                               Ast.Block(
                                   Utils.Try(
                                       Ast.Call(typeof(PythonOps).GetMethod("FunctionPushFrameCodeContext"), codeContext),
                                       Ast.Assign(
                                           tmp,
                                           DynamicExpression.Dynamic(
                                               PythonContext.GetPythonContext(invoke).Invoke(
                                                   BindingHelpers.GetCallSignature(invoke)
                                                   ),
                                               typeof(object),
                                               ArrayUtils.Insert(codeContext, exprArgs)
                                               )
                                           )
                                       ).Finally(
                                       Ast.Call(typeof(PythonOps).GetMethod("FunctionPopFrame"))
                                       ),
                                   tmp
                                   ),
                               Utils.Convert(
                                   BindingHelpers.InvokeFallback(invoke, codeContext, this, args).Expression,
                                   typeof(object)
                                   )
                               )
                           ),
                       self.Restrictions.Merge(BindingRestrictions.Combine(args))
                       ));
        }
Ejemplo n.º 17
0
        private DynamicMetaObject /*!*/ MakeMemberAccess(DynamicMetaObjectBinder /*!*/ member, string name, MemberAccess access, params DynamicMetaObject /*!*/[] /*!*/ args)
        {
            DynamicMetaObject self = Restrict(typeof(OldInstance));

            CustomInstanceDictionaryStorage dict;
            int key = GetCustomStorageSlot(name, out dict);

            if (key == -1)
            {
                PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldInstance " + access + " NoOptimized");
                return(MakeDynamicMemberAccess(member, name, access, args));
            }

            ParameterExpression tmp = Ast.Variable(typeof(object), "dict");
            Expression          target;

            ValidationInfo test = new ValidationInfo(
                Ast.NotEqual(
                    Ast.Assign(
                        tmp,
                        Ast.Call(
                            typeof(PythonOps).GetMethod("OldInstanceGetOptimizedDictionary"),
                            self.Expression,
                            AstUtils.Constant(dict.KeyVersion)
                            )
                        ),
                    AstUtils.Constant(null)
                    )
                );

            PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldInstance " + access + " Optimized");
            switch (access)
            {
            case MemberAccess.Invoke:
                ParameterExpression value = Ast.Variable(typeof(object), "value");
                target = Ast.Block(
                    new[] { value },
                    Ast.Condition(
                        Ast.Call(
                            typeof(PythonOps).GetMethod("TryOldInstanceDictionaryGetValueHelper"),
                            tmp,
                            Ast.Constant(key),
                            AstUtils.Convert(Expression, typeof(object)),
                            value
                            ),
                        AstUtils.Convert(
                            ((InvokeMemberBinder)member).FallbackInvoke(new DynamicMetaObject(value, BindingRestrictions.Empty), args, null).Expression,
                            typeof(object)
                            ),
                        AstUtils.Convert(
                            ((InvokeMemberBinder)member).FallbackInvokeMember(self, args).Expression,
                            typeof(object)
                            )
                        )
                    );
                break;

            case MemberAccess.Get:
                // BUG: There's a missing Fallback path here that's always been present even
                // in the version that used rules.
                target = Ast.Call(
                    typeof(PythonOps).GetMethod("OldInstanceDictionaryGetValueHelper"),
                    tmp,
                    AstUtils.Constant(key),
                    AstUtils.Convert(Expression, typeof(object))
                    );
                break;

            case MemberAccess.Set:
                target = Ast.Call(
                    typeof(PythonOps).GetMethod("OldInstanceDictionarySetExtraValue"),
                    tmp,
                    AstUtils.Constant(key),
                    AstUtils.Convert(args[1].Expression, typeof(object))
                    );
                break;

            case MemberAccess.Delete:
                target = Ast.Call(
                    typeof(PythonOps).GetMethod("OldInstanceDeleteCustomMember"),
                    AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext),
                    AstUtils.Convert(Expression, typeof(OldInstance)),
                    AstUtils.Constant(name)
                    );
                break;

            default:
                throw new InvalidOperationException();
            }

            return(BindingHelpers.AddDynamicTestAndDefer(
                       member,
                       new DynamicMetaObject(
                           target,
                           BindingRestrictions.Combine(args).Merge(self.Restrictions)
                           ),
                       args,
                       test,
                       tmp
                       ));
        }
Ejemplo n.º 18
0
        private MSAst.Expression AddFinally(MSAst.Expression /*!*/ body, MSAst.ParameterExpression nestedException)
        {
            if (_finally != null)
            {
                Debug.Assert(nestedException != null);

                MSAst.ParameterExpression nestedFrames = Ast.Variable(typeof(List <DynamicStackFrame>), "$nestedFrames");

                MSAst.Expression @finally = _finally;

                // lots is going on here.  We need to consider:
                //      1. Exceptions propagating out of try/except/finally.  Here we need to save the line #
                //          from the exception block and not save the # from the finally block later.
                //      2. Exceptions propagating out of the finally block.  Here we need to report the line number
                //          from the finally block and leave the existing stack traces cleared.
                //      3. Returning from the try block: Here we need to run the finally block and not update the
                //          line numbers.
                body = AstUtils.Try( // we use a fault to know when we have an exception and when control leaves normally (via
                    // either a return or the body completing successfully).
                    AstUtils.Try(
                        Parent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, _header)),
                        Ast.Assign(nestedException, AstUtils.Constant(false)),
                        body
                        ).Fault(
                        // fault
                        Ast.Assign(nestedException, AstUtils.Constant(true))
                        )
                    ).FinallyWithJumps(
                    // if we had an exception save the line # that was last executing during the try
                    AstUtils.If(
                        nestedException,
                        Parent.GetSaveLineNumberExpression(false)
                        ),

                    // clear the frames incase thae finally throws, and allow line number
                    // updates to proceed
                    UpdateLineUpdated(false),
                    Ast.Assign(
                        nestedFrames,
                        Ast.Call(AstMethods.GetAndClearDynamicStackFrames)
                        ),

                    // run the finally code
                    @finally,

                    // if the finally exits normally restore any previous exception info
                    Ast.Call(
                        AstMethods.SetDynamicStackFrames,
                        nestedFrames
                        ),

                    // if we took an exception in the try block we have saved the line number.  Otherwise
                    // we have no line number saved and will need to continue saving them if
                    // other exceptions are thrown.
                    AstUtils.If(
                        nestedException,
                        UpdateLineUpdated(true)
                        )
                    );

                body = Ast.Block(new[] { nestedFrames }, body);
            }
            return(body);
        }
Ejemplo n.º 19
0
        private static MethodMissingBinding BindToKernelMethodMissing(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ methodName,
                                                                      RubyMemberInfo methodMissing, RubyMethodVisibility incompatibleVisibility, bool isSuperCall)
        {
            // TODO: better specialization of method_missing methods
            if (methodMissing == null ||
                methodMissing.DeclaringModule == methodMissing.Context.BasicObjectClass && methodMissing is RubyLibraryMethodInfo)
            {
                if (isSuperCall)
                {
                    metaBuilder.SetError(Methods.MakeMissingSuperException.OpCall(AstUtils.Constant(methodName)));
                }
                else if (incompatibleVisibility == RubyMethodVisibility.Private)
                {
                    metaBuilder.SetError(Methods.MakePrivateMethodCalledError.OpCall(
                                             AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName))
                                         );
                }
                else if (incompatibleVisibility == RubyMethodVisibility.Protected)
                {
                    metaBuilder.SetError(Methods.MakeProtectedMethodCalledError.OpCall(
                                             AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), args.TargetExpression, AstUtils.Constant(methodName))
                                         );
                }
                else
                {
                    return(MethodMissingBinding.Fallback);
                }

                return(MethodMissingBinding.Error);
            }

            return(MethodMissingBinding.Custom);
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Transform multiple python except handlers for a try block into a single catch body.
        /// </summary>
        /// <param name="exception">The variable for the exception in the catch block.</param>
        /// <returns>Null if there are no except handlers. Else the statement to go inside the catch handler</returns>
        private MSAst.Expression TransformHandlers(MSAst.ParameterExpression exception)
        {
            Assert.NotEmpty(_handlers);

            MSAst.ParameterExpression extracted = Ast.Variable(typeof(object), "$extracted");

            var tests = new List <Microsoft.Scripting.Ast.IfStatementTest>(_handlers.Length);

            MSAst.ParameterExpression converted = null;
            MSAst.Expression          catchAll  = null;

            for (int index = 0; index < _handlers.Length; index++)
            {
                TryStatementHandler tsh = _handlers[index];

                if (tsh.Test != null)
                {
                    Microsoft.Scripting.Ast.IfStatementTest ist;

                    //  translating:
                    //      except Test ...
                    //
                    //  generate following AST for the Test (common part):
                    //      CheckException(exception, Test)
                    MSAst.Expression test =
                        Ast.Call(
                            AstMethods.CheckException,
                            Parent.LocalContext,
                            extracted,
                            AstUtils.Convert(tsh.Test, typeof(object))
                            );

                    if (tsh.Target != null)
                    {
                        //  translating:
                        //      except Test, Target:
                        //          <body>
                        //  into:
                        //      if ((converted = CheckException(exception, Test)) != null) {
                        //          Target = converted;
                        //          traceback-header
                        //          <body>
                        //      }

                        if (converted == null)
                        {
                            converted = Ast.Variable(typeof(object), "$converted");
                        }

                        ist = AstUtils.IfCondition(
                            Ast.NotEqual(
                                Ast.Assign(converted, test),
                                AstUtils.Constant(null)
                                ),
                            Ast.Block(
                                tsh.Target.TransformSet(SourceSpan.None, converted, PythonOperationKind.None),
                                GlobalParent.AddDebugInfo(
                                    GetTracebackHeader(
                                        this,
                                        exception,
                                        tsh.Body
                                        ),
                                    new SourceSpan(tsh.Start, tsh.Header)
                                    ),
                                AstUtils.Empty()
                                )
                            );
                    }
                    else
                    {
                        //  translating:
                        //      except Test:
                        //          <body>
                        //  into:
                        //      if (CheckException(exception, Test) != null) {
                        //          traceback-header
                        //          <body>
                        //      }
                        ist = AstUtils.IfCondition(
                            Ast.NotEqual(
                                test,
                                AstUtils.Constant(null)
                                ),
                            GlobalParent.AddDebugInfo(
                                GetTracebackHeader(
                                    this,
                                    exception,
                                    tsh.Body
                                    ),
                                new SourceSpan(tsh.Start, tsh.Header)
                                )
                            );
                    }

                    // Add the test to the if statement test cascade
                    tests.Add(ist);
                }
                else
                {
                    Debug.Assert(index == _handlers.Length - 1);
                    Debug.Assert(catchAll == null);

                    //  translating:
                    //      except:
                    //          <body>
                    //  into:
                    //  {
                    //          traceback-header
                    //          <body>
                    //  }

                    catchAll = GlobalParent.AddDebugInfo(
                        GetTracebackHeader(this, exception, tsh.Body),
                        new SourceSpan(tsh.Start, tsh.Header)
                        );
                }
            }

            MSAst.Expression body = null;

            if (tests.Count > 0)
            {
                // rethrow the exception if we have no catch-all block
                if (catchAll == null)
                {
                    catchAll = Ast.Block(
                        Parent.GetSaveLineNumberExpression(true),
                        Ast.Throw(
                            Ast.Call(
                                typeof(ExceptionHelpers).GetMethod("UpdateForRethrow"),
                                exception
                                )
                            )
                        );
                }

                body = AstUtils.If(
                    tests.ToArray(),
                    catchAll
                    );
            }
            else
            {
                Debug.Assert(catchAll != null);
                body = catchAll;
            }

            IList <MSAst.ParameterExpression> args;

            if (converted != null)
            {
                args = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression> {
                    converted, extracted
                };
            }
            else
            {
                args = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression> {
                    extracted
                };
            }

            // Codegen becomes:
            //     extracted = PythonOps.SetCurrentException(exception)
            //      < dynamic exception analysis >
            return(Ast.Block(
                       args,
                       Ast.Assign(
                           extracted,
                           Ast.Call(
                               AstMethods.SetCurrentException,
                               Parent.LocalContext,
                               exception
                               )
                           ),
                       body,
                       Ast.Assign(extracted, Ast.Constant(null)),
                       AstUtils.Empty()
                       ));
        }
Ejemplo n.º 21
0
        private MSAst.Expression MakeBinaryOperation(PythonOperator op, MSAst.Expression left, MSAst.Expression right, SourceSpan span)
        {
            if (op == PythonOperator.NotIn)
            {
                return(AstUtils.Convert(
                           Ast.Not(
                               GlobalParent.Operation(
                                   typeof(bool),
                                   PythonOperationKind.Contains,
                                   left,
                                   right
                                   )
                               ),
                           typeof(object)
                           ));
            }
            else if (op == PythonOperator.In)
            {
                return(AstUtils.Convert(
                           GlobalParent.Operation(
                               typeof(bool),
                               PythonOperationKind.Contains,
                               left,
                               right
                               ),
                           typeof(object)
                           ));
            }

            PythonOperationKind action = PythonOperatorToAction(op);

            if (action != PythonOperationKind.None)
            {
                // Create action expression
                if (CanEmitWarning(op))
                {
                    MSAst.ParameterExpression tempLeft  = Ast.Parameter(left.Type, "left");
                    MSAst.ParameterExpression tempRight = Ast.Parameter(right.Type, "right");
                    return(Ast.Block(
                               new[] { tempLeft, tempRight },
                               Ast.Call(
                                   AstMethods.WarnDivision,
                                   Parent.LocalContext,
                                   AstUtils.Constant(GlobalParent.DivisionOptions),
                                   AstUtils.Convert(
                                       Ast.Assign(tempLeft, left),
                                       typeof(object)
                                       ),
                                   AstUtils.Convert(
                                       Ast.Assign(tempRight, right),
                                       typeof(object)
                                       )
                                   ),
                               GlobalParent.Operation(
                                   typeof(object),
                                   action,
                                   tempLeft,
                                   tempRight
                                   )
                               ));
                }

                return(GlobalParent.Operation(
                           typeof(object),
                           action,
                           left,
                           right
                           ));
            }
            else
            {
                // Call helper method
                return(Ast.Call(
                           GetHelperMethod(op),
                           ConvertIfNeeded(left, typeof(object)),
                           ConvertIfNeeded(right, typeof(object))
                           ));
            }
        }
Ejemplo n.º 22
0
        public override MSAst.Expression Reduce()
        {
            // allocated all variables here so they won't be shared w/ other
            // locals allocated during the body or except blocks.
            MSAst.ParameterExpression noNestedException = null;
            if (_finally != null)
            {
                noNestedException = Ast.Variable(typeof(bool), "$noException");
            }

            MSAst.ParameterExpression lineUpdated = null;
            MSAst.ParameterExpression runElse     = null;

            if (_else != null || (_handlers != null && _handlers.Length > 0))
            {
                lineUpdated = Ast.Variable(typeof(bool), "$lineUpdated_try");
                if (_else != null)
                {
                    runElse = Ast.Variable(typeof(bool), "run_else");
                }
            }

            // don't allocate locals below here...
            MSAst.Expression          body = _body;
            MSAst.Expression          @else = _else;
            MSAst.Expression          @catch, result;
            MSAst.ParameterExpression exception;

            if (_handlers != null && _handlers.Length > 0)
            {
                exception = Ast.Variable(typeof(Exception), "$exception");
                @catch    = TransformHandlers(exception);
            }
            else
            {
                exception = null;
                @catch    = null;
            }

            // We have else clause, must generate guard around it
            if (@else != null)
            {
                Debug.Assert(@catch != null);

                //  run_else = true;
                //  try {
                //      try_body
                //  } catch ( ... ) {
                //      run_else = false;
                //      catch_body
                //  }
                //  if (run_else) {
                //      else_body
                //  }
                result =
                    Ast.Block(
                        Ast.Assign(runElse, AstUtils.Constant(true)),
                        // save existing line updated, we could choose to do this only for nested exception handlers.
                        PushLineUpdated(false, lineUpdated),
                        AstUtils.Try(
                            Parent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, _header)),
                            body
                            ).Catch(exception,
                                    Ast.Assign(runElse, AstUtils.Constant(false)),
                                    @catch,
                                    // restore existing line updated after exception handler completes
                                    PopLineUpdated(lineUpdated),
                                    Ast.Assign(exception, Ast.Constant(null, typeof(Exception))),
                                    AstUtils.Default(body.Type)
                                    ),
                        AstUtils.IfThen(runElse,
                                        @else
                                        ),
                        AstUtils.Empty()
                        );
            }
            else if (@catch != null)            // no "else" clause
            //  try {
            //      <try body>
            //  } catch (Exception e) {
            //      ... catch handling ...
            //  }
            //
            {
                result =
                    AstUtils.Try(
                        GlobalParent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, _header)),
                        // save existing line updated
                        PushLineUpdated(false, lineUpdated),
                        body
                        ).Catch(exception,
                                @catch,
                                // restore existing line updated after exception handler completes
                                PopLineUpdated(lineUpdated),
                                Ast.Call(AstMethods.ExceptionHandled, Parent.LocalContext),
                                Ast.Assign(exception, Ast.Constant(null, typeof(Exception))),
                                AstUtils.Default(body.Type)
                                );
            }
            else
            {
                result = body;
            }

            return(Ast.Block(
                       GetVariables(noNestedException, lineUpdated, runElse),
                       AddFinally(result, noNestedException)
                       ));
        }
Ejemplo n.º 23
0
        protected override Expression VisitTry(TryExpression node)
        {
            int startYields = _yields.Count;

            bool savedInTryWithFinally = _inTryWithFinally;

            if (node.Finally != null || node.Fault != null)
            {
                _inTryWithFinally = true;
            }
            Expression @try      = Visit(node.Body);
            int        tryYields = _yields.Count;

            IList <CatchBlock> handlers = Visit(node.Handlers, VisitCatchBlock);
            int catchYields             = _yields.Count;

            // push a new return label in case the finally block yields
            _returnLabels.Push(Expression.Label("tryLabel"));
            // only one of these can be non-null
            Expression  @finally      = Visit(node.Finally);
            Expression  fault         = Visit(node.Fault);
            LabelTarget finallyReturn = _returnLabels.Pop();
            int         finallyYields = _yields.Count;

            _inTryWithFinally = savedInTryWithFinally;

            if (@try == node.Body &&
                handlers == node.Handlers &&
                @finally == node.Finally &&
                fault == node.Fault)
            {
                return(node);
            }

            // No yields, just return
            if (startYields == _yields.Count)
            {
                Debug.Assert(@try.Type == node.Type);
                Debug.Assert(handlers == null || handlers.Count == 0 || handlers[0].Body.Type == node.Type);
                return(Expression.MakeTry(null, @try, @finally, fault, handlers));
            }

            if (fault != null && finallyYields != catchYields)
            {
                // No one needs this yet, and it's not clear how we should get back to
                // the fault
                throw new NotSupportedException("yield in fault block is not supported");
            }

            // If try has yields, we need to build a new try body that
            // dispatches to the yield labels
            var tryStart = Expression.Label("tryStart");

            if (tryYields != startYields)
            {
                @try = Expression.Block(MakeYieldRouter(node.Body.Type, startYields, tryYields, tryStart), @try);
                Debug.Assert(@try.Type == node.Body.Type);
            }

            // Transform catches with yield to deferred handlers
            if (catchYields != tryYields)
            {
                var block = new List <Expression>();

                block.Add(MakeYieldRouter(node.Body.Type, tryYields, catchYields, tryStart));
                block.Add(null); // empty slot to fill in later

                for (int i = 0, n = handlers.Count; i < n; i++)
                {
                    CatchBlock c = handlers[i];

                    if (c == node.Handlers[i])
                    {
                        continue;
                    }

                    if (handlers.IsReadOnly)
                    {
                        handlers = ArrayUtils.ToArray(handlers);
                    }

                    // the variable that will be scoped to the catch block
                    var exceptionVar = Expression.Variable(c.Test, null);

                    // the variable that the catch block body will use to
                    // access the exception. We reuse the original variable if
                    // the catch block had one. It needs to be hoisted because
                    // the catch might contain yields.
                    var deferredVar = c.Variable ?? Expression.Variable(c.Test, null);
                    LiftVariable(deferredVar);

                    // We need to ensure that filters can access the exception
                    // variable
                    Expression filter = c.Filter;
                    if (filter != null && c.Variable != null)
                    {
                        filter = Expression.Block(new[] { c.Variable }, Expression.Assign(c.Variable, exceptionVar), filter);
                    }

                    // catch (ExceptionType exceptionVar) {
                    //     deferredVar = exceptionVar;
                    // }
                    handlers[i] = Expression.Catch(
                        exceptionVar,
                        Expression.Block(
                            DelayedAssign(Visit(deferredVar), exceptionVar),
                            Expression.Default(node.Body.Type)
                            ),
                        filter
                        );

                    // We need to rewrite rethrows into "throw deferredVar"
                    var catchBody = new RethrowRewriter {
                        Exception = deferredVar
                    }.Visit(c.Body);

                    // if (deferredVar != null) {
                    //     ... catch body ...
                    // }
                    block.Add(
                        Expression.Condition(
                            Expression.NotEqual(Visit(deferredVar), AstUtils.Constant(null, deferredVar.Type)),
                            catchBody,
                            Expression.Default(node.Body.Type)
                            )
                        );
                }

                block[1] = Expression.MakeTry(null, @try, null, null, new ReadOnlyCollection <CatchBlock>(handlers));
                @try     = Expression.Block(block);
                Debug.Assert(@try.Type == node.Body.Type);
                handlers = new CatchBlock[0]; // so we don't reuse these
            }

            if (finallyYields != catchYields)
            {
                // We need to add a catch block to save the exception, so we
                // can rethrow in case there is a yield in the finally. Also,
                // add logic for returning. It looks like this:
                //
                // try { ... } catch (Exception all) { saved = all; }
                // finally {
                //  if (_finallyReturnVar) goto finallyReturn;
                //   ...
                //   if (saved != null) throw saved;
                //   finallyReturn:
                // }
                // if (_finallyReturnVar) goto _return;

                // We need to add a catch(Exception), so if we have catches,
                // wrap them in a try
                if (handlers.Count > 0)
                {
                    @try = Expression.MakeTry(null, @try, null, null, handlers);
                    Debug.Assert(@try.Type == node.Body.Type);
                    handlers = new CatchBlock[0];
                }

                // NOTE: the order of these routers is important
                // The first call changes the labels to all point at "tryEnd",
                // so the second router will jump to "tryEnd"
                var        tryEnd          = Expression.Label("tryEnd");
                Expression inFinallyRouter = MakeYieldRouter(node.Body.Type, catchYields, finallyYields, tryEnd);
                Expression inTryRouter     = MakeYieldRouter(node.Body.Type, catchYields, finallyYields, tryStart);

                var all   = Expression.Variable(typeof(Exception), "e");
                var saved = Expression.Variable(typeof(Exception), "$saved$" + _temps.Count);
                LiftVariable(saved);
                @try = Expression.Block(
                    Expression.TryCatchFinally(
                        Expression.Block(
                            inTryRouter,
                            @try,
                            DelayedAssign(Visit(saved), AstUtils.Constant(null, saved.Type)),
                            Expression.Label(tryEnd)
                            ),
                        Expression.Block(
                            MakeSkipFinallyBlock(finallyReturn),
                            inFinallyRouter,
                            @finally,
                            Expression.Condition(
                                Expression.NotEqual(Visit(saved), AstUtils.Constant(null, saved.Type)),
                                Expression.Throw(Visit(saved)),
                                Utils.Empty()
                                ),
                            Expression.Label(finallyReturn)
                            ),
                        Expression.Catch(all, Utils.Void(DelayedAssign(Visit(saved), all)))
                        ),
                    Expression.Condition(
                        Expression.Equal(_gotoRouter, AstUtils.Constant(GotoRouterYielding)),
                        Expression.Goto(_returnLabels.Peek()),
                        Utils.Empty()
                        )
                    );

                @finally = null;
            }
            else if (@finally != null)
            {
                // try or catch had a yield, modify finally so we can skip over it
                @finally = Expression.Block(
                    MakeSkipFinallyBlock(finallyReturn),
                    @finally,
                    Expression.Label(finallyReturn)
                    );
            }

            // Make the outer try, if needed
            if (handlers.Count > 0 || @finally != null || fault != null)
            {
                @try = Expression.MakeTry(null, @try, @finally, fault, handlers);
            }
            Debug.Assert(@try.Type == node.Body.Type);
            return(Expression.Block(Expression.Label(tryStart), @try));
        }
Ejemplo n.º 24
0
        private MSAst.LambdaExpression CreateOuterLambda(Type lambdaType, MSAst.Expression debuggableBody)
        {
            List <MSAst.Expression> bodyExpressions    = new List <MSAst.Expression>();
            List <MSAst.Expression> tryExpressions     = new List <MSAst.Expression>();
            List <MSAst.Expression> finallyExpressions = new List <MSAst.Expression>();

            Type returnType = lambdaType.GetMethod("Invoke").ReturnType;

            MSAst.LabelTarget returnLabelTarget = Ast.Label(returnType);

            // Init $funcInfo
            tryExpressions.Add(
                Ast.Assign(
                    _funcInfo,
                    Ast.Convert(_functionInfo, typeof(FunctionInfo))
                    )
                );

            // Init $traceLocations
            // $TODO: only do this if we're in TracePoints mode
            tryExpressions.Add(
                Ast.Assign(
                    _traceLocations,
                    Ast.Call(typeof(RuntimeOps).GetMethod("GetTraceLocations"), _funcInfo)
                    )
                );

            // Init sourceFile locals
            foreach (var entry in _sourceFilesMap)
            {
                tryExpressions.Add(
                    Ast.Assign(
                        entry.Value,
                        Ast.Constant(entry.Key, typeof(DebugSourceFile))
                        )
                    );
            }

            if (_noPushFrameOptimization)
            {
                tryExpressions.Add(_pushFrame);
            }

            tryExpressions.Add(Ast.Call(
                                   typeof(RuntimeOps).GetMethod("OnFrameEnterTraceEvent"),
                                   _thread
                                   ));

            var frameExit = AstUtils.If(
                Ast.Equal(
                    _debugMarkerLocationMap.Length > 0 ?
                    Ast.Property(_sourceFilesMap[_debugMarkerLocationMap[0].SourceFile], "Mode") :
                    _globalDebugMode,
                    AstUtils.Constant((int)DebugMode.FullyEnabled)
                    ),
                Ast.Call(
                    typeof(RuntimeOps).GetMethod("OnFrameExitTraceEvent"),
                    _thread,
                    _debugMarker,
                    _retVal != null ? (MSAst.Expression)Ast.Convert(_retVal, typeof(object)) : Ast.Constant(null)
                    )
                );

            // normal exit
            tryExpressions.Add(
                Ast.Block(
                    _retVal != null ? Ast.Assign(_retVal, debuggableBody) : debuggableBody,
                    Ast.Assign(_frameExitException, Ast.Constant(true)),
                    frameExit)
                );

            tryExpressions.Add(
                _retVal != null ? (MSAst.Expression)Ast.Return(returnLabelTarget, _retVal) : Ast.Empty()
                );

            MSAst.Expression[] popFrame = new MSAst.Expression[] {
                AstUtils.If(
                    // Fire thead-exit event if PopFrame returns true
                    Ast.AndAlso(
                        Ast.Equal(Ast.Call(typeof(RuntimeOps).GetMethod("PopFrame"), _thread), Ast.Constant(true)),
                        Ast.Equal(_globalDebugMode, AstUtils.Constant((int)DebugMode.FullyEnabled))
                        ),
                    Ast.Call(
                        typeof(RuntimeOps).GetMethod("OnThreadExitEvent"),
                        _thread
                        )
                    )
            };

            if (_noPushFrameOptimization)
            {
                finallyExpressions.AddRange(popFrame);
            }
            else
            {
                finallyExpressions.Add(
                    AstUtils.If(
                        Ast.Equal(_framePushed, Ast.Constant(true)),
                        popFrame
                        )
                    );
            }

            MSAst.ParameterExpression caughtException;

            // Run the function body
            bodyExpressions.Add(Ast.TryCatchFinally(
                                    Ast.TryCatch(
                                        Ast.Block(
                                            ArrayUtils.Append(tryExpressions.ToArray(), Ast.Default(returnType))
                                            ),
                                        Ast.Catch(
                                            caughtException = Ast.Variable(typeof(Exception), "$caughtException"),
                                            Ast.Block(
                                                // The expressions below will always throw.
                                                // If the exception needs to be cancelled then OnTraceEvent will throw ForceToGeneratorLoopException.
                                                // If the exception is not being cancelled then we'll just rethrow at the end of the catch block.
                                                AstUtils.If(
                                                    Ast.Not(
                                                        Ast.TypeIs(
                                                            caughtException,
                                                            typeof(ForceToGeneratorLoopException)
                                                            )
                                                        ),
                                                    AstUtils.If(
                                                        Ast.NotEqual(_globalDebugMode, AstUtils.Constant((int)DebugMode.Disabled)),
                                                        _noPushFrameOptimization ? Ast.Empty() : _conditionalPushFrame,
                                                        Ast.Call(
                                                            typeof(RuntimeOps).GetMethod("OnTraceEventUnwind"),
                                                            _thread,
                                                            _debugMarker,
                                                            caughtException
                                                            )
                                                        ),
                                                    // exception exit
                                                    AstUtils.If(
                                                        Ast.Not(_frameExitException),
                                                        frameExit
                                                        )
                                                    ),

                                                Ast.Rethrow(),

                                                // Ensuring that the catch block is of the same type as the try block
                                                Ast.Default(returnType)
                                                )
                                            )
                                        ),
                                    Ast.Block(finallyExpressions),
                                    Ast.Catch(
                                        typeof(ForceToGeneratorLoopException),
                                        Ast.TryFinally(
                                            // Handle ForceToGeneratorLoopException
                                            Ast.Block(
                                                returnType != typeof(void) ? Ast.Block(
                                                    Ast.Assign(
                                                        _retValFromGeneratorLoop,
                                                        Ast.Call(
                                                            typeof(RuntimeOps).GetMethod("GeneratorLoopProc"),
                                                            _thread
                                                            )
                                                        ),
                                                    AstUtils.If(
                                                        Ast.NotEqual(
                                                            _retValFromGeneratorLoop,
                                                            Ast.Constant(null)
                                                            ),
                                                        Ast.Assign(_retVal, Ast.Convert(_retValFromGeneratorLoop, returnType)),
                                                        Ast.Return(
                                                            returnLabelTarget,
                                                            Ast.Convert(_retValFromGeneratorLoop, returnType)
                                                            )
                                                        ).Else(
                                                        Ast.Assign(_retVal, Ast.Default(returnType)),
                                                        Ast.Return(
                                                            returnLabelTarget,
                                                            Ast.Default(returnType)
                                                            )
                                                        )
                                                    ) :
                                                Ast.Block(
                                                    Ast.Call(
                                                        typeof(RuntimeOps).GetMethod("GeneratorLoopProc"),
                                                        _thread
                                                        ),
                                                    Ast.Return(returnLabelTarget)
                                                    )
                                                ,
                                                // Ensuring that the catch block is of the same type as the try block
                                                Ast.Default(returnType)
                                                ),
                                            // Make sure that the debugMarker is up-to-date after the generator loop
                                            Ast.Assign(
                                                _debugMarker,
                                                Ast.Call(
                                                    typeof(RuntimeOps).GetMethod("GetCurrentSequencePointForLeafGeneratorFrame"),
                                                    _thread
                                                    )
                                                )
                                            )
                                        )
                                    ));

            MSAst.Expression body = Ast.Block(bodyExpressions);

            if (body.Type == typeof(void) && returnType != typeof(void))
            {
                body = Ast.Block(body, Ast.Default(returnType));
            }

            return(Ast.Lambda(
                       lambdaType,
                       Ast.Block(
                           _lambdaVars,
                           Ast.Label(returnLabelTarget, body)
                           ),
                       _alias,
                       _lambdaParams));
        }
Ejemplo n.º 25
0
        internal Expression Reduce(bool shouldInterpret, bool emitDebugSymbols, int compilationThreshold,
                                   IList <ParameterExpression> parameters, Func <Expression <Func <MutableTuple, object> >,
                                                                                 Expression <Func <MutableTuple, object> > > bodyConverter)
        {
            _state   = LiftVariable(Expression.Parameter(typeof(int), "state"));
            _current = LiftVariable(Expression.Parameter(typeof(object), "current"));

            // lift the parameters into the tuple
            foreach (ParameterExpression pe in parameters)
            {
                LiftVariable(pe);
            }
            DelayedTupleExpression liftedGen = LiftVariable(_generatorParam);
            // Visit body
            Expression body = Visit(_body);

            Debug.Assert(_returnLabels.Count == 1);

            // Add the switch statement to the body
            int count = _yields.Count;
            var cases = new SwitchCase[count + 1];

            for (int i = 0; i < count; i++)
            {
                cases[i] = Expression.SwitchCase(Expression.Goto(_yields[i].Label), AstUtils.Constant(_yields[i].State));
            }
            cases[count] = Expression.SwitchCase(Expression.Goto(_returnLabels.Peek()), AstUtils.Constant(Finished));

            // Create the lambda for the PythonGeneratorNext, hoisting variables
            // into a tuple outside the lambda
            Expression[] tupleExprs = new Expression[_vars.Count];
            foreach (var variable in _orderedVars)
            {
                // first 2 are our state & out var
                if (variable.Value.Index >= 2 && variable.Value.Index < (parameters.Count + 2))
                {
                    tupleExprs[variable.Value.Index] = parameters[variable.Value.Index - 2];
                }
                else
                {
                    tupleExprs[variable.Value.Index] = Expression.Default(variable.Key.Type);
                }
            }

            Expression          newTuple  = MutableTuple.Create(tupleExprs);
            Type                tupleType = _tupleType.Value = newTuple.Type;
            ParameterExpression tupleExpr = _tupleExpr.Value = Expression.Parameter(tupleType, "tuple");
            ParameterExpression tupleArg  = Expression.Parameter(typeof(MutableTuple), "tupleArg");

            _temps.Add(_gotoRouter);
            _temps.Add(tupleExpr);

            // temps for the outer lambda
            ParameterExpression tupleTmp = Expression.Parameter(tupleType, "tuple");
            ParameterExpression ret      = Expression.Parameter(typeof(PythonGenerator), "ret");

            var innerLambda = Expression.Lambda <Func <MutableTuple, object> >(
                Expression.Block(
                    _temps.ToArray(),
                    Expression.Assign(
                        tupleExpr,
                        Expression.Convert(
                            tupleArg,
                            tupleType
                            )
                        ),
                    Expression.Switch(Expression.Assign(_gotoRouter, _state), cases),
                    body,
                    MakeAssign(_state, AstUtils.Constant(Finished)),
                    Expression.Label(_returnLabels.Peek()),
                    _current
                    ),
                _name,
                new ParameterExpression[] { tupleArg }
                );

            // Generate a call to PythonOps.MakeGeneratorClosure(Tuple data, object generatorCode)
            return(Expression.Block(
                       new[] { tupleTmp, ret },
                       Expression.Assign(
                           ret,
                           Expression.Call(
                               typeof(PythonOps).GetMethod("MakeGenerator"),
                               parameters[0],
                               Expression.Assign(tupleTmp, newTuple),
                               emitDebugSymbols ?
                               (Expression)bodyConverter(innerLambda) :
                               (Expression)Expression.Constant(
                                   new LazyCode <Func <MutableTuple, object> >(
                                       bodyConverter(innerLambda),
                                       shouldInterpret,
                                       compilationThreshold
                                       ),
                                   typeof(object)
                                   )
                               )
                           ),
                       new DelayedTupleAssign(
                           new DelayedTupleExpression(liftedGen.Index, new StrongBox <ParameterExpression>(tupleTmp), _tupleType, typeof(PythonGenerator)),
                           ret
                           ),
                       ret
                       ));
        }
Ejemplo n.º 26
0
 internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen)
 {
     return(AstUtils.Constant(_value));
 }
Ejemplo n.º 27
0
 protected override Expression ToExpression(OverloadResolver /*!*/ resolver, RestrictedArguments /*!*/ args, bool[] /*!*/ hasBeenUsed)
 {
     return(AstUtils.Constant(Activator.CreateInstance(ParameterInfo.ParameterType, ((RubyOverloadResolver)resolver).Context)));
 }
Ejemplo n.º 28
0
 public override Expression /*!*/ CreateExpression()
 {
     return(Methods.GetMethod(GetType(), "MakeShared").OpCall(_signature.CreateExpression(), AstUtils.Constant(_lexicalScopeId)));
 }
Ejemplo n.º 29
0
        protected override bool Build(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool defaultFallback)
        {
            RubyModule currentDeclaringModule;
            string     currentMethodName;

            var scope     = args.Scope;
            var scopeExpr = AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope));

            RubyScope targetScope;
            int       scopeNesting = scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out targetScope);

            if (scopeNesting == -1)
            {
                metaBuilder.AddCondition(Methods.IsSuperOutOfMethodScope.OpCall(scopeExpr));
                metaBuilder.SetError(Methods.MakeTopLevelSuperException.OpCall());
                return(true);
            }

            object target           = targetScope.SelfObject;
            var    targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self");
            var    assignTarget     = Ast.Assign(
                targetExpression,
                Methods.GetSuperCallTarget.OpCall(scopeExpr, AstUtils.Constant(scopeNesting))
                );

            if (_signature.HasImplicitArguments && targetScope.Kind == ScopeKind.BlockMethod)
            {
                metaBuilder.AddCondition(Ast.NotEqual(assignTarget, Ast.Field(null, Fields.NeedsUpdate)));
                metaBuilder.SetError(Methods.MakeImplicitSuperInBlockMethodError.OpCall());
                return(true);
            }

            // If we need to update we return RubyOps.NeedsUpdate instance that will cause the subsequent conditions to fail:
            metaBuilder.AddInitialization(assignTarget);

            args.SetTarget(targetExpression, target);

            Debug.Assert(currentDeclaringModule != null);

            RubyMemberInfo method;
            RubyMemberInfo methodMissing = null;

            // MRI bug: Uses currentDeclaringModule for method look-up so we can end up with an instance method of class C
            // called on a target of another class. See http://redmine.ruby-lang.org/issues/show/2419.

            // we need to lock the hierarchy of the target class:
            var targetClass = scope.RubyContext.GetImmediateClassOf(target);

            using (targetClass.Context.ClassHierarchyLocker()) {
                // initialize all methods in ancestors:
                targetClass.InitializeMethodsNoLock();

                // target is stored in a local, therefore it cannot be part of the restrictions:
                metaBuilder.TreatRestrictionsAsConditions = true;
                metaBuilder.AddTargetTypeTest(target, targetClass, targetExpression, args.MetaContext,
                                              new[] { Symbols.MethodMissing } // currentMethodName is resolved for super, which cannot be an instance singleton
                                              );
                metaBuilder.TreatRestrictionsAsConditions = false;

                method = targetClass.ResolveSuperMethodNoLock(currentMethodName, currentDeclaringModule).InvalidateSitesOnOverride().Info;

                if (_signature.ResolveOnly)
                {
                    metaBuilder.Result = AstUtils.Constant(method != null);
                    return(true);
                }

                if (method == null)
                {
                    // MRI: method_missing is called for the targetClass, not for the super:
                    methodMissing = targetClass.ResolveMethodMissingForSite(currentMethodName, RubyMethodVisibility.None);
                }
            }

            if (method != null)
            {
                method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule);
            }
            else
            {
                return(RubyCallAction.BuildMethodMissingCall(metaBuilder, args, currentMethodName, methodMissing, RubyMethodVisibility.None, true, defaultFallback));
            }

            return(true);
        }
Ejemplo n.º 30
0
        internal Expression MakeExpression(RestrictedArguments restrictedArgs)
        {
            bool[]       usageMarkers;
            Expression[] spilledArgs;
            Expression[] callArgs = GetArgumentExpressions(restrictedArgs, out usageMarkers, out spilledArgs);

            Expression call;
            MethodBase mb = _overload.ReflectionInfo;

            // TODO: make MakeExpression virtual on OverloadInfo?
            if (mb == null)
            {
                throw new InvalidOperationException("Cannot generate an expression for an overload w/o MethodBase");
            }

            MethodInfo mi = mb as MethodInfo;

            if (mi != null)
            {
                Expression instance;
                if (mi.IsStatic)
                {
                    instance = null;
                }
                else
                {
                    Debug.Assert(mi != null);
                    instance = _instanceBuilder.ToExpression(ref mi, _resolver, restrictedArgs, usageMarkers);
                    Debug.Assert(instance != null, "Can't skip instance expression");
                }

                if (CompilerHelpers.IsVisible(mi))
                {
                    call = AstUtils.SimpleCallHelper(instance, mi, callArgs);
                }
                else
                {
                    call = Ast.Call(
                        typeof(BinderOps).GetMethod("InvokeMethod"),
                        AstUtils.Constant(mi),
                        instance != null ? AstUtils.Convert(instance, typeof(object)) : AstUtils.Constant(null),
                        AstUtils.NewArrayHelper(typeof(object), callArgs)
                        );
                }
            }
            else
            {
                ConstructorInfo ci = (ConstructorInfo)mb;
                if (CompilerHelpers.IsVisible(ci))
                {
                    call = AstUtils.SimpleNewHelper(ci, callArgs);
                }
                else
                {
                    call = Ast.Call(
                        typeof(BinderOps).GetMethod("InvokeConstructor"),
                        AstUtils.Constant(ci),
                        AstUtils.NewArrayHelper(typeof(object), callArgs)
                        );
                }
            }

            if (spilledArgs != null)
            {
                call = Expression.Block(spilledArgs.AddLast(call));
            }

            Expression ret = _returnBuilder.ToExpression(_resolver, _argBuilders, restrictedArgs, call);

            List <Expression> updates = null;

            for (int i = 0; i < _argBuilders.Count; i++)
            {
                Expression next = _argBuilders[i].UpdateFromReturn(_resolver, restrictedArgs);
                if (next != null)
                {
                    if (updates == null)
                    {
                        updates = new List <Expression>();
                    }
                    updates.Add(next);
                }
            }

            if (updates != null)
            {
                if (ret.Type != typeof(void))
                {
                    ParameterExpression temp = Ast.Variable(ret.Type, "$ret");
                    updates.Insert(0, Ast.Assign(temp, ret));
                    updates.Add(temp);
                    ret = Ast.Block(new[] { temp }, updates.ToArray());
                }
                else
                {
                    updates.Insert(0, ret);
                    ret = Ast.Block(typeof(void), updates.ToArray());
                }
            }

            if (_resolver.Temps != null)
            {
                ret = Ast.Block(_resolver.Temps, ret);
            }

            return(ret);
        }