Example #1
0
        private static DynamicMetaObject MakeGetItemIterable(DynamicMetaObject metaUserObject, PythonContext state, PythonTypeSlot pts, string method)
        {
            ParameterExpression tmp = Ast.Parameter(typeof(object), "getitemVal");

            return(new DynamicMetaObject(
                       Expression.Block(
                           new[] { tmp },
                           Expression.Call(
                               typeof(PythonOps).GetMethod(method),
                               AstUtils.Convert(metaUserObject.Expression, typeof(object)),
                               Ast.Block(
                                   MetaPythonObject.MakeTryGetTypeMember(
                                       state,
                                       pts,
                                       tmp,
                                       metaUserObject.Expression,
                                       Ast.Call(
                                           typeof(DynamicHelpers).GetMethod(nameof(DynamicHelpers.GetPythonType)),
                                           AstUtils.Convert(
                                               metaUserObject.Expression,
                                               typeof(object)
                                               )
                                           )
                                       ),
                                   tmp
                                   ),
                               AstUtils.Constant(
                                   CallSite <Func <CallSite, CodeContext, object, int, object> > .Create(
                                       new PythonInvokeBinder(state, new CallSignature(1))
                                       )
                                   )
                               )
                           ),
                       metaUserObject.Restrictions
                       ));
        }
Example #2
0
        public static Expression RecordMutator(Expression[] obj)
        {
            if (obj.Length == 2)
            {
                var rtd   = Unwrap(obj[0]);
                var index = Unwrap(obj[1]);

                if (rtd is BoundExpression && index is ConstantExpression)
                {
                    var rtdname = ((BoundExpression)rtd).Variable.Name;
                    var i       = (int)((ConstantExpression)index).Value;
                    var e       = Ast.Constant(new RecordMutatorConstant
                    {
                        RtdSymbol = rtdname,
                        Index     = i,
                        NameHint  = IronScheme.Compiler.Generator.VarHint,
                        NameHint2 = IronScheme.Compiler.Generator.VarHint2
                    });

                    return(Ast.Comma(e, Ast.Call(typeof(Records).GetMethod("RecordMutator"), obj)));
                }
            }
            return(null);
        }
            protected override bool AddMetaSlotAccess(PythonType metaType, PythonTypeSlot pts)
            {
                ParameterExpression tmp = Ast.Variable(typeof(object), "slotRes");

                pts.MakeGetExpression(
                    _state.Binder,
                    _codeContext,
                    _type,
                    new DynamicMetaObject(
                        AstUtils.Constant(metaType),
                        BindingRestrictions.Empty,
                        metaType
                        ),
                    _cb
                    );

                if (!pts.IsAlwaysVisible)
                {
                    _cb.AddCondition(Ast.Call(typeof(PythonOps).GetMethod("IsClsVisible"), _codeContext));
                    return(false);
                }

                return(pts.GetAlwaysSucceeds);
            }
Example #4
0
        internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op)
        {
            MSAst.Expression assignment;

            if (op != PythonOperationKind.None)
            {
                right = GlobalParent.Operation(
                    typeof(object),
                    op,
                    this,
                    right
                    );
            }

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

            if (Reference.PythonVariable != null)
            {
                assignment = AssignValue(
                    Parent.GetVariableExpression(Reference.PythonVariable),
                    ConvertIfNeeded(right, typeof(object))
                    );
            }
            else
            {
                assignment = Ast.Call(
                    null,
                    AstMethods.SetName,
                    Parent.LocalContext,
                    Ast.Constant(Name),
                    AstUtils.Convert(right, typeof(object))
                    );
            }

            return(GlobalParent.AddDebugInfoAndVoid(assignment, aspan));
        }
        public override MSAst.Expression Reduce()
        {
            // If debugging is off, return empty statement
            if (Optimize)
            {
                return(AstUtils.Empty());
            }

            // Transform into:
            // if (_test) {
            // } else {
            //     RaiseAssertionError(_message);
            // }
            return(GlobalParent.AddDebugInfoAndVoid(
                       AstUtils.Unless(                                     // if
                           TransformAndDynamicConvert(_test, typeof(bool)), // _test
                           Ast.Call(                                        // else branch
                               AstMethods.RaiseAssertionError,
                               TransformOrConstantNull(_message, typeof(object))
                               )
                           ),
                       Span
                       ));
        }
Example #6
0
        private void SplatDictionaryArgument(IList<string> splattedNames, IList<DynamicMetaObject> splattedArgs) {
            Assert.NotNull(splattedNames, splattedArgs);

            DynamicMetaObject dictMo = GetArgument(_signature.ArgumentCount - 1);
            IDictionary dict = (IDictionary)dictMo.Value;
            IDictionaryEnumerator dictEnum = dict.GetEnumerator();
            while (dictEnum.MoveNext()) {
                DictionaryEntry de = dictEnum.Entry;
                
                if (de.Key is string) {
                    splattedNames.Add((string)de.Key);
                    splattedArgs.Add(
                        DynamicMetaObject.Create(
                            de.Value,
                            Ast.Call(
                                AstUtils.Convert(dictMo.Expression, typeof(IDictionary)),
                                typeof(IDictionary).GetMethod("get_Item"),
                                AstUtils.Constant(de.Key as string)
                            )
                        )
                    );
                }
            }
        }
        private DynamicMetaObject TryPythonConversion(DynamicMetaObjectBinder conversion, Type type)
        {
            if (!type.IsEnum)
            {
                switch (Type.GetTypeCode(type))
                {
                case TypeCode.Object:
                    if (type == typeof(Complex))
                    {
                        return(MakeConvertRuleForCall(conversion, type, this, "__complex__", "ConvertToComplex",
                                                      (() => MakeConvertRuleForCall(conversion, type, this, "__float__", "ConvertToFloat",
                                                                                    (() => FallbackConvert(conversion)),
                                                                                    (x) => Ast.Call(null, typeof(PythonOps).GetMethod("ConvertFloatToComplex"), x))),
                                                      (x) => x));
                    }
                    else if (type == typeof(BigInteger))
                    {
                        return(MakeConvertRuleForCall(conversion, type, this, "__long__", "ConvertToLong"));
                    }
                    else if (type == typeof(IEnumerable))
                    {
                        return(PythonConversionBinder.ConvertToIEnumerable(conversion, Restrict(Value.GetType())));
                    }
                    else if (type == typeof(IEnumerator))
                    {
                        return(PythonConversionBinder.ConvertToIEnumerator(conversion, Restrict(Value.GetType())));
                    }
                    else if (type.IsSubclassOf(typeof(Delegate)))
                    {
                        return(MakeDelegateTarget(conversion, type, Restrict(Value.GetType())));
                    }
                    break;

                case TypeCode.Int32:
                    return(MakeConvertRuleForCall(conversion, type, this, "__int__", "ConvertToInt"));

                case TypeCode.Double:
                    return(MakeConvertRuleForCall(conversion, type, this, "__float__", "ConvertToFloat"));

                case TypeCode.Boolean:
                    return(PythonProtocol.ConvertToBool(
                               conversion,
                               this
                               ));

                case TypeCode.String:
                    if (!typeof(Extensible <string>).IsAssignableFrom(this.LimitType))
                    {
                        return(MakeConvertRuleForCall(conversion, type, this, "__str__", "ConvertToString"));
                    }
                    break;
                }
            }

            return(null);
        }
Example #8
0
        private DynamicMetaObject TryToCharConversion(DynamicMetaObject /*!*/ self)
        {
            DynamicMetaObject res;
            // we have an implicit conversion to char if the
            // string length == 1, but we can only represent
            // this is implicit via a rule.
            string     strVal  = self.Value as string;
            Expression strExpr = self.Expression;

            if (strVal == null)
            {
                Extensible <string> extstr = self.Value as Extensible <string>;
                if (extstr != null)
                {
                    strVal  = extstr.Value;
                    strExpr =
                        Ast.Property(
                            AstUtils.Convert(
                                strExpr,
                                typeof(Extensible <string>)
                                ),
                            typeof(Extensible <string>).GetProperty("Value")
                            );
                }
            }

            // we can only produce a conversion if we have a string value...
            if (strVal != null)
            {
                self = self.Restrict(self.GetRuntimeType());

                Expression getLen = Ast.Property(
                    AstUtils.Convert(
                        strExpr,
                        typeof(string)
                        ),
                    typeof(string).GetProperty("Length")
                    );

                if (strVal.Length == 1)
                {
                    res = new DynamicMetaObject(
                        Ast.Call(
                            AstUtils.Convert(strExpr, typeof(string)),
                            typeof(string).GetMethod("get_Chars"),
                            AstUtils.Constant(0)
                            ),
                        self.Restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Ast.Equal(getLen, AstUtils.Constant(1))))
                        );
                }
                else
                {
                    res = new DynamicMetaObject(
                        Ast.Throw(
                            Ast.Call(
                                typeof(PythonOps).GetMethod("TypeError"),
                                AstUtils.Constant("expected string of length 1 when converting to char, got '{0}'"),
                                Ast.NewArrayInit(typeof(object), self.Expression)
                                ),
                            ReturnType
                            ),
                        self.Restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Ast.NotEqual(getLen, AstUtils.Constant(1))))
                        );
                }
            }
            else
            {
                // let the base class produce the rule
                res = null;
            }

            return(res);
        }
Example #9
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(nameof(PythonOps.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(nameof(PythonOps.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(nameof(PythonOps.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(nameof(PythonOps.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))
                       ));
        }
Example #10
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(nameof(PythonOps.OldInstanceTryGetBoundCustomMember)),
                                               codeContext,
                                               self.Expression,
                                               AstUtils.Constant("__call__")
                                               )
                                           ),
                                       typeof(OperationFailed)
                                       )
                                   ),
                               Ast.Block(
                                   Utils.Try(
                                       Ast.Call(typeof(PythonOps).GetMethod(nameof(PythonOps.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(nameof(PythonOps.FunctionPopFrame)))
                                       ),
                                   tmp
                                   ),
                               Utils.Convert(
                                   BindingHelpers.InvokeFallback(invoke, codeContext, this, args).Expression,
                                   typeof(object)
                                   )
                               )
                           ),
                       self.Restrictions.Merge(BindingRestrictions.Combine(args))
                       ));
        }
        private DynamicMetaObject /*!*/ MakeGetMember(DynamicMetaObjectBinder /*!*/ member, DynamicMetaObject codeContext)
        {
            PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "OldClass GetMember");
            PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "OldClass GetMember");
            DynamicMetaObject self = Restrict(typeof(OldClass));

            Expression target;
            string     memberName = GetGetMemberName(member);

            switch (memberName)
            {
            case "__dict__":
                target = Ast.Block(
                    Ast.Call(
                        typeof(PythonOps).GetMethod("OldClassDictionaryIsPublic"),
                        self.Expression
                        ),
                    Ast.Call(
                        typeof(PythonOps).GetMethod("OldClassGetDictionary"),
                        self.Expression
                        )
                    );
                break;

            case "__bases__":
                target = Ast.Call(
                    typeof(PythonOps).GetMethod("OldClassGetBaseClasses"),
                    self.Expression
                    );
                break;

            case "__name__":
                target = Ast.Call(
                    typeof(PythonOps).GetMethod("OldClassGetName"),
                    self.Expression
                    );
                break;

            default:
                ParameterExpression tmp = Ast.Variable(typeof(object), "lookupVal");
                return(new DynamicMetaObject(
                           Ast.Block(
                               new ParameterExpression[] { tmp },
                               Ast.Condition(
                                   Expression.Not(
                                       Expression.TypeIs(
                                           Expression.Assign(
                                               tmp,
                                               Ast.Call(
                                                   typeof(PythonOps).GetMethod("OldClassTryLookupValue"),
                                                   AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext),
                                                   self.Expression,
                                                   AstUtils.Constant(memberName)
                                                   )
                                               ),
                                           typeof(OperationFailed)
                                           )
                                       ),
                                   tmp,
                                   AstUtils.Convert(
                                       GetMemberFallback(this, member, codeContext).Expression,
                                       typeof(object)
                                       )
                                   )
                               ),
                           self.Restrictions
                           ));
            }

            return(new DynamicMetaObject(
                       target,
                       self.Restrictions
                       ));
        }
        /// <summary>
        /// Returns an expression which creates the function object.
        /// </summary>
        internal MSAst.Expression MakeFunctionExpression()
        {
            var defaults    = new List <MSAst.Expression>();
            var kwdefaults  = new List <MSAst.Expression>();
            var annotations = new List <MSAst.Expression>();

            if (ReturnAnnotation != null)
            {
                // value needs to come before key in the array
                annotations.Add(AstUtils.Convert(ReturnAnnotation, typeof(object)));
                annotations.Add(Ast.Constant("return", typeof(string)));
            }

            foreach (var param in _parameters)
            {
                if (param.Kind == ParameterKind.Normal && param.DefaultValue != null)
                {
                    defaults.Add(AstUtils.Convert(param.DefaultValue, typeof(object)));
                }

                if (param.Kind == ParameterKind.KeywordOnly && param.DefaultValue != null)
                {
                    // value needs to come before key in the array
                    kwdefaults.Add(AstUtils.Convert(param.DefaultValue, typeof(object)));
                    kwdefaults.Add(Ast.Constant(param.Name, typeof(string)));
                }

                if (param.Annotation != null)
                {
                    // value needs to come before key in the array
                    annotations.Add(AstUtils.Convert(param.Annotation, typeof(object)));
                    annotations.Add(Ast.Constant(param.Name, typeof(string)));
                }
            }

            MSAst.Expression funcCode = GlobalParent.Constant(GetOrMakeFunctionCode());
            FuncCodeExpr = funcCode;

            MSAst.Expression ret;
            if (EmitDebugFunction())
            {
                LightLambdaExpression code = CreateFunctionLambda();

                // we need to compile all of the debuggable code together at once otherwise mdbg gets confused.  If we're
                // in tracing mode we'll still compile things one off though just to keep things simple.  The code will still
                // be debuggable but naive debuggers like mdbg will have more issues.
                ret = Ast.Call(
                    AstMethods.MakeFunctionDebug,                                                   // method
                    Parent.LocalContext,                                                            // 1. Emit CodeContext
                    FuncCodeExpr,                                                                   // 2. FunctionCode
                    ((IPythonGlobalExpression)GetVariableExpression(_nameVariable)).RawValue(),     // 3. module name
                    defaults.Count == 0 ?                                                           // 4. default values
                    AstUtils.Constant(null, typeof(object[])) :
                    (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults),
                    kwdefaults.Count == 0 ? AstUtils.Constant(null, typeof(PythonDictionary)) :
                    (MSAst.Expression)Ast.Call(                                                     // 5. kwdefaults
                        AstMethods.MakeDictFromItems,
                        Ast.NewArrayInit(
                            typeof(object),
                            kwdefaults
                            )
                        ),
                    annotations.Count == 0 ? AstUtils.Constant(null, typeof(PythonDictionary)) :
                    (MSAst.Expression)Ast.Call(                                                     // 6. annotations
                        AstMethods.MakeDictFromItems,
                        Ast.NewArrayInit(
                            typeof(object),
                            annotations
                            )
                        ),
                    IsGenerator ?
                    (MSAst.Expression) new PythonGeneratorExpression(code, GlobalParent.PyContext.Options.CompilationThreshold) :
                    (MSAst.Expression)code
                    );
            }
            else
            {
                ret = Ast.Call(
                    AstMethods.MakeFunction,                                                        // method
                    Parent.LocalContext,                                                            // 1. Emit CodeContext
                    FuncCodeExpr,                                                                   // 2. FunctionCode
                    ((IPythonGlobalExpression)GetVariableExpression(_nameVariable)).RawValue(),     // 3. module name
                    defaults.Count == 0 ?                                                           // 4. default values
                    AstUtils.Constant(null, typeof(object[])) :
                    (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults),
                    kwdefaults.Count == 0 ? AstUtils.Constant(null, typeof(PythonDictionary)) :
                    (MSAst.Expression)Ast.Call(                                                     // 5. kwdefaults
                        AstMethods.MakeDictFromItems,
                        Ast.NewArrayInit(
                            typeof(object),
                            kwdefaults
                            )
                        ),
                    annotations.Count == 0 ? AstUtils.Constant(null, typeof(PythonDictionary)) :
                    (MSAst.Expression)Ast.Call(                                                     // 6. annotations
                        AstMethods.MakeDictFromItems,
                        Ast.NewArrayInit(
                            typeof(object),
                            annotations
                            )
                        )
                    );
            }

            return(AddDecorators(ret, Decorators));
        }
Example #13
0
        internal static DynamicMetaObject Call(DynamicMetaObjectBinder /*!*/ call, DynamicMetaObject target, DynamicMetaObject /*!*/[] /*!*/ args)
        {
            Assert.NotNull(call, args);
            Assert.NotNullItems(args);

            if (target.NeedsDeferral())
            {
                return(call.Defer(ArrayUtils.Insert(target, args)));
            }

            foreach (DynamicMetaObject mo in args)
            {
                if (mo.NeedsDeferral())
                {
                    RestrictTypes(args);

                    return(call.Defer(
                               ArrayUtils.Insert(target, args)
                               ));
                }
            }

            DynamicMetaObject self = target.Restrict(target.GetLimitType());

            ValidationInfo valInfo   = BindingHelpers.GetValidationInfo(target);
            PythonType     pt        = DynamicHelpers.GetPythonType(target.Value);
            PythonContext  pyContext = PythonContext.GetPythonContext(call);

            // look for __call__, if it's present dispatch to it.  Otherwise fall back to the
            // default binder
            PythonTypeSlot callSlot;

            if (!typeof(Delegate).IsAssignableFrom(target.GetLimitType()) &&
                pt.TryResolveSlot(pyContext.SharedContext, "__call__", out callSlot))
            {
                ConditionalBuilder cb = new ConditionalBuilder(call);

                callSlot.MakeGetExpression(
                    pyContext.Binder,
                    PythonContext.GetCodeContext(call),
                    self,
                    GetPythonType(self),
                    cb
                    );

                if (!cb.IsFinal)
                {
                    cb.FinishCondition(GetCallError(call, self));
                }

                Expression[] callArgs = ArrayUtils.Insert(
                    PythonContext.GetCodeContext(call),
                    cb.GetMetaObject().Expression,
                    DynamicUtils.GetExpressions(args)
                    );

                Expression body = DynamicExpression.Dynamic(
                    PythonContext.GetPythonContext(call).Invoke(
                        BindingHelpers.GetCallSignature(call)
                        ),
                    typeof(object),
                    callArgs
                    );

                body = Ast.TryFinally(
                    Ast.Block(
                        Ast.Call(typeof(PythonOps).GetMethod(nameof(PythonOps.FunctionPushFrame)), Ast.Constant(pyContext)),
                        body
                        ),
                    Ast.Call(typeof(PythonOps).GetMethod(nameof(PythonOps.FunctionPopFrame)))
                    );

                return(BindingHelpers.AddDynamicTestAndDefer(
                           call,
                           new DynamicMetaObject(body, self.Restrictions.Merge(BindingRestrictions.Combine(args))),
                           args,
                           valInfo
                           ));
            }

            return(null);
        }
Example #14
0
        public override MSAst.Expression Reduce()
        {
            MSAst.Expression destination = _dest;

            if (_expressions.Length == 0)
            {
                MSAst.Expression result;
                if (destination != null)
                {
                    result = Ast.Call(
                        AstMethods.PrintNewlineWithDest,
                        Parent.LocalContext,
                        destination
                        );
                }
                else
                {
                    result = Ast.Call(
                        AstMethods.PrintNewline,
                        Parent.LocalContext
                        );
                }
                return(GlobalParent.AddDebugInfo(result, Span));
            }
            else
            {
                // Create list for the individual statements
                ReadOnlyCollectionBuilder <MSAst.Expression> statements = new ReadOnlyCollectionBuilder <MSAst.Expression>();

                // Store destination in a temp, if we have one
                MSAst.ParameterExpression temp = null;
                if (destination != null)
                {
                    temp = Ast.Variable(typeof(object), "destination");

                    statements.Add(MakeAssignment(temp, destination));

                    destination = temp;
                }
                for (int i = 0; i < _expressions.Length; i++)
                {
                    bool       withComma = (i < _expressions.Length - 1 || _trailingComma);// ? "PrintComma" : "Print";
                    Expression current   = _expressions[i];
                    MSAst.MethodCallExpression mce;

                    if (destination != null)
                    {
                        mce = Ast.Call(
                            withComma ? AstMethods.PrintCommaWithDest : AstMethods.PrintWithDest,
                            Parent.LocalContext,
                            destination,
                            AstUtils.Convert(current, typeof(object))
                            );
                    }
                    else
                    {
                        mce = Ast.Call(
                            withComma ? AstMethods.PrintComma : AstMethods.Print,
                            Parent.LocalContext,
                            AstUtils.Convert(current, typeof(object))
                            );
                    }

                    statements.Add(mce);
                }

                statements.Add(AstUtils.Empty());
                MSAst.Expression res;
                if (temp != null)
                {
                    res = Ast.Block(new[] { temp }, statements.ToReadOnlyCollection());
                }
                else
                {
                    res = Ast.Block(statements.ToReadOnlyCollection());
                }
                return(GlobalParent.AddDebugInfo(res, Span));
            }
        }
Example #15
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);
        }
        protected override Expression VisitTry(TryExpression node)
        {
            MSAst.Expression b = Visit(node.Body);
            ReadOnlyCollection <CatchBlock> h = Visit(node.Handlers, VisitCatchBlock);

            MSAst.Expression y = Visit(node.Finally);
            MSAst.Expression f;

            _insideConditionalBlock = true;
            try {
                f = Visit(node.Fault);
            } finally {
                _insideConditionalBlock = false;
            }

            node = Ast.MakeTry(node.Type, b, y, f, h);

            List <MSAst.CatchBlock> newHandlers = null;

            MSAst.Expression newFinally = null;

            // If the TryStatement has any Catch blocks we need to insert the exception
            // event as a first statement so that we can be notified of first-chance exceptions.
            if (node.Handlers != null && node.Handlers.Count > 0)
            {
                newHandlers = new List <CatchBlock>();

                foreach (var catchBlock in node.Handlers)
                {
                    ParameterExpression exceptionVar = catchBlock.Variable ?? Ast.Parameter(catchBlock.Test, null);

                    Expression debugMarker, thread;
                    if (_transformToGenerator)
                    {
                        debugMarker = Ast.Call(
                            typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.GetCurrentSequencePointForGeneratorFrame)),
                            _frame
                            );

                        thread = Ast.Call(typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.GetThread)), _frame);
                    }
                    else
                    {
                        debugMarker = _debugMarker;
                        thread      = _thread;
                    }

                    MSAst.Expression exceptionEvent = Ast.Block(
                        // Rethrow ForceToGeneratorLoopException
                        AstUtils.If(
                            Ast.TypeIs(
                                exceptionVar,
                                typeof(ForceToGeneratorLoopException)
                                ),
                            Ast.Throw(exceptionVar)
                            ),
                        AstUtils.If(
                            Ast.Equal(_globalDebugMode, AstUtils.Constant((int)DebugMode.FullyEnabled)),
                            _pushFrame ?? Ast.Empty(),
                            Ast.Call(
                                typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.OnTraceEvent)),
                                thread,
                                debugMarker,
                                exceptionVar
                                )
                            )
                        );

                    newHandlers.Add(Ast.MakeCatchBlock(
                                        catchBlock.Test,
                                        exceptionVar,
                                        Ast.Block(
                                            exceptionEvent,
                                            catchBlock.Body
                                            ),
                                        catchBlock.Filter
                                        ));
                }
            }

            if (!_transformToGenerator && node.Finally != null)
            {
                // Prevent the user finally block from running if the frame is currently remapping to generator
                newFinally = AstUtils.If(
                    Ast.Not(
                        Ast.Call(
                            typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.IsCurrentLeafFrameRemappingToGenerator)),
                            _thread
                            )
                        ),
                    node.Finally
                    );
            }

            if (newHandlers != null || newFinally != null)
            {
                node = Ast.MakeTry(
                    node.Type,
                    node.Body,
                    newFinally ?? node.Finally,
                    node.Fault,
                    newHandlers != null ? (IEnumerable <CatchBlock>)newHandlers : node.Handlers
                    );
            }

            return(node);
        }
        protected override MSAst.Expression VisitDebugInfo(MSAst.DebugInfoExpression node)
        {
            if (!node.IsClear)
            {
                MSAst.Expression transformedExpression;

                // Verify that DebugInfoExpression has valid SymbolDocumentInfo
                if (node.Document == null)
                {
                    throw new InvalidOperationException(
                              string.Format(
                                  CultureInfo.CurrentCulture,
                                  ErrorStrings.DebugInfoWithoutSymbolDocumentInfo,
                                  _locationCookie));
                }

                DebugSourceFile sourceFile = _debugContext.GetDebugSourceFile(
                    String.IsNullOrEmpty(node.Document.FileName) ? "<compile>" : node.Document.FileName);

                // Update the location cookie
                int locationCookie = _locationCookie++;
                if (!_transformToGenerator)
                {
                    MSAst.Expression tracebackCall = null;
                    if (locationCookie == 0)
                    {
                        tracebackCall = Ast.Empty();
                    }
                    else
                    {
                        tracebackCall = Ast.Call(
                            typeof(RuntimeOps).GetMethod(nameof(RuntimeOps.OnTraceEvent)),
                            _thread,
                            AstUtils.Constant(locationCookie),
                            Ast.Convert(Ast.Constant(null), typeof(Exception))
                            );
                    }

                    transformedExpression = Ast.Block(
                        Ast.Assign(
                            _debugMarker,
                            AstUtils.Constant(locationCookie)
                            ),
                        Ast.IfThen(
                            Ast.GreaterThan(
                                Ast.Property(_sourceFilesToVariablesMap[sourceFile], "Mode"),
                                Ast.Constant((int)DebugMode.ExceptionsOnly)
                                ),
                            Ast.IfThen(
                                Ast.OrElse(
                                    Ast.Equal(
                                        Ast.Property(_sourceFilesToVariablesMap[sourceFile], "Mode"),
                                        Ast.Constant((int)DebugMode.FullyEnabled)
                                        ),
                                    Ast.ArrayIndex(
                                        _traceLocations,
                                        AstUtils.Constant(locationCookie)
                                        )
                                    ),
                                Ast.Block(
                                    _pushFrame ?? Ast.Empty(),
                                    tracebackCall
                                    )
                                )
                            )
                        );
                }
                else
                {
                    Debug.Assert(_generatorLabelTarget != null);

                    transformedExpression = Ast.Block(
                        AstUtils.YieldReturn(
                            _generatorLabelTarget,
                            _debugYieldValue,
                            locationCookie
                            )
                        );

                    // Update the variable scope map
                    if (_currentLocals.Count > 0)
                    {
                        BlockExpression curentBlock = _currentLocals.Peek();
                        if (!_variableScopeMapCache.TryGetValue(curentBlock, out IList <VariableInfo> scopedVaribles))
                        {
                            scopedVaribles = new List <VariableInfo>();
                            BlockExpression[] blocks = _currentLocals.ToArray();
                            for (int i = blocks.Length - 1; i >= 0; i--)
                            {
                                foreach (var variable in blocks[i].Variables)
                                {
                                    scopedVaribles.Add(_localsToVarInfos[variable]);
                                }
                            }

                            _variableScopeMapCache.Add(curentBlock, scopedVaribles);
                        }

                        _variableScopeMap.Add(locationCookie, scopedVaribles);
                    }

                    DebugSourceSpan span = new DebugSourceSpan(
                        sourceFile,
                        node.StartLine,
                        node.StartColumn,
                        node.EndLine,
                        node.EndColumn);

                    // Update the location-span map
                    _markerLocationMap.Add(locationCookie, span);
                }

                return(transformedExpression);
            }

            return(Ast.Empty());
        }
        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));
        }
Example #19
0
        // if (site.Version == <context>.ConstantAccessVersion) {
        //   object value = site.Value;
        //   if (value.GetType() == typeof(WeakReference)) {
        //     if (value == ConstantSiteCache.Missing) {
        //       <result> = ConstantMissing(...);
        //     } else {
        //       <result> = ((WeakReference)value).Target;
        //     }
        //   } else {
        //     <result> = value;
        //   }
        // } else {
        //   <result> = GetConstant(...);
        // }
        private static MSA.Expression /*!*/ MakeCachedRead(AstGenerator /*!*/ gen, int opKind, bool isGlobal, bool isQualified,
                                                           MSA.Expression /*!*/ name)
        {
            object siteCache;

            MSA.ParameterExpression siteVar, valueVar;
            FieldInfo versionField, valueField;

            MSA.Expression readValue;
            MSA.Expression fallback;

            if (opKind == OpIsDefined)
            {
                siteCache = new IsDefinedConstantSiteCache();
                gen.CurrentScope.GetIsDefinedConstantSiteCacheVariables(out siteVar);
                versionField = Fields.IsDefinedConstantSiteCache_Version;
                valueField   = Fields.IsDefinedConstantSiteCache_Value;

                readValue = Ast.Field(siteVar, valueField);

                fallback = (isQualified) ?
                           Methods.IsDefinedQualifiedConstant.OpCall(gen.CurrentScopeVariable, siteVar, name, AstUtils.Constant(isGlobal)) :
                           (isGlobal ? Methods.IsDefinedGlobalConstant : Methods.IsDefinedUnqualifiedConstant).
                           OpCall(gen.CurrentScopeVariable, siteVar, name);
            }
            else
            {
                siteCache = (ConstantSiteCache) new ConstantSiteCache();
                gen.CurrentScope.GetConstantSiteCacheVariables(out siteVar, out valueVar);
                versionField = Fields.ConstantSiteCache_Version;
                valueField   = Fields.ConstantSiteCache_Value;

                MSA.Expression weakValue = Ast.Call(Ast.Convert(valueVar, typeof(WeakReference)), Methods.WeakReference_get_Target);
                if (!isQualified)
                {
                    weakValue = Ast.Condition(
                        // const missing:
                        Ast.Equal(valueVar, AstUtils.Constant(ConstantSiteCache.WeakMissingConstant)),
                        (isGlobal ? Methods.GetGlobalMissingConstant : Methods.GetMissingConstant).
                        OpCall(gen.CurrentScopeVariable, siteVar, name),

                        // weak value:
                        weakValue
                        );
                }

                readValue = Ast.Condition(
                    Ast.TypeEqual(Ast.Assign(valueVar, Ast.Field(siteVar, valueField)), typeof(WeakReference)),
                    weakValue,
                    valueVar
                    );

                fallback = (isQualified ? Methods.GetQualifiedConstant : Methods.GetUnqualifiedConstant).
                           OpCall(gen.CurrentScopeVariable, siteVar, name, AstUtils.Constant(isGlobal));
            }

            return(Ast.Block(
                       Ast.Condition(
                           Ast.Equal(
                               Ast.Field(Ast.Assign(siteVar, Ast.Constant(siteCache)), versionField),
                               Ast.Field(Ast.Constant(gen.Context), Fields.RubyContext_ConstantAccessVersion)
                               ),
                           readValue,
                           fallback
                           )
                       ));
        }
Example #20
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)
                        )
                    );
            }
        }
Example #21
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(Start, _header)
                    )
                );

            //******************************************************************
            // 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(Start, _header)
                    )
                );

            //******************************************************************
            // 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;
            MSAst.ParameterExpression nestedFrames = Ast.Variable(typeof(List <DynamicStackFrame>), "$nestedFrames");
            variables.Add(nestedFrames);
            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)
                                                ),
                                            Ast.Assign(
                                                nestedFrames,
                                                Ast.Call(AstMethods.GetAndClearDynamicStackFrames)
                                                ),
                                            //  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.Call(
                                                    AstMethods.SetDynamicStackFrames,
                                                    nestedFrames
                                                    ),
                                                Ast.Throw(
                                                    Ast.Call(
                                                        AstMethods.MakeRethrowExceptionWorker,
                                                        exception
                                                        )
                                                    )
                                                )
                                            ),
                                        _body.Span
                                        )
                                    ),
                                Ast.Call(
                                    AstMethods.SetDynamicStackFrames,
                                    nestedFrames
                                    ),
                                PopLineUpdated(lineUpdated),
                                Ast.Empty()
                                )
                    // finally:
                    ).Finally(
                    //  if exc:
                    //      exit(None, None, None)
                    AstUtils.IfThen(
                        exc,
                        GlobalParent.AddDebugInfoAndVoid(
                            Ast.Block(
                                Ast.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()));
        }
Example #22
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
                        )
                    );
            }
        }
Example #23
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(nameof(PythonOps.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(nameof(PythonOps.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(nameof(PythonOps.OldInstanceDictionaryGetValueHelper)),
                    tmp,
                    AstUtils.Constant(key),
                    AstUtils.Convert(Expression, typeof(object))
                    );
                break;

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

            case MemberAccess.Delete:
                target = Ast.Call(
                    typeof(PythonOps).GetMethod(nameof(PythonOps.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
                       ));
        }
Example #24
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(exception, 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()
                       ));
        }
Example #25
0
        internal DynamicMetaObject FallbackConvert(Type returnType, DynamicMetaObject self, DynamicMetaObject errorSuggestion)
        {
            Type type             = Type;
            DynamicMetaObject res = null;

            switch (Type.GetTypeCode(type))
            {
            case TypeCode.Boolean:
                res = MakeToBoolConversion(self);
                break;

            case TypeCode.Char:
                res = TryToCharConversion(self);
                break;

            case TypeCode.String:
                if (self.GetLimitType() == typeof(Bytes) && !_context.PythonOptions.Python30)
                {
                    res = new DynamicMetaObject(
                        Ast.Call(
                            typeof(PythonOps).GetMethod("MakeString"),
                            AstUtils.Convert(self.Expression, typeof(IList <byte>))
                            ),
                        BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, typeof(Bytes))
                        );
                }
                break;

            case TypeCode.Object:
                // !!! Deferral?
                if (type.IsArray && self.Value is PythonTuple && type.GetArrayRank() == 1)
                {
                    res = MakeToArrayConversion(self, type);
                }
                else if (type.IsGenericType && !type.IsAssignableFrom(CompilerHelpers.GetType(self.Value)))
                {
                    Type genTo = type.GetGenericTypeDefinition();

                    // Interface conversion helpers...
                    if (genTo == typeof(IList <>))
                    {
                        if (self.LimitType == typeof(string))
                        {
                            res = new DynamicMetaObject(
                                Ast.Call(
                                    typeof(PythonOps).GetMethod("MakeByteArray"),
                                    AstUtils.Convert(self.Expression, typeof(string))
                                    ),
                                BindingRestrictions.GetTypeRestriction(
                                    self.Expression,
                                    typeof(string)
                                    )
                                );
                        }
                        else
                        {
                            res = TryToGenericInterfaceConversion(self, type, typeof(IList <object>), typeof(ListGenericWrapper <>));
                        }
                    }
                    else if (genTo == typeof(IDictionary <,>))
                    {
                        res = TryToGenericInterfaceConversion(self, type, typeof(IDictionary <object, object>), typeof(DictionaryGenericWrapper <,>));
                    }
                    else if (genTo == typeof(IEnumerable <>))
                    {
                        res = TryToGenericInterfaceConversion(self, type, typeof(IEnumerable), typeof(IEnumerableOfTWrapper <>));
                    }
                }
                else if (type == typeof(IEnumerable))
                {
                    if (!typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) && IsIndexless(self))
                    {
                        res = ConvertToIEnumerable(this, self.Restrict(self.GetLimitType()));
                    }
                }
                else if (type == typeof(IEnumerator))
                {
                    if (!typeof(IEnumerator).IsAssignableFrom(self.GetLimitType()) &&
                        !typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) &&
                        IsIndexless(self))
                    {
                        res = ConvertToIEnumerator(this, self.Restrict(self.GetLimitType()));
                    }
                }
                break;
            }

            if (type.IsEnum && Enum.GetUnderlyingType(type) == self.GetLimitType())
            {
                // numeric type to enum, this is ok if the value is zero
                object value = Activator.CreateInstance(type);

                return(new DynamicMetaObject(
                           Ast.Condition(
                               Ast.Equal(
                                   AstUtils.Convert(self.Expression, Enum.GetUnderlyingType(type)),
                                   AstUtils.Constant(Activator.CreateInstance(self.GetLimitType()))
                                   ),
                               AstUtils.Constant(value),
                               Ast.Call(
                                   typeof(PythonOps).GetMethod("TypeErrorForBadEnumConversion").MakeGenericMethod(type),
                                   AstUtils.Convert(self.Expression, typeof(object))
                                   )
                               ),
                           self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, self.GetLimitType())),
                           value
                           ));
            }

            return(res ?? EnsureReturnType(returnType, Context.Binder.ConvertTo(Type, ResultKind, self, _context.SharedOverloadResolverFactory, errorSuggestion)));
        }
Example #26
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 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(lineUpdated, runElse),
                       AddFinally(result)
                       ));
        }
Example #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)
                                 ));
            }
        }
        private DynamicMetaObject /*!*/ MakeSetMember(SetMemberBinder /*!*/ member, DynamicMetaObject /*!*/ value)
        {
            PythonContext     state = PythonContext.GetPythonContext(member);
            DynamicMetaObject self  = Restrict(Value.GetType());

            if (Value.GetType() != typeof(PythonType) && DynamicHelpers.GetPythonType(Value).IsSystemType)
            {
                // built-in subclass of .NET type.  Usually __setattr__ is handled by MetaUserObject
                // but we can have a built-in subtype that's not a user type.
                PythonTypeSlot pts;
                if (Value.TryGetCustomSetAttr(state.SharedContext, out pts))
                {
                    Debug.Assert(pts.GetAlwaysSucceeds);

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

                    return(BindingHelpers.AddDynamicTestAndDefer(
                               member,
                               new DynamicMetaObject(
                                   Ast.Block(
                                       new[] { tmp },
                                       DynamicExpression.Dynamic(
                                           state.Invoke(new CallSignature(2)),
                                           typeof(object),
                                           AstUtils.Constant(state.SharedContext),
                                           Ast.Block(
                                               Ast.Call(
                                                   typeof(PythonOps).GetMethod(nameof(PythonOps.SlotTryGetValue)),
                                                   AstUtils.Constant(state.SharedContext),
                                                   AstUtils.Convert(AstUtils.WeakConstant(pts), typeof(PythonTypeSlot)),
                                                   AstUtils.Convert(Expression, typeof(object)),
                                                   AstUtils.Convert(AstUtils.WeakConstant(DynamicHelpers.GetPythonType(Value)), typeof(PythonType)),
                                                   tmp
                                                   ),
                                               tmp
                                               ),
                                           Ast.Constant(member.Name),
                                           value.Expression
                                           )
                                       ),
                                   self.Restrictions
                                   ),
                               new DynamicMetaObject[] { this, value },
                               TestUserType()
                               ));
                }
            }

            return(BindingHelpers.AddDynamicTestAndDefer(
                       member,
                       new DynamicMetaObject(
                           Ast.Call(
                               typeof(PythonOps).GetMethod(nameof(PythonOps.PythonTypeSetCustomMember)),
                               AstUtils.Constant(PythonContext.GetPythonContext(member).SharedContext),
                               self.Expression,
                               AstUtils.Constant(member.Name),
                               AstUtils.Convert(
                                   value.Expression,
                                   typeof(object)
                                   )
                               ),
                           self.Restrictions.Merge(value.Restrictions)
                           ),
                       new DynamicMetaObject[] { this, value },
                       TestUserType()
                       ));
        }
        private DynamicMetaObject /*!*/ MakeConvertRuleForCall(DynamicMetaObjectBinder /*!*/ convertToAction, Type toType, DynamicMetaObject /*!*/ self, string name, string returner, Func <DynamicMetaObject> fallback, Func <Expression, Expression> resultConverter)
        {
            PythonType     pt = ((IPythonObject)self.Value).PythonType;
            PythonTypeSlot pts;
            CodeContext    context = PythonContext.GetPythonContext(convertToAction).SharedContext;
            ValidationInfo valInfo = BindingHelpers.GetValidationInfo(this, pt);

            if (pt.TryResolveSlot(context, name, out pts) && !IsBuiltinConversion(context, pts, name, pt))
            {
                ParameterExpression tmp = Ast.Variable(typeof(object), "func");

                Expression callExpr = resultConverter(
                    Ast.Call(
                        PythonOps.GetConversionHelper(returner, GetResultKind(convertToAction)),
                        Ast.Dynamic(
                            PythonContext.GetPythonContext(convertToAction).InvokeNone,
                            typeof(object),
                            PythonContext.GetCodeContext(convertToAction),
                            tmp
                            )
                        )
                    );

                if (typeof(Extensible <>).MakeGenericType(toType).IsAssignableFrom(self.GetLimitType()))
                {
                    // if we're doing a conversion to the underlying type and we're an
                    // Extensible<T> of that type:

                    // if an extensible type returns it's self in a conversion, then we need
                    // to actually return the underlying value.  If an extensible just keeps
                    // returning more instances  of it's self a stack overflow occurs - both
                    // behaviors match CPython.
                    callExpr = AstUtils.Convert(AddExtensibleSelfCheck(convertToAction, toType, self, callExpr), typeof(object));
                }

                return(BindingHelpers.AddDynamicTestAndDefer(
                           convertToAction,
                           new DynamicMetaObject(
                               Ast.Condition(
                                   MakeTryGetTypeMember(
                                       PythonContext.GetPythonContext(convertToAction),
                                       pts,
                                       self.Expression,
                                       tmp
                                       ),
                                   callExpr,
                                   AstUtils.Convert(
                                       ConversionFallback(convertToAction),
                                       typeof(object)
                                       )
                                   ),
                               self.Restrict(self.GetRuntimeType()).Restrictions
                               ),
                           new DynamicMetaObject[] { this },
                           valInfo,
                           tmp
                           ));
            }

            return(fallback());
        }
Example #30
0
        private MSA.Expression /*!*/ TransformWrite(AstGenerator /*!*/ gen, AstExpressions /*!*/ rightValues, MSA.Expression splattedValue)
        {
            // We need to distinguish various special cases here.
            // Each of the bool variables defined below is true iff the corresponding special form of LHS/RHS occurs.
            // These flags drive the DLR AST being produced by this method.
            // For parallel assignment specification, see "Ruby Language.docx/Runtime/Parallel Assignment".

            // L(0,-) not applicable
            Debug.Assert(!(_leftValues.Count == 0 && _unsplattedValue == null));

            // L(1,-)?
            bool leftOneNone = _leftValues.Count == 1 && _unsplattedValue == null;

            // L(0,*)?
            bool leftNoneSplat = _leftValues.Count == 0 && _unsplattedValue != null;

            // R(0,*)?
            bool rightNoneSplat = rightValues.Count == 0 && splattedValue != null;

            // R(1,-)?
            bool rightOneNone = rightValues.Count == 1 && splattedValue == null;

            // R(1,*)?
            bool rightOneSplat = rightValues.Count == 1 && splattedValue != null;

            // R(0,-) not applicable
            Debug.Assert(!(rightValues.Count == 0 && splattedValue == null));

            MSA.Expression resultExpression;

            if (leftOneNone)
            {
                // L(1,-):

                // recurse right away (X) = RHS is equivalent to X = RHS:
                CompoundLeftValue compound = _leftValues[0] as CompoundLeftValue;
                if (compound != null)
                {
                    return(compound.TransformWrite(gen, rightValues, splattedValue));
                }

                if (rightOneSplat)
                {
                    // R(1,*)
                    resultExpression = Methods.SplatPair.OpCall(
                        AstUtils.Box(rightValues[0]),
                        AstUtils.LightDynamic(SplatAction.Make(gen.Context), typeof(IList), splattedValue)
                        );
                }
                else
                {
                    // case 1: R(1,-)
                    // case 2: R(0,*)
                    // case 3: otherwise
                    resultExpression = Arguments.TransformRead(gen, rightValues, splattedValue, true /* Splat */);
                }

                return(_leftValues[0].TransformWrite(gen, resultExpression));
            }

            bool optimizeReads = true;

            if (rightOneNone && !leftNoneSplat)
            {
                // R(1,-) && !L(0,*)
                resultExpression = Methods.Unsplat.OpCall(
                    AstUtils.LightDynamic(ConvertToArraySplatAction.Make(gen.Context), rightValues[0])
                    );
                optimizeReads = false;
            }
            else
            {
                // case 1: R(0,*) = L
                // case 2: otherwise
                resultExpression = Arguments.TransformRead(gen, rightValues, splattedValue, false /* Unsplat */);
                optimizeReads    = !rightNoneSplat;
            }

            var writes = new AstBlock();

            MSA.Expression result = gen.CurrentScope.DefineHiddenVariable("#rhs", typeof(IList));
            writes.Add(Ast.Assign(result, resultExpression));

            MethodInfo itemGetter = Methods.IList_get_Item;

            for (int i = 0; i < _leftValues.Count; i++)
            {
                MSA.Expression rvalue;

                if (optimizeReads)
                {
                    if (i < rightValues.Count)
                    {
                        // unchecked get item:
                        rvalue = Ast.Call(result, itemGetter, AstUtils.Constant(i));
                    }
                    else if (splattedValue != null)
                    {
                        // checked get item:
                        rvalue = Methods.GetArrayItem.OpCall(result, AstUtils.Constant(i));
                    }
                    else
                    {
                        // missing item:
                        rvalue = AstUtils.Constant(null);
                    }
                }
                else
                {
                    rvalue = Methods.GetArrayItem.OpCall(result, AstUtils.Constant(i));
                }

                writes.Add(_leftValues[i].TransformWrite(gen, rvalue));
            }

            // unsplatting the rest of rhs values into an array:
            if (_unsplattedValue != null)
            {
                // copies the rest of resulting array to the *LHS;
                // the resulting array contains splatted *RHS - no need for additional appending:
                MSA.Expression array = Methods.GetArraySuffix.OpCall(result, AstUtils.Constant(_leftValues.Count));

                // assign the array (possibly empty) to *LHS:
                writes.Add(_unsplattedValue.TransformWrite(gen, array));
            }

            writes.Add(result);
            return(writes);
        }