Beispiel #1
0
        protected Expression[] FinishTestForCandidate(IList <Type> testTypes, Type[] explicitArgTypes)
        {
            Expression[] exprArgs = MakeArgumentExpressions();
            Debug.Assert(exprArgs.Length == (explicitArgTypes.Length + ((_instance == null) ? 0 : 1)));
            Debug.Assert(testTypes == null || exprArgs.Length == testTypes.Count);

            MakeSplatTests();

            if (_reversedOperator)
            {
                ArrayUtils.SwapLastTwo(exprArgs);
            }

            if (explicitArgTypes.Length > 0 && testTypes != null)
            {
                // We've already tested the instance, no need to test it again. So remove it before adding
                // rules for the arguments
                Expression[] exprArgsWithoutInstance  = exprArgs;
                List <Type>  testTypesWithoutInstance = new List <Type>(testTypes);
                for (int i = 0; i < exprArgs.Length; i++)
                {
                    if (exprArgs[i] == _instance)
                    {
                        // We found the instance, so remove it
                        exprArgsWithoutInstance = ArrayUtils.RemoveAt(exprArgs, i);
                        testTypesWithoutInstance.RemoveAt(i);
                        break;
                    }
                }

                _test = Ast.AndAlso(_test, MakeNecessaryTests(_rule, testTypesWithoutInstance.ToArray(), exprArgsWithoutInstance));
            }

            return(exprArgs);
        }
Beispiel #2
0
        private void MakeParamsArrayTest()
        {
            int listIndex = Action.Signature.IndexOf(ArgumentType.List);

            Debug.Assert(listIndex != -1);
            _test = Ast.AndAlso(_test, MakeParamsTest(_args[listIndex + 1], _rule.Parameters[listIndex + 1]));
        }
Beispiel #3
0
        private void MakeParamsDictionaryTest()
        {
            IDictionary           dict     = (IDictionary)_args[_args.Length - 1];
            IDictionaryEnumerator dictEnum = dict.GetEnumerator();

            // verify the dictionary has the same count and arguments.

            string[] names = new string[dict.Count];
            int      index = 0;

            while (dictEnum.MoveNext())
            {
                names[index++] = (string)dictEnum.Entry.Key;
            }

            _test = Ast.AndAlso(
                _test,
                Ast.AndAlso(
                    Ast.TypeIs(_rule.Parameters[_rule.Parameters.Length - 1], typeof(IDictionary)),
                    Ast.Call(
                        typeof(BinderOps).GetMethod("CheckDictionaryMembers"),
                        Ast.Convert(_rule.Parameters[_rule.Parameters.Length - 1], typeof(IDictionary)),
                        _rule.AddTemplatedConstant(typeof(string[]), names)
                        )
                    )
                );
        }
Beispiel #4
0
        internal static ValidationInfo /*!*/ GetValidationInfo(params DynamicMetaObject /*!*/[] /*!*/ args)
        {
            Expression typeTest = null;

            for (int i = 0; i < args.Length; i++)
            {
                if (args[i].HasValue)
                {
                    IPythonObject val = args[i].Value as IPythonObject;
                    if (val != null)
                    {
                        Expression test = BindingHelpers.CheckTypeVersion(
                            AstUtils.Convert(args[i].Expression, val.GetType()),
                            val.PythonType.Version
                            );

                        test = Ast.AndAlso(
                            Ast.TypeEqual(args[i].Expression, val.GetType()),
                            test
                            );

                        if (typeTest != null)
                        {
                            typeTest = Ast.AndAlso(typeTest, test);
                        }
                        else
                        {
                            typeTest = test;
                        }
                    }
                }
            }

            return(new ValidationInfo(typeTest));
        }
Beispiel #5
0
        private Expression[] FinishTestForCandidate(Type[] testTypes, Type[] argTypes)
        {
            Expression[] exprargs = MakeArgumentExpressions();

            MakeSplatTests();

            if (_reversedOperator)
            {
                ArrayUtils.SwapLastTwo(exprargs);
            }

            if (argTypes.Length > 0 && testTypes != null)
            {
                // we've already tested the instance, no need to test it again...
                Expression[] testArgs = exprargs;
                Type[]       types    = testTypes;
                for (int i = 0; i < testArgs.Length; i++)
                {
                    if (testArgs[i] == _instance)
                    {
                        testArgs = ArrayUtils.RemoveAt(testArgs, i);
                        types    = ArrayUtils.RemoveAt(types, i);
                        break;
                    }
                }

                _test = Ast.AndAlso(_test, MakeNecessaryTests(_rule, new Type[][] { types }, testArgs));
            }

            return(exprargs);
        }
Beispiel #6
0
        public Expression MakeTestForTypes(Type[] types, int index)
        {
            Expression test = MakeTypeTest(types[index], index);

            if (index < types.Length - 1)
            {
                Expression nextTests = MakeTestForTypes(types, index + 1);
                if (ConstantCheck.Check(test, true))
                {
                    return(nextTests);
                }
                else if (ConstantCheck.Check(nextTests, true))
                {
                    return(test);
                }
                else
                {
                    return(Ast.AndAlso(test, nextTests));
                }
            }
            else
            {
                return(test);
            }
        }
Beispiel #7
0
        public static Expression MakeTypeTestExpression(Type t, Expression expr)
        {
            // we must always check for non-sealed types explicitly - otherwise we end up
            // doing fast-path behavior on a subtype which overrides behavior that wasn't
            // present for the base type.
            //TODO there's a question about nulls here
            if (CompilerHelpers.IsSealed(t) && t == expr.Type)
            {
                if (t.IsValueType)
                {
                    return(Ast.True());
                }
                return(Ast.NotEqual(expr, Ast.Null()));
            }

            return(Ast.AndAlso(
                       Ast.NotEqual(
                           expr,
                           Ast.Null()),
                       Ast.Equal(
                           Ast.Call(
                               Ast.ConvertHelper(expr, typeof(object)),
                               typeof(object).GetMethod("GetType")
                               ),
                           Ast.Constant(t)
                           )
                       ));
        }
Beispiel #8
0
        private void MakeParamsDictionaryTest()
        {
            IDictionary           dict     = (IDictionary)_args[_args.Length - 1];
            IDictionaryEnumerator dictEnum = dict.GetEnumerator();

            // verify the dictionary has the same count and arguments.

            string[] names = new string[dict.Count];
            int      index = 0;

            while (dictEnum.MoveNext())
            {
                string name = dictEnum.Entry.Key as string;
                if (name == null)
                {
                    throw new ArgumentTypeException(String.Format("expected string for dictionary argument got {0}", dictEnum.Entry.Key));
                }
                names[index++] = name;
            }

            _test = Ast.AndAlso(
                _test,
                Ast.AndAlso(
                    Ast.TypeIs(_rule.Parameters[_rule.Parameters.Count - 1], typeof(IDictionary)),
                    Ast.Call(
                        typeof(ScriptingRuntimeHelpers).GetMethod("CheckDictionaryMembers"),
                        Ast.Convert(_rule.Parameters[_rule.Parameters.Count - 1], typeof(IDictionary)),
                        Ast.Constant(names)
                        )
                    )
                );
        }
Beispiel #9
0
        protected virtual MethodBase[] GetTargetMethods()
        {
            if (_targets != null)
            {
                return(_targets);
            }

            object target = Callable;

            MethodBase[]       targets;
            Delegate           d;
            MemberGroup        mg;
            MethodGroup        mthgrp;
            BoundMemberTracker bmt;

            if ((d = target as Delegate) != null)
            {
                targets = GetDelegateTargets(d);
            }
            else if ((mg = target as MemberGroup) != null)
            {
                List <MethodInfo> foundTargets = new List <MethodInfo>();
                foreach (MemberTracker mt in mg)
                {
                    if (mt.MemberType == TrackerTypes.Method)
                    {
                        foundTargets.Add(((MethodTracker)mt).Method);
                    }
                }
                targets = foundTargets.ToArray();
            }
            else if ((mthgrp = target as MethodGroup) != null)
            {
                _test = Ast.AndAlso(_test, Ast.Equal(Ast.Convert(Rule.Parameters[0], typeof(object)), Ast.Constant(target)));

                List <MethodBase> foundTargets = new List <MethodBase>();
                foreach (MethodTracker mt in mthgrp.Methods)
                {
                    foundTargets.Add(mt.Method);
                }

                targets = foundTargets.ToArray();
            }
            else if ((bmt = target as BoundMemberTracker) != null)
            {
                targets = GetBoundMemberTargets(bmt);
            }
            else
            {
                targets = GetOperatorTargets(target);
            }

            return(targets);
        }
Beispiel #10
0
 public static MSA.Expression /*!*/ Logical(MSA.Expression /*!*/ left, MSA.Expression /*!*/ right, bool isConjunction)
 {
     if (isConjunction)
     {
         return(Ast.AndAlso(left, right));
     }
     else
     {
         return(Ast.OrElse(left, right));
     }
 }
Beispiel #11
0
 public void AddTest(Expression expression)
 {
     Assert.NotNull(expression);
     if (_test == null)
     {
         _test = expression;
     }
     else
     {
         _test = Ast.AndAlso(_test, expression);
     }
 }
Beispiel #12
0
 internal static ValidationInfo /*!*/ GetValidationInfo(DynamicMetaObject /*!*/ tested, PythonType type)
 {
     return(new ValidationInfo(
                Ast.AndAlso(
                    Ast.TypeEqual(tested.Expression, type.UnderlyingSystemType),
                    CheckTypeVersion(
                        AstUtils.Convert(tested.Expression, type.UnderlyingSystemType),
                        type.Version
                        )
                    )
                ));
 }
Beispiel #13
0
 public static Expression MakeParamsTest(StandardRule <T> rule, object paramArg, Expression listArg)
 {
     return(Ast.AndAlso(
                Ast.TypeIs(listArg, typeof(ICollection <object>)),
                Ast.Equal(
                    Ast.ReadProperty(
                        Ast.Convert(listArg, typeof(ICollection <object>)),
                        typeof(ICollection <object>).GetProperty("Count")
                        ),
                    rule.AddTemplatedConstant(typeof(int), ((IList <object>)paramArg).Count)
                    )
                ));
 }
Beispiel #14
0
        /// <summary>
        /// Builds the restrictions for calling with a splatted argument array.  Ensures that the
        /// argument is still an ICollection of object and that it has the same number of arguments.
        /// </summary>
        private static BindingRestrictions MakeParamsTest(DynamicMetaObject splattee, bool testTypes)
        {
            IList <object> list = splattee.Value as IList <object>;

            if (list == null)
            {
                if (splattee.Value == null)
                {
                    return(BindingRestrictions.GetExpressionRestriction(Ast.Equal(splattee.Expression, AstUtils.Constant(null))));
                }
                else
                {
                    return(BindingRestrictions.GetTypeRestriction(splattee.Expression, splattee.Value.GetType()));
                }
            }

            BindingRestrictions res = BindingRestrictions.GetExpressionRestriction(
                Ast.AndAlso(
                    Ast.TypeIs(splattee.Expression, typeof(IList <object>)),
                    Ast.Equal(
                        Ast.Property(
                            Ast.Convert(splattee.Expression, typeof(IList <object>)),
                            typeof(ICollection <object>).GetDeclaredProperty("Count")
                            ),
                        AstUtils.Constant(list.Count)
                        )
                    )
                );

            if (testTypes)
            {
                for (int i = 0; i < list.Count; i++)
                {
                    res = res.Merge(
                        BindingRestrictionsHelpers.GetRuntimeTypeRestriction(
                            Ast.Call(
                                AstUtils.Convert(
                                    splattee.Expression,
                                    typeof(IList <object>)
                                    ),
                                typeof(IList <object>).GetMethod("get_Item"),
                                AstUtils.Constant(i)
                                ),
                            CompilerHelpers.GetType(list[i])
                            )
                        );
                }
            }

            return(res);
        }
Beispiel #15
0
        protected override MethodBase[] GetTargetMethods()
        {
            object target = Arguments[0];
            Type   t      = GetTargetType(target);

            if (t != null)
            {
                Test = Ast.AndAlso(Test, Ast.Equal(Rule.Parameters[0], Ast.Constant(target)));

                return(CompilerHelpers.GetConstructors(t, Binder.PrivateBinding));
            }

            return(null);
        }
 /// <summary>
 /// If present, converts the finish condition body be a normal conditional body.
 /// The builder instance will become unfinished again.
 ///
 /// If no finish condition body is available, this extends the last condition check
 /// with the new condition.
 /// </summary>
 public void ExtendLastCondition(Expression condition)
 {
     if (_body != null)
     {
         AddCondition(condition, _body);
         _body = null;
     }
     else
     {
         _conditions[_conditions.Count - 1] = Ast.AndAlso(
             _conditions[_conditions.Count - 1],
             condition);
     }
 }
Beispiel #17
0
        public void AddTest(Expression expression)
        {
            ContractUtils.RequiresNotNull(expression, "expression");
            ContractUtils.Requires(TypeUtils.IsBool(expression.Type), "expression", Strings.TypeOfExpressionMustBeBool);

            if (_test == null)
            {
                _test = expression;
            }
            else
            {
                _test = Ast.AndAlso(_test, expression);
            }
        }
Beispiel #18
0
        internal override Expression CheckExpression(MethodBinderContext context, Expression[] parameters)
        {
            if (_count == 0)
            {
                return(null);
            }

            Expression res = context.CheckExpression(parameters[_start], _elementType);

            for (int i = 1; i < _count; i++)
            {
                res = Ast.AndAlso(res, context.CheckExpression(parameters[_start + i], _elementType));
            }
            return(res);
        }
Beispiel #19
0
            public static Expression BooleanAnd(Expression[] args)
            {
                int len = args.Length;

                switch (len)
                {
                case 0:
                    return(Ast.Constant(true));

                default:
                    var rargs = new Expression[len - 1];
                    Array.Copy(args, 1, rargs, 0, rargs.Length);
                    return(Ast.AndAlso(Ast.ConvertHelper(args[0], typeof(bool)), BooleanAnd(rargs)));
                }
            }
Beispiel #20
0
        private MethodBase[] GetBoundMemberTargets(BoundMemberTracker bmt)
        {
            Debug.Assert(bmt.Instance == null); // should be null for trackers that leak to user code

            MethodBase[] targets;
            _instance = Ast.Convert(
                Ast.Property(
                    Ast.Convert(Rule.Parameters[0], typeof(BoundMemberTracker)),
                    typeof(BoundMemberTracker).GetProperty("ObjectInstance")
                    ),
                bmt.BoundTo.DeclaringType
                );
            _test = Ast.AndAlso(
                _test,
                Ast.Equal(
                    Ast.Property(
                        Ast.Convert(Rule.Parameters[0], typeof(BoundMemberTracker)),
                        typeof(BoundMemberTracker).GetProperty("BoundTo")
                        ),
                    Ast.Constant(bmt.BoundTo)
                    )
                );
            _test = Ast.AndAlso(
                _test,
                Rule.MakeTypeTest(
                    CompilerHelpers.GetType(bmt.ObjectInstance),
                    Ast.Property(
                        Ast.Convert(Rule.Parameters[0], typeof(BoundMemberTracker)),
                        typeof(BoundMemberTracker).GetProperty("ObjectInstance")
                        )
                    )
                );
            switch (bmt.BoundTo.MemberType)
            {
            case TrackerTypes.MethodGroup:
                targets = ((MethodGroup)bmt.BoundTo).GetMethodBases();
                break;

            case TrackerTypes.Method:
                targets = new MethodBase[] { ((MethodTracker)bmt.BoundTo).Method };
                break;

            default:
                throw new InvalidOperationException();     // nothing else binds yet
            }
            return(targets);
        }
Beispiel #21
0
        private Expression /*!*/ MakeCheckSelf(DynamicMetaObjectBinder /*!*/ binder, CallSignature signature, DynamicMetaObject /*!*/[] /*!*/ args)
        {
            ArgumentType firstArgKind = signature.GetArgumentKind(0);

            Expression res;

            if (firstArgKind == ArgumentType.Simple || firstArgKind == ArgumentType.Instance)
            {
                res = CheckSelf(binder, AstUtils.Convert(Expression, typeof(Method)), args[0].Expression);
            }
            else if (firstArgKind != ArgumentType.List)
            {
                res = CheckSelf(binder, AstUtils.Convert(Expression, typeof(Method)), AstUtils.Constant(null));
            }
            else
            {
                // list, check arg[0] and then return original list.  If not a list,
                // or we have no items, then check against null & throw.
                res = CheckSelf(
                    binder,
                    AstUtils.Convert(Expression, typeof(Method)),
                    Ast.Condition(
                        Ast.AndAlso(
                            Ast.TypeIs(args[0].Expression, typeof(IList <object>)),
                            Ast.NotEqual(
                                Ast.Property(
                                    Ast.Convert(args[0].Expression, typeof(ICollection)),
                                    typeof(ICollection).GetProperty("Count")
                                    ),
                                AstUtils.Constant(0)
                                )
                            ),
                        Ast.Call(
                            Ast.Convert(args[0].Expression, typeof(IList <object>)),
                            typeof(IList <object>).GetMethod("get_Item"),
                            AstUtils.Constant(0)
                            ),
                        AstUtils.Constant(null)
                        )
                    );
            }

            return(res);
        }
Beispiel #22
0
        public static Expression MakeNecessaryTests(StandardRule <T> rule, IList <Type[]> necessaryTests, Expression [] arguments)
        {
            Expression typeTest = Ast.Constant(true);

            if (necessaryTests.Count > 0)
            {
                Type[] testTypes = null;

                for (int i = 0; i < necessaryTests.Count; i++)
                {
                    if (necessaryTests[i] == null)
                    {
                        continue;
                    }
                    if (testTypes == null)
                    {
                        testTypes = new Type[necessaryTests[i].Length];
                    }

                    for (int j = 0; j < necessaryTests[i].Length; j++)
                    {
                        if (testTypes[j] == null || testTypes[j].IsAssignableFrom(necessaryTests[i][j]))
                        {
                            // no test yet or more specific test
                            testTypes[j] = necessaryTests[i][j];
                        }
                    }
                }

                if (testTypes != null)
                {
                    for (int i = 0; i < testTypes.Length; i++)
                    {
                        if (testTypes[i] != null)
                        {
                            Debug.Assert(i < arguments.Length);
                            typeTest = Ast.AndAlso(typeTest, rule.MakeTypeTest(testTypes[i], arguments[i]));
                        }
                    }
                }
            }
            return(typeTest);
        }
Beispiel #23
0
        /// <summary>
        /// Builds the restrictions for calling with a splatted argument array.  Ensures that the
        /// argument is still an ICollection of object and that it has the same number of arguments.
        /// </summary>
        private static Restrictions MakeParamsTest(object paramArg, Expression listArg, bool testTypes)
        {
            IList <object> coll = (IList <object>)paramArg;

            Restrictions res = Restrictions.GetExpressionRestriction(
                Ast.AndAlso(
                    Ast.TypeIs(listArg, typeof(IList <object>)),
                    Ast.Equal(
                        Ast.Property(
                            Ast.Convert(listArg, typeof(IList <object>)),
                            typeof(ICollection <object>).GetProperty("Count")
                            ),
                        Ast.Constant(coll.Count)
                        )
                    )
                );

            if (testTypes)
            {
                for (int i = 0; i < coll.Count; i++)
                {
                    res = res.Merge(
                        Restrictions.GetTypeRestriction(
                            Ast.Call(
                                AstUtils.Convert(
                                    listArg,
                                    typeof(IList <object>)
                                    ),
                                typeof(IList <object>).GetMethod("get_Item"),
                                Ast.Constant(i)
                                ),
                            CompilerHelpers.GetType(coll[i])
                            )
                        );
                }
            }

            return(res);
        }
Beispiel #24
0
        private void MakeInvalidParametersRule(MethodBinder binder, CallType callType, MethodBase[] targets)
        {
            MakeSplatTests();

            if (_args.Length > 1)
            {
                // we do an exact type check on all of the arguments types for a failed call.
                Expression[] argExpr = MakeArgumentExpressions();
                SymbolId[]   names;
                Type[]       vals;
                GetArgumentNamesAndTypes(out names, out vals);
                if (_instance != null)
                {
                    // target type was added to test already
                    argExpr = ArrayUtils.RemoveFirst(argExpr);
                }

                _test = Ast.AndAlso(_test, MakeNecessaryTests(_rule, new Type[][] { vals }, argExpr));
            }

            _rule.SetTarget(Binder.MakeInvalidParametersError(binder, Action, callType, targets, _rule, _args));
        }
Beispiel #25
0
        /// <summary>
        /// Builds the restrictions for calling with keyword arguments.  The restrictions include
        /// tests on the individual keys of the dictionary to ensure they have the same names.
        /// </summary>
        private static BindingRestrictions MakeParamsDictionaryTest(IList <DynamicMetaObject> args, bool testTypes)
        {
            IDictionary           dict     = (IDictionary)args[args.Count - 1].Value;
            IDictionaryEnumerator dictEnum = dict.GetEnumerator();

            // verify the dictionary has the same count and arguments.

            string[] names = new string[dict.Count];
            Type[]   types = testTypes ? new Type[dict.Count] : null;
            int      index = 0;

            while (dictEnum.MoveNext())
            {
                string name = dictEnum.Entry.Key as string;
                if (name == null)
                {
                    throw ScriptingRuntimeHelpers.SimpleTypeError(
                              $"expected string for dictionary argument got {dictEnum.Entry.Key}");
                }
                names[index] = name;
                if (types != null)
                {
                    types[index] = CompilerHelpers.GetType(dictEnum.Entry.Value);
                }
                index++;
            }

            return(BindingRestrictions.GetExpressionRestriction(
                       Ast.AndAlso(
                           Ast.TypeIs(args[args.Count - 1].Expression, typeof(IDictionary)),
                           Ast.Call(
                               typeof(BinderOps).GetMethod("CheckDictionaryMembers"),
                               Ast.Convert(args[args.Count - 1].Expression, typeof(IDictionary)),
                               AstUtils.Constant(names),
                               testTypes ? AstUtils.Constant(types) : AstUtils.Constant(null, typeof(Type[]))
                               )
                           )
                       ));
        }
Beispiel #26
0
        private void MakeInvalidParametersRule(BindingTarget bt)
        {
            MakeSplatTests();

            if (_args.Length > 1)
            {
                // we do an exact type check on all of the arguments types for a failed call.
                Expression[] argExpr = MakeArgumentExpressions();
                SymbolId[]   names;
                Type[]       vals;
                GetArgumentNamesAndTypes(out names, out vals);
                if (_instance != null)
                {
                    // target type was added to test already
                    argExpr = ArrayUtils.RemoveFirst(argExpr);
                }

                _test = Ast.AndAlso(_test, MakeNecessaryTests(_rule, vals, argExpr));
            }

            _rule.Target = Binder.MakeInvalidParametersError(bt).MakeErrorForRule(_rule, Binder);
        }
Beispiel #27
0
        public void AddTargetTypeTest(object target, RubyClass /*!*/ targetClass, Expression /*!*/ targetParameter, DynamicMetaObject /*!*/ metaContext,
                                      IEnumerable <string> /*!*/ resolvedNames)
        {
            // no changes to the module's class hierarchy while building the test:
            targetClass.Context.RequiresClassHierarchyLock();

            // initialization changes the version number, so ensure that the module is initialized:
            targetClass.InitializeMethodsNoLock();

            var context = (RubyContext)metaContext.Value;

            if (target is IRubyObject)
            {
                Type type = target.GetType();
                AddTypeRestriction(type, targetParameter);

                // Ruby objects (get the method directly to prevent interface dispatch):
                MethodInfo classGetter = type.GetMethod(Methods.IRubyObject_get_ImmediateClass.Name, BindingFlags.Public | BindingFlags.Instance);
                if (type.IsVisible() && classGetter != null && classGetter.ReturnType == typeof(RubyClass))
                {
                    AddCondition(
                        // (#{type})target.ImmediateClass.Version.Method == #{immediateClass.Version.Method}
                        Ast.Equal(
                            Ast.Field(
                                Ast.Field(
                                    Ast.Call(Ast.Convert(targetParameter, type), classGetter),
                                    Fields.RubyModule_Version
                                    ),
                                Fields.VersionHandle_Method
                                ),
                            AstUtils.Constant(targetClass.Version.Method)
                            )
                        );
                    return;
                }

                // TODO: explicit iface-implementation
                throw new NotSupportedException("Type implementing IRubyObject should be visible and have ImmediateClass getter");
            }

            AddRuntimeTest(metaContext);

            // singleton nil:
            if (target == null)
            {
                AddRestriction(Ast.Equal(targetParameter, AstUtils.Constant(null)));
                AddVersionTest(context.NilClass);
                return;
            }

            // singletons true, false:
            if (target is bool)
            {
                AddRestriction(Ast.AndAlso(
                                   Ast.TypeIs(targetParameter, typeof(bool)),
                                   Ast.Equal(Ast.Convert(targetParameter, typeof(bool)), AstUtils.Constant(target))
                                   ));

                AddVersionTest((bool)target ? context.TrueClass : context.FalseClass);
                return;
            }

            var nominalClass = targetClass.NominalClass;

            Debug.Assert(!nominalClass.IsSingletonClass);
            Debug.Assert(!nominalClass.IsRubyClass);

            // Do we need a singleton check?
            if (nominalClass.ClrSingletonMethods == null ||
                CollectionUtils.TrueForAll(resolvedNames, (methodName) => !nominalClass.ClrSingletonMethods.ContainsKey(methodName)))
            {
                // no: there is no singleton subclass of target class that defines any method being called:
                AddTypeRestriction(target.GetType(), targetParameter);
                AddVersionTest(targetClass);
            }
            else if (targetClass.IsSingletonClass)
            {
                // yes: check whether the incoming object is a singleton and the singleton has the right version:
                AddTypeRestriction(target.GetType(), targetParameter);
                AddCondition(Methods.IsClrSingletonRuleValid.OpCall(
                                 metaContext.Expression,
                                 targetParameter,
                                 AstUtils.Constant(targetClass.Version.Method)
                                 ));
            }
            else
            {
                // yes: check whether the incoming object is NOT a singleton and the class has the right version:
                AddTypeRestriction(target.GetType(), targetParameter);
                AddCondition(Methods.IsClrNonSingletonRuleValid.OpCall(
                                 metaContext.Expression,
                                 targetParameter,
                                 Ast.Constant(targetClass.Version),
                                 AstUtils.Constant(targetClass.Version.Method)
                                 ));
            }
        }
Beispiel #28
0
 public void AddCondition(Expression /*!*/ condition)
 {
     Assert.NotNull(condition);
     _condition = (_condition != null) ? Ast.AndAlso(_condition, condition) : condition;
 }
        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));
        }
Beispiel #30
0
        private MSA.Expression /*!*/ TransformExceptionHandling(AstGenerator /*!*/ gen, ResultOperation resultOperation)
        {
            Assert.NotNull(gen);

            MSA.Expression exceptionThrownVariable  = gen.CurrentScope.DefineHiddenVariable("#exception-thrown", typeof(bool));
            MSA.Expression exceptionRethrowVariable = gen.CurrentScope.DefineHiddenVariable("#exception-rethrow", typeof(bool));
            MSA.Expression retryingVariable         = gen.CurrentScope.DefineHiddenVariable("#retrying", typeof(bool));
            MSA.Expression oldExceptionVariable     = gen.CurrentScope.DefineHiddenVariable("#old-exception", typeof(Exception));

            MSA.ParameterExpression unwinder, exceptionVariable;
            MSA.Expression          transformedBody;
            MSA.Expression          transformedEnsure;
            MSA.Expression          transformedElse;

            if (_ensureStatements != null)
            {
                transformedEnsure = Ast.Block(
                    // ensure:
                    Ast.Assign(oldExceptionVariable, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)),
                    gen.TransformStatements(_ensureStatements, ResultOperation.Ignore),
                    Methods.SetCurrentException.OpCall(gen.CurrentScopeVariable, oldExceptionVariable),

                    // rethrow:
                    AstUtils.IfThen(
                        Ast.AndAlso(
                            exceptionRethrowVariable,
                            Ast.NotEqual(oldExceptionVariable, AstUtils.Constant(null))
                            ),
                        Ast.Throw(oldExceptionVariable)
                        )
                    );
            }
            else
            {
                // rethrow:
                transformedEnsure = AstUtils.IfThen(
                    Ast.AndAlso(
                        exceptionRethrowVariable,
                        Ast.NotEqual(
                            Ast.Assign(oldExceptionVariable, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)),
                            AstUtils.Constant(null, typeof(Exception)))
                        ),
                    Ast.Throw(oldExceptionVariable)
                    );
            }

            if (_elseStatements != null)
            {
                transformedElse = gen.TransformStatements(_elseStatements, resultOperation);
            }
            else
            {
                transformedElse = AstUtils.Empty();
            }

            // body should do return, but else-clause is present => we cannot do return from the guarded statements:
            // (the value of the last expression in the body cannot be the last executed expression statement => we can ignore it):
            transformedBody = gen.TransformStatements(_statements, (_elseStatements != null) ? ResultOperation.Ignore : resultOperation);

            MSA.Expression enterRescue = null, leaveRescue = null;
            var            retryLabel = Ast.Label("retry");

            // make rescue clause:
            MSA.Expression transformedRescue;
            if (_rescueClauses != null)
            {
                // outer-most EH blocks sets and clears runtime flag RuntimeFlowControl.InTryRescue:
                if (gen.CurrentRescue == null)
                {
                    enterRescue = Methods.EnterRescue.OpCall(gen.CurrentScopeVariable);
                    leaveRescue = Methods.LeaveRescue.OpCall(gen.CurrentScopeVariable);
                }
                else
                {
                    enterRescue = leaveRescue = AstUtils.Empty();
                }

                gen.EnterRescueClause(retryingVariable, retryLabel);

                var handlers = new IfStatementTest[_rescueClauses.Count];
                for (int i = 0; i < handlers.Length; i++)
                {
                    handlers[i] = _rescueClauses[i].Transform(gen, resultOperation);
                }

                transformedRescue =
                    AstUtils.Try(
                        enterRescue,
                        AstUtils.If(handlers, Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(true)))
                        ).Filter(unwinder = Ast.Parameter(typeof(EvalUnwinder), "#u"),
                                 Ast.Equal(Ast.Field(unwinder, EvalUnwinder.ReasonField), AstUtils.Constant(BlockReturnReason.Retry)),

                                 Ast.Block(
                                     Ast.Assign(retryingVariable, AstUtils.Constant(true)),
                                     Ast.Continue(retryLabel),
                                     AstUtils.Empty()
                                     )
                                 );


                gen.LeaveRescueClause();
            }
            else
            {
                transformedRescue = Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(true));
            }

            if (_elseStatements != null)
            {
                transformedElse = AstUtils.Unless(exceptionThrownVariable, transformedElse);
            }

            var result = Ast.Block(
                Ast.Label(retryLabel),
                AstUtils.Try(
                    Ast.Assign(exceptionThrownVariable, AstUtils.Constant(false)),
                    Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(false)),
                    Ast.Assign(retryingVariable, AstUtils.Constant(false)),

                    // save exception (old_$! is not used unless there is a rescue clause):
                    (_rescueClauses == null) ? (MSA.Expression)AstUtils.Empty() :
                    Ast.Assign(oldExceptionVariable, Methods.GetCurrentException.OpCall(gen.CurrentScopeVariable)),

                    AstUtils.Try(
                        Ast.Block(transformedBody, AstUtils.Empty())
                        ).Filter(exceptionVariable = Ast.Parameter(typeof(Exception), "#e"),
                                 Methods.CanRescue.OpCall(gen.CurrentScopeVariable, exceptionVariable),

                                 Ast.Assign(exceptionThrownVariable, AstUtils.Constant(true)),
                                 transformedRescue,
                                 AstUtils.Empty()
                                 ).FinallyIf((_rescueClauses != null),
                                             // restore previous exception if the current one has been handled:
                                             AstUtils.Unless(exceptionRethrowVariable,
                                                             Methods.SetCurrentException.OpCall(gen.CurrentScopeVariable, oldExceptionVariable)
                                                             ),
                                             leaveRescue
                                             ),

                    // unless (exception_thrown) do <else-statements> end
                    transformedElse,
                    AstUtils.Empty()
                    ).FilterIf((_rescueClauses != null || _elseStatements != null),
                               exceptionVariable = Ast.Parameter(typeof(Exception), "#e"),
                               Methods.CanRescue.OpCall(gen.CurrentScopeVariable, exceptionVariable),

                               Ast.Assign(exceptionRethrowVariable, AstUtils.Constant(true)),
                               AstUtils.Empty()
                               ).FinallyWithJumps(
                    AstUtils.Unless(retryingVariable, transformedEnsure)
                    )
                );

            return(result);
        }