예제 #1
0
        private MSAst.Expression ReduceWorker(bool optimizeDynamicConvert)
        {
            MSAst.Expression result;

            if (_tests.Length > 100)
            {
                // generate:
                // if(x) {
                //   body
                //   goto end
                // } else {
                // }
                // elseBody
                // end:
                //
                // to avoid deeply recursive trees which can stack overflow.
                BlockBuilder builder = new BlockBuilder();
                var          label   = Ast.Label();
                for (int i = 0; i < _tests.Length; i++)
                {
                    IfStatementTest ist = _tests[i];

                    builder.Add(
                        Ast.Condition(
                            optimizeDynamicConvert ?
                            TransformAndDynamicConvert(ist.Test, typeof(bool)) :
                            GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, ist.Test),
                            Ast.Block(
                                TransformMaybeSingleLineSuite(ist.Body, GlobalParent.IndexToLocation(ist.Test.StartIndex)),
                                Ast.Goto(label)
                                ),
                            Utils.Empty()
                            )
                        );
                }

                if (_else != null)
                {
                    builder.Add(_else);
                }

                builder.Add(Ast.Label(label));
                result = builder.ToExpression();
            }
            else
            {
                // Now build from the inside out
                if (_else != null)
                {
                    result = _else;
                }
                else
                {
                    result = AstUtils.Empty();
                }

                int i = _tests.Length;
                while (i-- > 0)
                {
                    IfStatementTest ist = _tests[i];

                    result = GlobalParent.AddDebugInfoAndVoid(
                        Ast.Condition(
                            optimizeDynamicConvert ?
                            TransformAndDynamicConvert(ist.Test, typeof(bool)) :
                            GlobalParent.Convert(typeof(bool), Microsoft.Scripting.Actions.ConversionResultKind.ExplicitCast, ist.Test),
                            TransformMaybeSingleLineSuite(ist.Body, GlobalParent.IndexToLocation(ist.Test.StartIndex)),
                            result
                            ),
                        new SourceSpan(GlobalParent.IndexToLocation(ist.StartIndex), GlobalParent.IndexToLocation(ist.HeaderIndex))
                        );
                }
            }

            return(result);
        }
예제 #2
0
        protected internal static Expression InlineCall(CodeBlock parent, CodeBlockExpression cbe, bool istailpostion, params Expression[] pp)
        {
            // all var names are unique.
            CodeBlock cb = cbe.Block;

            if (parent.IsGlobal)
            {
                return(CallNormal(cbe, pp));
            }

            List <Statement> assigns = new List <Statement>();
            int i = 0;

            cb.Inlined = true;

            if (parent.Filename == null && cb.Filename != null)
            {
                parent.Filename = cb.Filename;
            }

            var parentvars = new List <Variable>(parent.Variables);

            foreach (Variable p in cb.Parameters)
            {
                SymbolId origname = p.Name;

                p.Name  = (SymbolId)Builtins.GenSym(p.Name);
                p.Block = parent;
                p.Kind  = Variable.VariableKind.Local;
                parent.AddVariable(p);

                Expression val = Unwrap(pp[i]);
                if (val.Type != typeof(SymbolId) && !Generator.assigns.ContainsKey(origname))
                {
                    if (p.Type == typeof(object))
                    {
                        p.Type = val.Type;
                        assigns.Add(Ast.Write(p, val));
                    }
                    else
                    {
                        assigns.Add(Ast.Write(p, Ast.ConvertHelper(val, p.Type)));
                    }
                }
                else
                {
                    if (p.Type == typeof(object))
                    {
                        assigns.Add(Ast.Write(p, pp[i]));
                    }
                    else
                    {
                        assigns.Add(Ast.Write(p, Ast.ConvertHelper(pp[i], p.Type)));
                    }
                }

                if (p.Lift)
                {
                    parent.HasEnvironment = true;
                }
                i++;
            }

            foreach (Variable l in cb.Variables)
            {
                if (l.DefaultValue == null && l.Kind != Variable.VariableKind.Global)
                {
                    l.Name = (SymbolId)Builtins.GenSym(l.Name);
                }
                l.Block = parent;
                parent.AddVariable(l);

                if (l.Lift)
                {
                    parent.HasEnvironment = true;
                }
            }

            Expression body = RewriteReturn(cb.Body);

            if (assigns.Count > 0)
            {
                return(Ast.Comma(Ast.Void(Ast.Block(assigns)), body));
            }
            else
            {
                return(body);
            }
        }
예제 #3
0
        private MSAst.LambdaExpression CreateOuterLambda(Type lambdaType, MSAst.Expression debuggableBody)
        {
            List <MSAst.Expression> bodyExpressions    = new List <MSAst.Expression>();
            List <MSAst.Expression> tryExpressions     = new List <MSAst.Expression>();
            List <MSAst.Expression> finallyExpressions = new List <MSAst.Expression>();

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

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

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

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

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

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

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

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

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

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

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

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

            MSAst.ParameterExpression caughtException;

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

                                                Ast.Rethrow(),

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

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

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

            return(Ast.Lambda(
                       lambdaType,
                       Ast.Block(
                           _lambdaVars,
                           Ast.Label(returnLabelTarget, body)
                           ),
                       _alias,
                       _lambdaParams));
        }
예제 #4
0
                Statement Rewrite(Statement s)
                {
                    if (s is BlockStatement)
                    {
                        var stmts = ((BlockStatement)s).Statements;
                        List <Statement> newbody = new List <Statement>();

                        foreach (var stmt in stmts)
                        {
                            var nstmt = Rewrite(stmt);
                            if (nstmt != null)
                            {
                                if (nstmt is BlockStatement)
                                {
                                    newbody.AddRange(((BlockStatement)nstmt).Statements);
                                }
                                else
                                {
                                    newbody.Add(nstmt);
                                }
                            }
                        }
                        return(Ast.Block(newbody));
                    }

                    if (s is WriteStatement)
                    {
                        var ws = (WriteStatement)s;
                        if (!references.ContainsKey(ws.Variable))
                        {
                            if (ws.Value is MemberExpression)
                            {
                                var me = ws.Value as MemberExpression;
                                if (me.Member == Compiler.Generator.Unspecified && !ScriptDomainManager.Options.LightweightDebugging)
                                {
                                    return(null);
                                }
                            }
                            if (ws.Value is BoundExpression)
                            {
                                return(null);
                            }
                            return(Ast.Statement(ws.Value));
                        }
                    }

                    if (s is ExpressionStatement)
                    {
                        var es = (ExpressionStatement)s;
                        if (es.Expression is VoidExpression)
                        {
                            var ve = (VoidExpression)es.Expression;
                            return(ve.Statement);
                        }
                    }

                    if (s is IfStatement)
                    {
                        var ifs = (IfStatement)s;
                        if (ifs.ElseStatement == null)
                        {
                            return(Ast.If(ifs.Tests[0].Test, Rewrite(ifs.Tests[0].Body)).ToStatement());
                        }
                        else
                        {
                            return(Ast.If(ifs.Tests[0].Test, Rewrite(ifs.Tests[0].Body)).Else(Rewrite(ifs.ElseStatement)));
                        }
                    }

                    return(s);
                }
예제 #5
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));
            }
        }
예제 #6
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
                       ));
        }
예제 #7
0
 public static MSA.Expression /*!*/ Infinite(MSA.LabelTarget @break, MSA.LabelTarget @continue, params MSA.Expression[] /*!*/ body)
 {
     return(AstUtils.Infinite(Ast.Void(Ast.Block(body)), @break, @continue));
 }
예제 #8
0
        internal protected override Expression ToExpression(OverloadResolver resolver, RestrictedArguments args, bool[] hasBeenUsed)
        {
            var actualArgs     = resolver.GetActualArguments();
            int splatIndex     = actualArgs.SplatIndex;
            int collapsedCount = actualArgs.CollapsedCount;
            int firstSplatted  = actualArgs.FirstSplattedArg;

            var result        = new Expression[2 + _expandedCount + (collapsedCount > 0 ? 2 : 0)];
            var arrayVariable = resolver.GetTemporary(_elementType.MakeArrayType(), "a");
            int e             = 0;

            result[e++] = Ast.Assign(arrayVariable, Ast.NewArrayBounds(_elementType, Ast.Constant(_expandedCount + collapsedCount)));

            int itemIndex = 0;
            int i         = _start;

            while (true)
            {
                // inject loop copying collapsed items:
                if (i == splatIndex)
                {
                    var indexVariable = resolver.GetTemporary(typeof(int), "t");

                    // for (int t = 0; t <= {collapsedCount}; t++) {
                    //   a[{itemIndex} + t] = CONVERT<ElementType>(list.get_Item({splatIndex - firstSplatted} + t))
                    // }
                    result[e++] = Ast.Assign(indexVariable, AstUtils.Constant(0));
                    result[e++] = AstUtils.Loop(
                        Ast.LessThan(indexVariable, Ast.Constant(collapsedCount)),
                        // TODO: not implemented in the old interpreter
                        // Ast.PostIncrementAssign(indexVariable),
                        Ast.Assign(indexVariable, Ast.Add(indexVariable, AstUtils.Constant(1))),
                        Ast.Assign(
                            Ast.ArrayAccess(arrayVariable, Ast.Add(AstUtils.Constant(itemIndex), indexVariable)),
                            resolver.Convert(
                                new DynamicMetaObject(
                                    resolver.GetSplattedItemExpression(Ast.Add(AstUtils.Constant(splatIndex - firstSplatted), indexVariable)),
                                    BindingRestrictions.Empty
                                    ),
                                null,
                                ParameterInfo,
                                _elementType
                                )
                            ),
                        null
                        );

                    itemIndex += collapsedCount;
                }

                if (i >= _start + _expandedCount)
                {
                    break;
                }

                Debug.Assert(!hasBeenUsed[i]);
                hasBeenUsed[i] = true;

                result[e++] = Ast.Assign(
                    Ast.ArrayAccess(arrayVariable, AstUtils.Constant(itemIndex++)),
                    resolver.Convert(args.GetObject(i), args.GetType(i), ParameterInfo, _elementType)
                    );

                i++;
            }

            result[e++] = arrayVariable;

            Debug.Assert(e == result.Length);
            return(Ast.Block(result));
        }
예제 #9
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
                       ));
        }
예제 #10
0
        private DynamicMetaObject InvokeWorker(DynamicMetaObjectBinder /*!*/ callAction, DynamicMetaObject /*!*/[] args)
        {
            PerfTrack.NoteEvent(PerfTrack.Categories.Binding, "Method Invoke " + args.Length);
            PerfTrack.NoteEvent(PerfTrack.Categories.BindingTarget, "Method");

            CallSignature       signature    = BindingHelpers.GetCallSignature(callAction);
            DynamicMetaObject   self         = Restrict(typeof(Method));
            BindingRestrictions restrictions = self.Restrictions;

            DynamicMetaObject func = GetMetaFunction(self);
            DynamicMetaObject call;

            if (Value.im_self == null)
            {
                // restrict to null self (Method is immutable so this is an invariant test)
                restrictions = restrictions.Merge(
                    BindingRestrictions.GetExpressionRestriction(
                        Ast.Equal(
                            GetSelfExpression(self),
                            AstUtils.Constant(null)
                            )
                        )
                    );

                if (args.Length == 0)
                {
                    // this is an error, we pass null which will throw the normal error
                    call = new DynamicMetaObject(
                        Ast.Call(
                            typeof(PythonOps).GetMethod("MethodCheckSelf"),
                            PythonContext.GetCodeContext(callAction),
                            self.Expression,
                            AstUtils.Constant(null)
                            ),
                        restrictions
                        );
                }
                else
                {
                    // this may or may not be an error
                    call = new DynamicMetaObject(
                        Ast.Block(
                            MakeCheckSelf(callAction, signature, args),
                            Ast.Dynamic(
                                PythonContext.GetPythonContext(callAction).Invoke(
                                    BindingHelpers.GetCallSignature(callAction)
                                    ).GetLightExceptionBinder(callAction.SupportsLightThrow()),
                                typeof(object),
                                ArrayUtils.Insert(PythonContext.GetCodeContext(callAction), DynamicUtils.GetExpressions(ArrayUtils.Insert(func, args)))
                                )
                            ),
                        BindingRestrictions.Empty
                        );

                    /*call = func.Invoke(callAction, ArrayUtils.Insert(func, args));
                     * call =  new MetaObject(
                     *  Ast.Comma(
                     *      Ast.Call(
                     *          typeof(PythonOps).GetMethod("MethodCheckSelf"),
                     *          self.Expression,
                     *          args[0].Expression
                     *      ),
                     *      call.Expression
                     *  ),
                     *  call.Restrictions
                     * );*/
                }
            }
            else
            {
                // restrict to non-null self (Method is immutable so this is an invariant test)
                restrictions = restrictions.Merge(
                    BindingRestrictions.GetExpressionRestriction(
                        Ast.NotEqual(
                            GetSelfExpression(self),
                            AstUtils.Constant(null)
                            )
                        )
                    );

                DynamicMetaObject   im_self = GetMetaSelf(self);
                DynamicMetaObject[] newArgs = ArrayUtils.Insert(func, im_self, args);
                CallSignature       newSig  = new CallSignature(ArrayUtils.Insert(new Argument(ArgumentType.Simple), signature.GetArgumentInfos()));


                call = new DynamicMetaObject(
                    Ast.Dynamic(
                        PythonContext.GetPythonContext(callAction).Invoke(
                            newSig
                            ).GetLightExceptionBinder(callAction.SupportsLightThrow()),
                        typeof(object),
                        ArrayUtils.Insert(PythonContext.GetCodeContext(callAction), DynamicUtils.GetExpressions(newArgs))
                        ),
                    BindingRestrictions.Empty
                    );

                /*
                 * call = func.Invoke(
                 *  new CallBinder(
                 *      PythonContext.GetBinderState(callAction),
                 *      newSig
                 *  ),
                 *  newArgs
                 * );*/
            }

            if (call.HasValue)
            {
                return(new DynamicMetaObject(
                           call.Expression,
                           restrictions.Merge(call.Restrictions),
                           call.Value
                           ));
            }
            else
            {
                return(new DynamicMetaObject(
                           call.Expression,
                           restrictions.Merge(call.Restrictions)
                           ));
            }
        }
예제 #11
0
        private MSAst.Expression AddFinally(MSAst.Expression /*!*/ body)
        {
            if (Finally != null)
            {
                MSAst.ParameterExpression tryThrows    = Ast.Variable(typeof(Exception), "$tryThrows");
                MSAst.ParameterExpression locException = Ast.Variable(typeof(Exception), "$localException");

                MSAst.Expression? @finally = Finally;

                // lots is going on here.  We need to consider:
                //      1. Exceptions propagating out of try/except/finally.  Here we need to save the line #
                //          from the exception block and not save the # from the finally block later.
                //      2. Exceptions propagating out of the finally block.  Here we need to report the line number
                //          from the finally block and leave the existing stack traces cleared.
                //      3. Returning from the try block: Here we need to run the finally block and not update the
                //          line numbers.
                body = AstUtils.Try(
                    // we use a fault to know when we have an exception and when control leaves normally (via
                    // either a return or the body completing successfully).
                    AstUtils.Try(
                        Parent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, GlobalParent.IndexToLocation(HeaderIndex))),
                        Ast.Assign(tryThrows, AstUtils.Constant(null, typeof(Exception))),
                        body,
                        AstUtils.Empty()
                        ).Catch(
                        locException,
                        Expression.Block(
                            // If there was no except block, or the except block threw, then the
                            // exception has not yet been properly set, so we need to set the
                            // currently handled exception when we catch it
                            Ast.Call(AstMethods.SetCurrentException, Parent.LocalContext, locException),
                            Ast.Assign(tryThrows, locException),
                            Expression.Rethrow()
                            )
                        )
                    ).FinallyWithJumps(
                    // if we had an exception save the line # that was last executing during the try
                    AstUtils.If(
                        Expression.NotEqual(tryThrows, Expression.Default(typeof(Exception))),
                        Parent.GetSaveLineNumberExpression(tryThrows, false)
                        ),

                    // clear the frames incase thae finally throws, and allow line number
                    // updates to proceed
                    UpdateLineUpdated(false),

                    // run the finally code
                    // if the finally block reraises the same exception we have been handling,
                    // mark it as already updated
                    AstUtils.Try(
                        @finally
                        ).Catch(
                        locException,
                        AstUtils.If(
                            Expression.Equal(locException, tryThrows),
                            UpdateLineUpdated(true)
                            ),
                        Expression.Rethrow()
                        ),

                    // if we took an exception in the try block we have saved the line number.  Otherwise
                    // we have no line number saved and will need to continue saving them if
                    // other exceptions are thrown.
                    AstUtils.If(
                        Expression.NotEqual(tryThrows, Expression.Default(typeof(Exception))),
                        UpdateLineUpdated(true)
                        )
                    );
                body = Ast.Block(new[] { tryThrows }, body);
            }

            return(body);
        }
예제 #12
0
        private Microsoft.Scripting.Ast.LightExpression <Func <CodeContext, CodeContext> > MakeClassBody()
        {
            // we always need to create a nested context for class defs

            var init   = new List <MSAst.Expression>();
            var locals = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>();

            locals.Add(LocalCodeContextVariable);
            locals.Add(PythonAst._globalContext);

            init.Add(Ast.Assign(PythonAst._globalContext, new GetGlobalContextExpression(_parentContextParam)));

            GlobalParent.PrepareScope(locals, init);

            CreateVariables(locals, init);

            var createLocal = CreateLocalContext(_parentContextParam);

            init.Add(Ast.Assign(LocalCodeContextVariable, createLocal));

            List <MSAst.Expression> statements = new List <MSAst.Expression>();

            // Create the body
            MSAst.Expression bodyStmt = _body;

            // __module__ = __name__
            MSAst.Expression modStmt = AssignValue(GetVariableExpression(_modVariable), GetVariableExpression(_modNameVariable));

            string doc = GetDocumentation(_body);

            if (doc != null)
            {
                statements.Add(
                    AssignValue(
                        GetVariableExpression(_docVariable),
                        AstUtils.Constant(doc)
                        )
                    );
            }

            if (_body.CanThrow && GlobalParent.PyContext.PythonOptions.Frames)
            {
                bodyStmt = AddFrame(LocalContext, FuncCodeExpr, bodyStmt);
                locals.Add(FunctionStackVariable);
            }

            bodyStmt = WrapScopeStatements(
                Ast.Block(
                    Ast.Block(init),
                    statements.Count == 0 ?
                    EmptyBlock :
                    Ast.Block(new ReadOnlyCollection <MSAst.Expression>(statements)),
                    modStmt,
                    bodyStmt,
                    LocalContext
                    ),
                _body.CanThrow
                );

            var lambda = AstUtils.LightLambda <Func <CodeContext, CodeContext> >(
                typeof(CodeContext),
                Ast.Block(
                    locals,
                    bodyStmt
                    ),
                Name + "$" + Interlocked.Increment(ref _classId),
                new[] { _parentContextParam }
                );

            return(lambda);
        }
예제 #13
0
                static Statement Rewrite(Statement body)
                {
                    if (body is LabeledStatement)
                    {
                        var ls = (LabeledStatement)body;
                        return(ls.Mark(Rewrite(ls.Statement)));
                    }

                    if (body is BlockStatement)
                    {
                        var node    = body as BlockStatement;
                        var newbody = new List <Statement>();

                        foreach (var stmt in node.Statements)
                        {
                            var ns = Rewrite(stmt);
                            if (ns is BlockStatement)
                            {
                                newbody.AddRange(((BlockStatement)ns).Statements);
                            }
                            else
                            {
                                newbody.Add(ns);
                            }
                        }
                        return(Ast.Block(newbody));
                    }

                    if (body is WriteStatement)
                    {
                        var ws = (WriteStatement)body;

                        if (ws.Value is CommaExpression)
                        {
                            var ce    = ws.Value as CommaExpression;
                            var block = RewriteExpressions(ce.Expressions, x => Ast.Write(ws.Variable, x));
                            return(Rewrite(Ast.Block(block)));
                        }
                        else if (ws.Value == null)
                        {
                            var cb = ws.Variable.Block;
                            if (cb != null)
                            {
                                cb.RemoveVariables(new List <Variable>(new[] { ws.Variable }));
                                cb.Bind();
                            }
                            return(Ast.Empty());
                        }
                        else if (ws.Variable.Block == null)
                        {
                            //var cb = ws.Variable.Block;
                            //cb.RemoveVariables(new List<Variable>(new[] { ws.Variable }));
                            //cb.Bind();
                            return(Ast.Empty());
                        }
                        else if (ws.HasNoRef)
                        {
                            //var cb = ws.Variable.Block;
                            //cb.RemoveVariables(new List<Variable>(new[] { ws.Variable }));
                            //cb.Bind();
                            //return Ast.Empty();
                        }
                    }

                    if (body is ReturnStatement)
                    {
                        var rs = body as ReturnStatement;

                        if (rs.Expression is UnaryExpression && rs.Expression.NodeType == AstNodeType.Convert)
                        {
                            var ux = (UnaryExpression)rs.Expression;
                            var op = ux.Operand;

                            if (op is VoidExpression)
                            {
                                return(Rewrite(op as VoidExpression));
                            }
                            if (op is CommaExpression)
                            {
                                var ce = op as CommaExpression;

                                var block = RewriteExpressions(ce.Expressions,
                                                               x => Ast.Return(Ast.ConvertHelper(x, ux.Type)));

                                return(Rewrite(Ast.Block(block)));
                            }
                        }

                        if (rs.Expression is CommaExpression)
                        {
                            var ce = rs.Expression as CommaExpression;
                            var le = ce.Expressions[ce.Expressions.Count - 1];
                            if (le is VoidExpression && ((VoidExpression)le).Statement is ContinueStatement)
                            {
                                var block = RewriteExpressions(ce.Expressions, x => Ast.Continue());
                                return(Rewrite(Ast.Block(block)));
                            }
                            else
                            {
                                var block = RewriteExpressions(ce.Expressions, Ast.Return);
                                return(Rewrite(Ast.Block(block)));
                            }
                        }

                        if (rs.Expression is VoidExpression)
                        {
                            var ve = rs.Expression as VoidExpression;
                            return(Rewrite(ve));
                        }

                        if (rs.Expression is MethodCallExpression)
                        {
                            var mce = rs.Expression as MethodCallExpression;
                            var uce = Unwrap(mce.Instance);
                            if (uce is CommaExpression)
                            {
                                var ce    = uce as CommaExpression;
                                var block = RewriteExpressions(ce.Expressions,
                                                               x =>
                                {
                                    if (mce.Arguments.Count == 1 && mce.Arguments[0].Type == typeof(object[]))
                                    {
                                        var mc      = Ast.SimpleCallHelper(x, mce.Method, mce.Arguments.ToArray());
                                        mc.TailCall = mce.TailCall;
                                        return(Ast.Return(mc));
                                    }
                                    else
                                    {
                                        //var args = Array.ConvertAll(mce.Arguments.ToArray(), y => Ast.ConvertHelper(y, typeof(object)));
                                        var mc      = Ast.SimpleCallHelper(x, mce.Method, mce.Arguments.ToArray());
                                        mc.TailCall = mce.TailCall;
                                        return(Ast.Return(mc));
                                    }
                                });
                                return(Rewrite(Ast.Block(block)));
                            }
                        }
                    }

                    if (body is ExpressionStatement)
                    {
                        var es  = (ExpressionStatement)body;
                        var trs = TryRewriteExpression(es.Expression);
                        if (trs != null)
                        {
                            return(trs);
                        }
                    }

                    if (body is IfStatement)
                    {
                        var ifs = (IfStatement)body;
                        if (ifs.ElseStatement == null)
                        {
                            return(Ast.If(ifs.Tests[0].Test, Rewrite(ifs.Tests[0].Body)).ToStatement());
                        }
                        else
                        {
                            return(Ast.If(ifs.Tests[0].Test, Rewrite(ifs.Tests[0].Body)).Else(Rewrite(ifs.ElseStatement)));
                        }
                    }

                    return(body);
                }
예제 #14
0
        private void MakePropertyRule(SetOrDeleteMemberInfo memInfo, DynamicMetaObject instance, DynamicMetaObject target, Type targetType, MemberGroup properties)
        {
            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(
                        MakeError(
                            MakeStaticPropertyInstanceAccessError(
                                info,
                                true,
                                instance,
                                target
                                ),
                            typeof(object)
                            )
                        );
                }
                else if (info.IsStatic && info.DeclaringType != targetType)
                {
                    memInfo.Body.FinishCondition(
                        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(
                    MakeError(
                        MakeMissingMemberErrorForAssignReadOnlyProperty(targetType, instance, memInfo.Name), typeof(object)
                        )
                    );
            }
        }
예제 #15
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),
                        LightExceptions.RewriteExternal(
                            AstUtils.Try(
                                Parent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, GlobalParent.IndexToLocation(_headerIndex))),
                                body,
                                AstUtils.Constant(null)
                                ).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.Constant(null)
                                        )
                            ),
                        AstUtils.IfThen(runElse,
                                        @else
                                        ),
                        AstUtils.Empty()
                        );
            }
            else if (@catch != null)            // no "else" clause
            //  try {
            //      <try body>
            //  } catch (Exception e) {
            //      ... catch handling ...
            //  }
            //
            {
                result =
                    LightExceptions.RewriteExternal(
                        AstUtils.Try(
                            GlobalParent.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Span.Start, GlobalParent.IndexToLocation(_headerIndex))),
                            // save existing line updated
                            PushLineUpdated(false, lineUpdated),
                            body,
                            AstUtils.Constant(null)
                            ).Catch(exception,
                                    @catch,
                                    // restore existing line updated after exception handler completes
                                    PopLineUpdated(lineUpdated),
                                    Ast.Assign(exception, Ast.Constant(null, typeof(Exception))),
                                    AstUtils.Constant(null)
                                    )
                        );
            }
            else
            {
                result = body;
            }

            return(Ast.Block(
                       GetVariables(lineUpdated, runElse),
                       AddFinally(result),
                       AstUtils.Default(typeof(void))
                       ));
        }
예제 #16
0
 internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen)
 {
     return(Ast.Block(Transform(gen), AstUtils.Constant(null)));
 }
예제 #17
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))
                       ));
        }
예제 #18
0
        // arguments: complex arguments (expressions, maplets, splat, block)
        // singleArgument: siple argument (complex are not used)
        // assignmentRhsArgument: rhs of the assignment: target.method=(rhs)
        internal static MSA.Expression /*!*/ TransformRead(Expression /*!*/ node, AstGenerator /*!*/ gen, bool hasImplicitSelf,
                                                           string /*!*/ methodName, MSA.Expression /*!*/ transformedTarget,
                                                           Arguments arguments, Block block, MSA.Expression singleArgument, MSA.Expression assignmentRhsArgument)
        {
            Debug.Assert(assignmentRhsArgument == null || block == null, "Block not allowed in assignment");
            Debug.Assert(singleArgument == null || arguments == null && assignmentRhsArgument == null);
            Assert.NotNull(gen, transformedTarget);
            Assert.NotEmpty(methodName);

            // Pass args in this order:
            // 1. instance
            // 2. block (if present)
            // 3. passed args: normal args, maplets, array
            // 4. RHS of assignment (if present)

            MSA.Expression blockArgVariable;
            MSA.Expression transformedBlock;

            if (block != null)
            {
                blockArgVariable = gen.CurrentScope.DefineHiddenVariable("#block-def", typeof(Proc));
                transformedBlock = block.Transform(gen);
            }
            else
            {
                blockArgVariable = transformedBlock = null;
            }

            var siteBuilder = new CallSiteBuilder(gen, transformedTarget, blockArgVariable);

            if (arguments != null)
            {
                arguments.TransformToCall(gen, siteBuilder);
            }
            else if (singleArgument != null)
            {
                siteBuilder.Add(singleArgument);
            }

            MSA.Expression rhsVariable = null;
            if (assignmentRhsArgument != null)
            {
                rhsVariable             = gen.CurrentScope.DefineHiddenVariable("#rhs", assignmentRhsArgument.Type);
                siteBuilder.RhsArgument = Ast.Assign(rhsVariable, assignmentRhsArgument);
            }

            var dynamicSite = siteBuilder.MakeCallAction(methodName, hasImplicitSelf);

#if FEATURE_CALL_SITE_TRACER
            if (gen.Context.CallSiteCreated != null)
            {
                gen.Context.CallSiteCreated(node, dynamicSite);
            }
#endif

            MSA.Expression result = gen.DebugMark(dynamicSite, methodName);

            if (block != null)
            {
                result = gen.DebugMark(MakeCallWithBlockRetryable(gen, result, blockArgVariable, transformedBlock, block.IsDefinition),
                                       "#RB: method call with a block ('" + methodName + "')");
            }

            if (assignmentRhsArgument != null)
            {
                result = Ast.Block(result, rhsVariable);
            }

            return(result);
        }
예제 #19
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))
                       ));
        }
예제 #20
0
        /// <summary>
        /// Creates the LambdaExpression which implements the body of the function.
        ///
        /// The functions signature is either "object Function(PythonFunction, ...)"
        /// where there is one object parameter for each user defined parameter or
        /// object Function(PythonFunction, object[]) for functions which take more
        /// than PythonCallTargets.MaxArgs arguments.
        /// </summary>
        private LightLambdaExpression CreateFunctionLambda()
        {
            bool     needsWrapperMethod = _parameters.Length > PythonCallTargets.MaxArgs;
            Delegate originalDelegate;
            Type     delegateType = GetDelegateType(_parameters, needsWrapperMethod, out originalDelegate);

            MSAst.ParameterExpression localContext = null;
            ReadOnlyCollectionBuilder <MSAst.ParameterExpression> locals = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>();

            if (NeedsLocalsDictionary || ContainsNestedFreeVariables)
            {
                localContext = LocalCodeContextVariable;
                locals.Add(localContext);
            }

            MSAst.ParameterExpression[] parameters = CreateParameters(needsWrapperMethod, locals);

            List <MSAst.Expression> init = new List <MSAst.Expression>();

            foreach (var param in _parameters)
            {
                IPythonVariableExpression pyVar = GetVariableExpression(param.PythonVariable) as IPythonVariableExpression;
                if (pyVar != null)
                {
                    var varInit = pyVar.Create();
                    if (varInit != null)
                    {
                        init.Add(varInit);
                    }
                }
            }

            // Transform the parameters.
            init.Add(Ast.ClearDebugInfo(GlobalParent.Document));

            locals.Add(PythonAst._globalContext);
            init.Add(Ast.Assign(PythonAst._globalContext, new GetGlobalContextExpression(_parentContext)));

            GlobalParent.PrepareScope(locals, init);

            // Create variables and references. Since references refer to
            // parameters, do this after parameters have been created.

            CreateFunctionVariables(locals, init);

            // Initialize parameters - unpack tuples.
            // Since tuples unpack into locals, this must be done after locals have been created.
            InitializeParameters(init, needsWrapperMethod, parameters);

            List <MSAst.Expression> statements = new List <MSAst.Expression>();
            // add beginning sequence point
            var start = GlobalParent.IndexToLocation(StartIndex);

            statements.Add(GlobalParent.AddDebugInfo(
                               AstUtils.Empty(),
                               new SourceSpan(new SourceLocation(0, start.Line, start.Column), new SourceLocation(0, start.Line, Int32.MaxValue))));


            // For generators, we need to do a check before the first statement for Generator.Throw() / Generator.Close().
            // The exception traceback needs to come from the generator's method body, and so we must do the check and throw
            // from inside the generator.
            if (IsGenerator)
            {
                MSAst.Expression s1 = YieldExpression.CreateCheckThrowExpression(SourceSpan.None);
                statements.Add(s1);
            }

            MSAst.ParameterExpression extracted = null;
            if (!IsGenerator && _canSetSysExcInfo)
            {
                // need to allocate the exception here so we don't share w/ exceptions made & freed
                // during the body.
                extracted = Ast.Parameter(typeof(Exception), "$ex");
                locals.Add(extracted);
            }

            if (_body.CanThrow && !(_body is SuiteStatement) && _body.StartIndex != -1)
            {
                statements.Add(UpdateLineNumber(GlobalParent.IndexToLocation(_body.StartIndex).Line));
            }

            statements.Add(Body);
            MSAst.Expression body = Ast.Block(statements);

            // If this function can modify sys.exc_info() (_canSetSysExcInfo), then it must restore the result on finish.
            //
            // Wrap in
            //   $temp = PythonOps.SaveCurrentException()
            //   <body>
            //   PythonOps.RestoreCurrentException($temp)
            // Skip this if we're a generator. For generators, the try finally is handled by the PythonGenerator class
            //  before it's invoked. This is because the restoration must occur at every place the function returns from
            //  a yield point. That's different than the finally semantics in a generator.
            if (extracted != null)
            {
                MSAst.Expression s = AstUtils.Try(
                    Ast.Assign(
                        extracted,
                        Ast.Call(AstMethods.SaveCurrentException)
                        ),
                    body
                    ).Finally(
                    Ast.Call(
                        AstMethods.RestoreCurrentException, extracted
                        )
                    );
                body = s;
            }

            if (_body.CanThrow && GlobalParent.PyContext.PythonOptions.Frames)
            {
                body = AddFrame(LocalContext, Ast.Property(_functionParam, typeof(PythonFunction).GetProperty("__code__")), body);
                locals.Add(FunctionStackVariable);
            }

            body = AddProfiling(body);
            body = WrapScopeStatements(body, _body.CanThrow);
            body = Ast.Block(body, AstUtils.Empty());
            body = AddReturnTarget(body);


            MSAst.Expression bodyStmt = body;
            if (localContext != null)
            {
                var createLocal = CreateLocalContext(_parentContext);

                init.Add(
                    Ast.Assign(
                        localContext,
                        createLocal
                        )
                    );
            }

            init.Add(bodyStmt);

            bodyStmt = Ast.Block(init);

            // wrap a scope if needed
            bodyStmt = Ast.Block(locals.ToReadOnlyCollection(), bodyStmt);

            return(AstUtils.LightLambda(
                       typeof(object),
                       delegateType,
                       AddDefaultReturn(bodyStmt, typeof(object)),
                       Name + "$" + Interlocked.Increment(ref _lambdaId),
                       parameters
                       ));
        }
예제 #21
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);
                Expression         body;

                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)
                    );

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

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

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

            return(null);
        }
예제 #22
0
        internal static MSAst.Expression TransformFor(ScopeStatement parent, MSAst.ParameterExpression enumerator,
                                                      Expression list, Expression left, MSAst.Expression body,
                                                      Statement else_, SourceSpan span, SourceLocation header,
                                                      MSAst.LabelTarget breakLabel, MSAst.LabelTarget continueLabel, bool isStatement)
        {
            // enumerator, isDisposable = Dynamic(GetEnumeratorBinder, list)
            MSAst.Expression init = Ast.Assign(
                enumerator,
                new PythonDynamicExpression1 <KeyValuePair <IEnumerator, IDisposable> >(
                    Binders.UnaryOperationBinder(
                        parent.GlobalParent.PyContext,
                        PythonOperationKind.GetEnumeratorForIteration
                        ),
                    parent.GlobalParent.CompilationMode,
                    AstUtils.Convert(list, typeof(object))
                    )
                );

            // while enumerator.MoveNext():
            //    left = enumerator.Current
            //    body
            // else:
            //    else
            MSAst.Expression ls = AstUtils.Loop(
                parent.GlobalParent.AddDebugInfo(
                    Ast.Call(
                        Ast.Property(
                            enumerator,
                            typeof(KeyValuePair <IEnumerator, IDisposable>).GetProperty("Key")
                            ),
                        typeof(IEnumerator).GetMethod("MoveNext")
                        ),
                    left.Span
                    ),
                null,
                Ast.Block(
                    left.TransformSet(
                        SourceSpan.None,
                        Ast.Call(
                            Ast.Property(
                                enumerator,
                                typeof(KeyValuePair <IEnumerator, IDisposable>).GetProperty("Key")
                                ),
                            typeof(IEnumerator).GetProperty("Current").GetGetMethod()
                            ),
                        PythonOperationKind.None
                        ),
                    body,
                    isStatement ? UpdateLineNumber(parent.GlobalParent.IndexToLocation(list.StartIndex).Line) : AstUtils.Empty(),
                    AstUtils.Empty()
                    ),
                else_,
                breakLabel,
                continueLabel
                );

            return(Ast.Block(
                       init,
                       Ast.TryFinally(
                           ls,
                           Ast.Call(AstMethods.ForLoopDispose, enumerator)
                           )
                       ));
        }
예제 #23
0
        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("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("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()
                       ));
        }
예제 #24
0
        internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expression right, PythonOperationKind op)
        {
            // if we just have a simple named multi-assignment  (e.g. a, b = 1,2)
            // then go ahead and step over the entire statement at once.  If we have a
            // more complex statement (e.g. a.b, c.d = 1, 2) then we'll step over the
            // sets individually as they could be property sets the user wants to step
            // into.  TODO: Enable stepping of the right hand side?
            bool emitIndividualSets = false;

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

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

            SourceSpan totalSpan = SourceSpan.None;

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

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

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

            int expected    = _items.Length;
            int argcntafter = -1;

            for (var i = 0; i < _items.Length; i++)
            {
                var item = _items[i];
                if (item is StarredExpression)
                {
                    expected    = i;
                    argcntafter = _items.Length - i - 1;
                    break;
                }
            }

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

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

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

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

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

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

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

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

            // 10. Return the suite statement (block)
            return(GlobalParent.AddDebugInfo(Ast.Block(new[] { array_temp, right_temp }, assignStmt1, assignStmt2, itemSet, AstUtils.Empty()), totalSpan));
        }
예제 #25
0
        static Expression RewriteReturn(Statement statement)
        {
            if (statement is BlockStatement)
            {
                BlockStatement   bs      = (BlockStatement)statement;
                List <Statement> newbody = new List <Statement>(bs.Statements);
                Statement        last    = newbody[newbody.Count - 1];

                newbody.RemoveAt(newbody.Count - 1);

                Statement fb = FlattenStatement(Ast.Block(newbody));

                Expression eb = Ast.Void(fb);

                if (fb is ExpressionStatement)
                {
                    eb = ((ExpressionStatement)fb).Expression;
                }

                return(Ast.Comma(eb, Unwrap(RewriteReturn(last))));
            }

            if (statement is ReturnStatement)
            {
                Expression e = ((ReturnStatement)statement).Expression;
                if (e is MethodCallExpression)
                {
                    ((MethodCallExpression)e).TailCall = false;
                }
                if (e.Type != typeof(object))
                {
                    return(e);
                }
                else
                {
                    return(Unwrap(e));
                }
            }

            if (statement is IfStatement)
            {
                IfStatement ifs = (IfStatement)statement;

                Debug.Assert(ifs.Tests.Count == 1);
                var a = Unwrap(RewriteReturn(ifs.Tests[0].Body));
                var b = Unwrap(RewriteReturn(ifs.ElseStatement));
                if (a.Type != b.Type)
                {
                    a = Ast.ConvertHelper(a, typeof(object));
                    b = Ast.ConvertHelper(b, typeof(object));
                }
                return(Ast.Condition(ifs.Tests[0].Test, a, b));
            }

            if (statement is LabeledStatement)
            {
                var ls = statement as LabeledStatement;
                return(Ast.Void(ls));
            }

            throw new ArgumentException("Unexpected");
        }
예제 #26
0
        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
                       ));
        }
예제 #27
0
        internal MSA.Expression <T> /*!*/ Transform <T>(AstGenerator /*!*/ gen)
        {
            Debug.Assert(gen != null);

            ScopeBuilder scope = DefineLocals();

            MSA.ParameterExpression[] parameters;
            MSA.ParameterExpression   selfVariable;
            MSA.ParameterExpression   runtimeScopeVariable;
            MSA.ParameterExpression   blockParameter;

            if (gen.CompilerOptions.FactoryKind == TopScopeFactoryKind.None ||
                gen.CompilerOptions.FactoryKind == TopScopeFactoryKind.ModuleEval)
            {
                parameters = new MSA.ParameterExpression[4];

                runtimeScopeVariable = parameters[0] = Ast.Parameter(typeof(RubyScope), "#scope");
                selfVariable         = parameters[1] = Ast.Parameter(typeof(object), "#self");
                parameters[2]        = Ast.Parameter(typeof(RubyModule), "#module");
                blockParameter       = parameters[3] = Ast.Parameter(typeof(Proc), "#block");
            }
            else
            {
                parameters = new MSA.ParameterExpression[2];

                runtimeScopeVariable = parameters[0] = Ast.Parameter(typeof(RubyScope), "#scope");
                selfVariable         = parameters[1] = Ast.Parameter(typeof(object), "#self");

                blockParameter = null;
            }

            gen.EnterSourceUnit(
                scope,
                selfVariable,
                runtimeScopeVariable,
                blockParameter,
                gen.CompilerOptions.TopLevelMethodName, // method name for blocks
                null                                    // parameters for super calls
                );

            MSA.Expression body;

            if (_statements.Count > 0)
            {
                if (gen.PrintInteractiveResult)
                {
                    var resultVariable = scope.DefineHiddenVariable("#result", typeof(object));

                    var epilogue = Methods.PrintInteractiveResult.OpCall(runtimeScopeVariable,
                                                                         AstUtils.LightDynamic(ConvertToSAction.Make(gen.Context), typeof(MutableString),
                                                                                               CallSiteBuilder.InvokeMethod(gen.Context, "inspect", RubyCallSignature.WithScope(0),
                                                                                                                            gen.CurrentScopeVariable, resultVariable
                                                                                                                            )
                                                                                               )
                                                                         );

                    body = gen.TransformStatements(null, _statements, epilogue, ResultOperation.Store(resultVariable));
                }
                else
                {
                    body = gen.TransformStatements(_statements, ResultOperation.Return);
                }

                // TODO:
                var exceptionVariable = Ast.Parameter(typeof(Exception), "#exception");
                body = AstUtils.Try(
                    body
                    ).Filter(exceptionVariable, Methods.TraceTopLevelCodeFrame.OpCall(runtimeScopeVariable, exceptionVariable),
                             Ast.Empty()
                             );
            }
            else
            {
                body = AstUtils.Constant(null);
            }

            // scope initialization:
            MSA.Expression prologue;
            switch (gen.CompilerOptions.FactoryKind)
            {
            case TopScopeFactoryKind.None:
            case TopScopeFactoryKind.ModuleEval:
                prologue = Methods.InitializeScopeNoLocals.OpCall(runtimeScopeVariable, EnterInterpretedFrameExpression.Instance);
                break;

            case TopScopeFactoryKind.Hosted:
            case TopScopeFactoryKind.File:
            case TopScopeFactoryKind.WrappedFile:
                prologue = Methods.InitializeScope.OpCall(
                    runtimeScopeVariable, scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(),
                    EnterInterpretedFrameExpression.Instance
                    );
                break;

            case TopScopeFactoryKind.Main:
                prologue = Methods.InitializeScope.OpCall(
                    runtimeScopeVariable, scope.MakeLocalsStorage(), scope.GetVariableNamesExpression(),
                    EnterInterpretedFrameExpression.Instance
                    );
                if (_dataOffset >= 0)
                {
                    prologue = Ast.Block(
                        prologue,
                        Methods.SetDataConstant.OpCall(
                            runtimeScopeVariable,
                            gen.SourcePathConstant,
                            AstUtils.Constant(_dataOffset)
                            )
                        );
                }
                break;

            default:
                throw Assert.Unreachable;
            }

            // BEGIN blocks:
            if (gen.FileInitializers != null)
            {
                var b = new AstBlock();
                b.Add(prologue);
                b.Add(gen.FileInitializers);
                b.Add(body);
                body = b;
            }

            body = gen.AddReturnTarget(scope.CreateScope(body));

            gen.LeaveSourceUnit();

            return(Ast.Lambda <T>(body, GetEncodedName(gen), parameters));
        }
예제 #28
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 as Target:
                        //          <body>
                        //  into:
                        //      if ((converted = CheckException(exception, Test)) != null) {
                        //          try {
                        //              Target = converted;
                        //              traceback-header
                        //              <body>
                        //          }
                        //          finally {
                        //              del Target
                        //          }
                        //      }

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

                        ist = AstUtils.IfCondition(
                            Ast.NotEqual(
                                Ast.Assign(converted, test),
                                AstUtils.Constant(null)
                                ),
                            Ast.TryFinally(
                                Ast.Block(
                                    tsh.Target.TransformSet(SourceSpan.None, converted, PythonOperationKind.None),
                                    GlobalParent.AddDebugInfo(
                                        GetTracebackHeader(
                                            this,
                                            exception,
                                            tsh.Body
                                            ),
                                        new SourceSpan(GlobalParent.IndexToLocation(tsh.StartIndex), GlobalParent.IndexToLocation(tsh.HeaderIndex))
                                        ),
                                    AstUtils.Empty()
                                    ),
                                Ast.Block(
                                    tsh.Target.TransformSet(SourceSpan.None, AstUtils.Constant(null), PythonOperationKind.None),
                                    tsh.Target.TransformDelete()
                                    )
                                )
                            );
                    }
                    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(GlobalParent.IndexToLocation(tsh.StartIndex), GlobalParent.IndexToLocation(tsh.HeaderIndex))
                                )
                            );
                    }

                    // 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(GlobalParent.IndexToLocation(tsh.StartIndex), GlobalParent.IndexToLocation(tsh.HeaderIndex))
                        );
                }
            }

            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()
                       ));
        }
예제 #29
0
        internal MSAst.Expression ReduceWorker()
        {
            if (_body is ReturnStatement retStmt &&
                (_languageFeatures == ModuleOptions.None ||
                 _languageFeatures == (ModuleOptions.ExecOrEvalCode | ModuleOptions.Interpret) ||
                 _languageFeatures == (ModuleOptions.ExecOrEvalCode | ModuleOptions.Interpret | ModuleOptions.LightThrow)))
            {
                // for simple eval's we can construct a simple tree which just
                // leaves the value on the stack.  Return's can't exist in modules
                // so this is always safe.
                Debug.Assert(!IsModule);

                var ret = (ReturnStatement)_body;
                Ast simpleBody;
                if ((_languageFeatures & ModuleOptions.LightThrow) != 0)
                {
                    simpleBody = LightExceptions.Rewrite(retStmt.Expression.Reduce());
                }
                else
                {
                    simpleBody = retStmt.Expression.Reduce();
                }

                var start = IndexToLocation(ret.Expression.StartIndex);
                var end   = IndexToLocation(ret.Expression.EndIndex);

                return(Ast.Block(
                           Ast.DebugInfo(
                               _document,
                               start.Line,
                               start.Column,
                               end.Line,
                               end.Column
                               ),
                           AstUtils.Convert(simpleBody, typeof(object))
                           ));
            }

            ReadOnlyCollectionBuilder <MSAst.Expression> block = new ReadOnlyCollectionBuilder <MSAst.Expression>();

            AddInitialization(block);

            string doc = GetDocumentation(_body);

            if (doc != null || IsModule)
            {
                block.Add(AssignValue(GetVariableExpression(DocVariable), Ast.Constant(doc)));
            }

            if (!(_body is SuiteStatement) && _body.CanThrow)
            {
                // we only initialize line numbers in suite statements but if we don't generate a SuiteStatement
                // at the top level we can miss some line number updates.
                block.Add(UpdateLineNumber(_body.Start.Line));
            }

            block.Add(_body);

            MSAst.Expression body = Ast.Block(block.ToReadOnlyCollection());

            body = WrapScopeStatements(body, Body.CanThrow);   // new ComboActionRewriter().VisitNode(Transform(ag))

            body = AddModulePublishing(body);

            body = AddProfiling(body);

            if ((((PythonCompilerOptions)_compilerContext.Options).Module & ModuleOptions.LightThrow) != 0)
            {
                body = LightExceptions.Rewrite(body);
            }

            body = Ast.Label(FunctionDefinition._returnLabel, AstUtils.Convert(body, typeof(object)));
            if (body.Type == typeof(void))
            {
                body = Ast.Block(body, Ast.Constant(null));
            }

            return(body);
        }
        // see Ruby Language.doc/Runtime/Control Flow Implementation/While-Until
        internal override MSA.Expression /*!*/ TransformRead(AstGenerator /*!*/ gen)
        {
            MSA.Expression          resultVariable = gen.CurrentScope.DefineHiddenVariable("#loop-result", typeof(object));
            MSA.Expression          redoVariable   = gen.CurrentScope.DefineHiddenVariable("#skip-condition", typeof(bool));
            MSA.ParameterExpression unwinder;

            bool isInnerLoop = gen.CurrentLoop != null;

            MSA.LabelTarget breakLabel    = Ast.Label();
            MSA.LabelTarget continueLabel = Ast.Label();

            gen.EnterLoop(redoVariable, resultVariable, breakLabel, continueLabel);
            MSA.Expression transformedBody      = gen.TransformStatements(_statements, ResultOperation.Ignore);
            MSA.Expression transformedCondition = _condition.TransformCondition(gen, true);
            gen.LeaveLoop();

            MSA.Expression conditionPositiveStmt, conditionNegativeStmt;
            if (_isWhileLoop)
            {
                conditionPositiveStmt = AstUtils.Empty();
                conditionNegativeStmt = Ast.Break(breakLabel);
            }
            else
            {
                conditionPositiveStmt = Ast.Break(breakLabel);
                conditionNegativeStmt = AstUtils.Empty();
            }

            // make the loop first:
            MSA.Expression loop = new AstBlock {
                gen.ClearDebugInfo(),
                           Ast.Assign(redoVariable, AstUtils.Constant(_isPostTest)),

                AstFactory.Infinite(breakLabel, continueLabel,
                                    AstUtils.Try(

                                        AstUtils.If(redoVariable,
                                                    Ast.Assign(redoVariable, AstUtils.Constant(false))
                                                    ).ElseIf(transformedCondition,
                                                             conditionPositiveStmt
                                                             ).Else(
                                            conditionNegativeStmt
                                            ),

                                        transformedBody,
                                        AstUtils.Empty()

                                        ).Catch(unwinder = Ast.Parameter(typeof(BlockUnwinder), "#u"),
                                                // redo = u.IsRedo
                                                Ast.Assign(redoVariable, Ast.Field(unwinder, BlockUnwinder.IsRedoField)),
                                                AstUtils.Empty()

                                                ).Filter(unwinder = Ast.Parameter(typeof(EvalUnwinder), "#u"),
                                                         Ast.Equal(Ast.Field(unwinder, EvalUnwinder.ReasonField), AstFactory.BlockReturnReasonBreak),

                                                         // result = unwinder.ReturnValue
                                                         Ast.Assign(resultVariable, Ast.Field(unwinder, EvalUnwinder.ReturnValueField)),
                                                         Ast.Break(breakLabel)
                                                         )
                                    ),
                gen.ClearDebugInfo(),
                AstUtils.Empty(),
            };

            // wrap it to try finally that updates RFC state:
            if (!isInnerLoop)
            {
                loop = AstUtils.Try(
                    Methods.EnterLoop.OpCall(gen.CurrentScopeVariable),
                    loop
                    ).Finally(
                    Methods.LeaveLoop.OpCall(gen.CurrentScopeVariable)
                    );
            }

            return(Ast.Block(loop, resultVariable));
        }