예제 #1
0
        internal MSA.Expression /*!*/ TransformOptionalsInitialization(AstGenerator /*!*/ gen)
        {
            Assert.NotNull(gen);

            if (_optional.Length == 0)
            {
                return(AstUtils.Empty());
            }

            MSA.Expression singleton = gen.CurrentScope.DefineHiddenVariable("#default", typeof(object));

            MSA.Expression result = AstUtils.Empty();
            for (int i = 0; i < _optional.Length; i++)
            {
                result = AstUtils.IfThen(
                    Ast.Equal(_optional[i].Left.TransformRead(gen), singleton),
                    Ast.Block(
                        result,
                        _optional[i].TransformRead(gen) // assignment
                        )
                    );
            }

            return(Ast.Block(
                       Ast.Assign(singleton, Ast.Field(null, Fields.DefaultArgument)),
                       result,
                       AstUtils.Empty()
                       ));
        }
예제 #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
                );
            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 = Expression.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
                       ));
        }
예제 #3
0
        internal MSA.Expression /*!*/ Transform(AstGenerator /*!*/ gen, bool isLambda)
        {
            ScopeBuilder scope = DefineLocals(gen.CurrentScope);

            // define hidden parameters and RHS-placeholders (#1..#n will be used as RHS of a parallel assignment):
            MSA.ParameterExpression blockParameter, selfParameter;
            var parameters = DefineParameters(out selfParameter, out blockParameter);

            MSA.ParameterExpression scopeVariable = scope.DefineHiddenVariable("#scope", typeof(RubyBlockScope));
            MSA.LabelTarget         redoLabel     = Ast.Label();

            gen.EnterBlockDefinition(
                scope,
                blockParameter,
                selfParameter,
                scopeVariable,
                redoLabel
                );

            MSA.Expression          paramInit = MakeParametersInitialization(gen, parameters);
            MSA.ParameterExpression blockUnwinder, filterVariable;

            MSA.Expression traceCall, traceReturn;
            if (gen.TraceEnabled)
            {
                int firstStatementLine = _body.Count > 0 ? _body.First.Location.Start.Line : Location.End.Line;
                int lastStatementLine  = _body.Count > 0 ? _body.Last.Location.End.Line : Location.End.Line;

                traceCall   = Methods.TraceBlockCall.OpCall(scopeVariable, blockParameter, gen.SourcePathConstant, AstUtils.Constant(firstStatementLine));
                traceReturn = Methods.TraceBlockReturn.OpCall(scopeVariable, blockParameter, gen.SourcePathConstant, AstUtils.Constant(lastStatementLine));
            }
            else
            {
                traceCall = traceReturn = Ast.Empty();
            }

            MSA.Expression body = AstUtils.Try(
                paramInit,
                traceCall,
                Ast.Label(redoLabel),
                AstUtils.Try(
                    gen.TransformStatements(_body, ResultOperation.Return)
                    ).Catch(blockUnwinder = Ast.Parameter(typeof(BlockUnwinder), "#u"),
                            // redo:
                            AstUtils.IfThen(Ast.Field(blockUnwinder, BlockUnwinder.IsRedoField), Ast.Goto(redoLabel)),

                            // next:
                            gen.Return(Ast.Field(blockUnwinder, BlockUnwinder.ReturnValueField))
                            )
                ).Filter(filterVariable = Ast.Parameter(typeof(Exception), "#e"),
                         Methods.FilterBlockException.OpCall(scopeVariable, filterVariable)
                         ).Finally(
                traceReturn,
                Ast.Empty()
                );

            body = gen.AddReturnTarget(
                scope.CreateScope(
                    scopeVariable,
                    Methods.CreateBlockScope.OpCall(new AstExpressions {
                scope.MakeLocalsStorage(),
                scope.GetVariableNamesExpression(),
                blockParameter,
                selfParameter,
                EnterInterpretedFrameExpression.Instance
            }),
                    body
                    )
                );

            gen.LeaveBlockDefinition();

            int parameterCount = ParameterCount;
            var attributes = _parameters.GetBlockSignatureAttributes();

            var dispatcher = Ast.Constant(
                BlockDispatcher.Create(parameterCount, attributes, gen.SourcePath, Location.Start.Line), typeof(BlockDispatcher)
                );

            return(Ast.Coalesce(
                       (isLambda ? Methods.InstantiateLambda : Methods.InstantiateBlock).OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable, dispatcher),
                       (isLambda ? Methods.DefineLambda : Methods.DefineBlock).OpCall(gen.CurrentScopeVariable, gen.CurrentSelfVariable, dispatcher,
                                                                                      BlockDispatcher.CreateLambda(
                                                                                          body,
                                                                                          RubyStackTraceBuilder.EncodeMethodName(gen.CurrentMethod.MethodName, gen.SourcePath, Location, gen.DebugMode),
                                                                                          parameters,
                                                                                          parameterCount,
                                                                                          attributes
                                                                                          )
                                                                                      )
                       ));
        }