상속: System.Dynamic.DynamicMetaObject, IRestrictedMetaObject
예제 #1
0
        /// <summary>
        /// Creating a Python type involves calling __new__ and __init__.  We resolve them
        /// and generate calls to either the builtin funcions directly or embed sites which
        /// call the slots at runtime.
        /// </summary>
        private DynamicMetaObject/*!*/ MakePythonTypeCall(DynamicMetaObjectBinder/*!*/ call, Expression/*!*/ codeContext, DynamicMetaObject/*!*/[]/*!*/ args) {
            ValidationInfo valInfo = MakeVersionCheck();

            DynamicMetaObject self = new RestrictedMetaObject(
                AstUtils.Convert(Expression, LimitType),
                BindingRestrictionsHelpers.GetRuntimeTypeRestriction(Expression, LimitType),
                Value
            );
            CallSignature sig = BindingHelpers.GetCallSignature(call);
            ArgumentValues ai = new ArgumentValues(sig, self, args);
            NewAdapter newAdapter;
            InitAdapter initAdapter;

            if (TooManyArgsForDefaultNew(call, args)) {
                return MakeIncorrectArgumentsForCallError(call, ai, valInfo);
            } else if (Value.UnderlyingSystemType.IsGenericTypeDefinition()) {
                return MakeGenericTypeDefinitionError(call, ai, valInfo);
            } else if (Value.HasAbstractMethods(PythonContext.GetPythonContext(call).SharedContext)) {
                return MakeAbstractInstantiationError(call, ai, valInfo);
            }

            DynamicMetaObject translated = BuiltinFunction.TranslateArguments(call, codeContext, self, args, false, Value.Name);
            if (translated != null) {
                return translated;
            }

            GetAdapters(ai, call, codeContext, out newAdapter, out initAdapter);
            PythonContext state = PythonContext.GetPythonContext(call);
            
            // get the expression for calling __new__
            DynamicMetaObject createExpr = newAdapter.GetExpression(state.Binder);
            if (createExpr.Expression.Type == typeof(void)) {
                return BindingHelpers.AddDynamicTestAndDefer(
                    call,
                    createExpr,
                    args,                        
                    valInfo
                );                    
            }

            Expression res;
            BindingRestrictions additionalRestrictions = BindingRestrictions.Empty;
            if (!Value.IsSystemType && (!(newAdapter is DefaultNewAdapter) || HasFinalizer(call))) {
                // we need to dynamically check the return value to see if it's a subtype of
                // the type that we are calling.  If it is then we need to call __init__/__del__
                // for the actual returned type.
                res = DynamicExpression.Dynamic(
                    Value.GetLateBoundInitBinder(sig),
                    typeof(object),
                    ArrayUtils.Insert(
                        codeContext,
                        Expression.Convert(createExpr.Expression, typeof(object)),
                        DynamicUtils.GetExpressions(args)
                    )
                );
                additionalRestrictions = createExpr.Restrictions;
            } else {
                // just call the __init__ method, built-in types currently have
                // no wacky return values which don't return the derived type.

                // then get the statement for calling __init__
                ParameterExpression allocatedInst = Ast.Variable(createExpr.GetLimitType(), "newInst");
                Expression tmpRead = allocatedInst;
                DynamicMetaObject initCall = initAdapter.MakeInitCall(
                    state.Binder,
                    new RestrictedMetaObject(
                        AstUtils.Convert(allocatedInst, Value.UnderlyingSystemType),
                        createExpr.Restrictions
                    )
                );

                List<Expression> body = new List<Expression>();
                Debug.Assert(!HasFinalizer(call));

                // add the call to init if we need to
                if (initCall.Expression != tmpRead) {
                    // init can fail but if __new__ returns a different type
                    // no exception is raised.
                    DynamicMetaObject initStmt = initCall;

                    if (body.Count == 0) {
                        body.Add(
                            Ast.Assign(allocatedInst, createExpr.Expression)
                        );
                    }

                    if (!Value.UnderlyingSystemType.IsAssignableFrom(createExpr.Expression.Type)) {
                        // return type of object, we need to check the return type before calling __init__.
                        body.Add(
                            AstUtils.IfThen(
                                Ast.TypeIs(allocatedInst, Value.UnderlyingSystemType),
                                initStmt.Expression
                            )
                        );
                    } else {
                        // just call the __init__ method, no type check necessary (TODO: need null check?)
                        body.Add(initStmt.Expression);
                    }
                }

                // and build the target from everything we have
                if (body.Count == 0) {
                    res = createExpr.Expression;
                } else {
                    body.Add(allocatedInst);
                    res = Ast.Block(body);
                }
                res = Ast.Block(new ParameterExpression[] { allocatedInst }, res);

                additionalRestrictions = initCall.Restrictions;
            }

            return BindingHelpers.AddDynamicTestAndDefer(
                call,
                new DynamicMetaObject(
                    res,
                    self.Restrictions.Merge(additionalRestrictions)
                ),
                ArrayUtils.Insert(this, args),
                valInfo
            );
        }
예제 #2
0
        /// <summary>
        /// Creating a Python type involves calling __new__ and __init__.  We resolve them
        /// and generate calls to either the builtin funcions directly or embed sites which
        /// call the slots at runtime.
        /// </summary>
        private DynamicMetaObject/*!*/ MakePythonTypeCall(DynamicMetaObjectBinder/*!*/ call, Expression/*!*/ codeContext, DynamicMetaObject/*!*/[]/*!*/ args) {
            ValidationInfo valInfo = MakeVersionCheck();

            DynamicMetaObject self = new RestrictedMetaObject(
                AstUtils.Convert(Expression, LimitType),
                BindingRestrictionsHelpers.GetRuntimeTypeRestriction(Expression, LimitType),
                Value
            );
            ArgumentValues ai = new ArgumentValues(BindingHelpers.GetCallSignature(call), self, args);
            NewAdapter newAdapter;
            InitAdapter initAdapter;

            if (TooManyArgsForDefaultNew(call, args)) {
                return MakeIncorrectArgumentsForCallError(call, ai, valInfo);
            }

            GetAdapters(ai, call, codeContext, out newAdapter, out initAdapter);
            BinderState state = BinderState.GetBinderState(call);
            
            // get the expression for calling __new__
            DynamicMetaObject createExpr = newAdapter.GetExpression(state.Binder);
            if (createExpr.Expression.Type == typeof(void)) {
                return BindingHelpers.AddDynamicTestAndDefer(
                    call,
                    createExpr,
                    args,                        
                    valInfo
                );                    
            }

            // then get the statement for calling __init__
            ParameterExpression allocatedInst = Ast.Variable(createExpr.GetLimitType(), "newInst");
            Expression tmpRead = allocatedInst;
            DynamicMetaObject initCall = initAdapter.MakeInitCall(
                state.Binder,
                new RestrictedMetaObject(
                    AstUtils.Convert(allocatedInst, Value.UnderlyingSystemType),
                    createExpr.Restrictions
                )
            );

            List<Expression> body = new List<Expression>();
            // then get the call to __del__ if we need one
            if (HasFinalizer(call)) {
                body.Add(
                    Ast.Assign(allocatedInst, createExpr.Expression)
                );
                body.Add(
                    GetFinalizerInitialization(call, allocatedInst)
                );
            }

            // add the call to init if we need to
            if (initCall.Expression != tmpRead) {
                // init can fail but if __new__ returns a different type
                // no exception is raised.
                DynamicMetaObject initStmt = initCall;

                if (body.Count == 0) {
                    body.Add(
                        Ast.Assign(allocatedInst, createExpr.Expression)
                    );
                }

                if (!Value.UnderlyingSystemType.IsAssignableFrom(createExpr.Expression.Type)) {
                    // return type of object, we need to check the return type before calling __init__.
                    body.Add(
                        AstUtils.IfThen(
                            Ast.TypeIs(allocatedInst, Value.UnderlyingSystemType),
                            initStmt.Expression
                        )
                    );
                } else {
                    // just call the __init__ method, no type check necessary (TODO: need null check?)
                    body.Add(initStmt.Expression);
                }
            }

            Expression res;
            // and build the target from everything we have
            if (body.Count == 0) {
                res = createExpr.Expression;
            } else {
                body.Add(allocatedInst);
                res = Ast.Block(body);
            }
            res = Ast.Block(new ParameterExpression[] { allocatedInst }, res);

            return BindingHelpers.AddDynamicTestAndDefer(
                call,
                new DynamicMetaObject(
                    res,
                    self.Restrictions.Merge(initCall.Restrictions)
                ),
                ArrayUtils.Insert(this, args),
                valInfo
            );
        }