Exemple #1
0
        internal override MSAst.Expression Transform(AstGenerator ag) {
            string className = SymbolTable.IdToString(_name);
            AstGenerator builder = new AstGenerator(ag, className, false, "class " + className);

            // we always need to create a nested context for class defs
            builder.CreateNestedContext();

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

            // Create the body
            MSAst.Expression bodyStmt = builder.Transform(_body);
            MSAst.Expression modStmt = ag.Globals.Assign(ag.Globals.GetVariable(_modVariable), ag.Globals.GetVariable(_modNameVariable));

            string doc = ag.GetDocumentation(_body);
            if (doc != null) {
                init.Add(
                    ag.Globals.Assign(
                        ag.Globals.GetVariable(_docVariable),
                        AstUtils.Constant(doc)
                    )
                );
            }

            bodyStmt = builder.WrapScopeStatements(
                Ast.Block(
                    init.Count == 0 ?
                        AstGenerator.EmptyBlock :
                        Ast.Block(new ReadOnlyCollection<MSAst.Expression>(init)),
                    modStmt,
                    bodyStmt,
                    builder.LocalContext    // return value
                )
            );

            MSAst.LambdaExpression lambda = Ast.Lambda(
                typeof(Func<CodeContext>),
                builder.MakeBody(bodyStmt, true, false),
                builder.Name + "$" + _classId++,
                builder.Parameters
            );

            MSAst.Expression classDef = Ast.Call(
                AstGenerator.GetHelperMethod("MakeClass"),
                lambda,
                ag.LocalContext,
                AstUtils.Constant(SymbolTable.IdToString(_name)),
                Ast.NewArrayInit(
                    typeof(object),
                    ag.TransformAndConvert(_bases, typeof(object))
                ),
                AstUtils.Constant(FindSelfNames())
            );

            classDef = ag.AddDecorators(classDef, _decorators);

            return ag.AddDebugInfo(ag.Globals.Assign(ag.Globals.GetVariable(_variable), classDef), new SourceSpan(Start, Header));
        }
        internal override MSAst.Expression Transform(AstGenerator ag) {
            string className = _name;
            AstGenerator classGen = new AstGenerator(ag, className, false, "class " + className);
            classGen.Parameter(_parentContextParam);
            // we always need to create a nested context for class defs
            classGen.CreateNestedContext();

            List<MSAst.Expression> init = new List<MSAst.Expression>();
            
            classGen.AddHiddenVariable(ArrayGlobalAllocator._globalContext);
            init.Add(Ast.Assign(ArrayGlobalAllocator._globalContext, Ast.Call(typeof(PythonOps).GetMethod("GetGlobalContext"), _parentContextParam)));
            init.AddRange(classGen.Globals.PrepareScope(classGen));

            CreateVariables(classGen, _parentContextParam, init, true, false);

            List<MSAst.Expression> statements = new List<MSAst.Expression>();
            // Create the body
            MSAst.Expression bodyStmt = classGen.Transform(_body);
            
            // __module__ = __name__
            MSAst.Expression modStmt = GlobalAllocator.Assign(
                classGen.Globals.GetVariable(classGen, _modVariable), 
                classGen.Globals.GetVariable(classGen, _modNameVariable));

            string doc = classGen.GetDocumentation(_body);
            if (doc != null) {
                statements.Add(
                    GlobalAllocator.Assign(
                        classGen.Globals.GetVariable(classGen, _docVariable),
                        AstUtils.Constant(doc)
                    )
                );
            }

            FunctionCode funcCodeObj = new FunctionCode(
                ag.PyContext,
                null,
                null,
                Name,
                ag.GetDocumentation(_body),
                ArrayUtils.EmptyStrings,
                FunctionAttributes.None,
                Span,
                ag.Context.SourceUnit.Path,
                ag.EmitDebugSymbols,
                ag.ShouldInterpret,
                FreeVariables,
                GlobalVariables,
                CellVariables,
                AppendVariables(new List<string>()),
                Variables == null ? 0 : Variables.Count,
                classGen.LoopLocationsNoCreate,
                classGen.HandlerLocationsNoCreate
            );
            MSAst.Expression funcCode = classGen.Globals.GetConstant(funcCodeObj);
            classGen.FuncCodeExpr = funcCode;

            if (_body.CanThrow && ag.PyContext.PythonOptions.Frames) {
                bodyStmt = AstGenerator.AddFrame(classGen.LocalContext, funcCode, bodyStmt);
                classGen.AddHiddenVariable(AstGenerator._functionStack);
            }

            bodyStmt = classGen.WrapScopeStatements(
                Ast.Block(
                    statements.Count == 0 ?
                        AstGenerator.EmptyBlock :
                        Ast.Block(new ReadOnlyCollection<MSAst.Expression>(statements)),
                    modStmt,
                    bodyStmt,
                    classGen.LocalContext    // return value
                )
            );

            var lambda = Ast.Lambda<Func<CodeContext, CodeContext>>(
                classGen.MakeBody(_parentContextParam, init.ToArray(), bodyStmt),
                classGen.Name + "$" + _classId++,
                classGen.Parameters
            );
            
            funcCodeObj.Code = lambda;

            MSAst.Expression classDef = Ast.Call(
                AstGenerator.GetHelperMethod("MakeClass"),
                ag.EmitDebugSymbols ? 
                    (MSAst.Expression)lambda : 
                    Ast.Convert(funcCode, typeof(object)),
                ag.LocalContext,
                AstUtils.Constant(_name),
                Ast.NewArrayInit(
                    typeof(object),
                    ag.TransformAndConvert(_bases, typeof(object))
                ),
                AstUtils.Constant(FindSelfNames())
            );

            classDef = ag.AddDecorators(classDef, _decorators);

            return ag.AddDebugInfoAndVoid(GlobalAllocator.Assign(ag.Globals.GetVariable(ag, _variable), classDef), new SourceSpan(Start, Header));
        }
        internal MSAst.Expression TransformToFunctionExpression(AstGenerator ag) {
            string name;

            if (IsLambda) {
                name = "<lambda$" + Interlocked.Increment(ref _lambdaId) + ">";
            } else {
                name = SymbolTable.IdToString(_name);
            }

            // Create AST generator to generate the body with
            AstGenerator bodyGen = new AstGenerator(ag, name, IsGenerator, false);
            bodyGen.DisableInterpreter = true;

            // Transform the parameters.
            // Populate the list of the parameter names and defaults.
            List<MSAst.Expression> defaults = new List<MSAst.Expression>(0);
            List<MSAst.Expression> names = new List<MSAst.Expression>();
            TransformParameters(ag, bodyGen, defaults, names);

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

            // Create variables and references. Since references refer to
            // parameters, do this after parameters have been created.
            CreateVariables(bodyGen, statements);

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

            // 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(bodyGen, 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 = bodyGen.GetTemporary("$ex", typeof(Exception));
            }

            // Transform the body and add the resulting statements into the list
            TransformBody(bodyGen, statements);

            if (ag.DebugMode) {
                // add beginning and ending break points for the function.
                if (GetExpressionEnd(statements[statements.Count - 1]) != Body.End) {
                    statements.Add(ag.AddDebugInfo(Ast.Empty(), new SourceSpan(Body.End, Body.End)));
                }
            }

            MSAst.Expression body = Ast.Block(new ReadOnlyCollection<MSAst.Expression>(statements.ToArray()));

            // 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(
                            AstGenerator.GetHelperMethod("SaveCurrentException")
                        )
                    ),
                    body
                ).Finally(
                    Ast.Call(
                        AstGenerator.GetHelperMethod("RestoreCurrentException"), extracted
                    )
                );
                body = s;
            }

            body = bodyGen.WrapScopeStatements(body);
            bodyGen.Block.Body = bodyGen.AddReturnTarget(body);

            FunctionAttributes flags = ComputeFlags(_parameters);
            bool needsWrapperMethod = flags != FunctionAttributes.None;
            if (_canSetSysExcInfo) {
                flags |= FunctionAttributes.CanSetSysExcInfo;
            }

            MSAst.Expression code;
            if (IsGenerator) {
                code = bodyGen.Block.MakeGenerator(bodyGen.GeneratorLabel, GetGeneratorDelegateType(_parameters, needsWrapperMethod));
                flags |= FunctionAttributes.Generator;
            } else {
                code = bodyGen.Block.MakeLambda(GetDelegateType(_parameters, needsWrapperMethod));
            }

            MSAst.Expression ret = Ast.Call(
                null,                                                                                   // instance
                typeof(PythonOps).GetMethod("MakeFunction"),                                            // method
                new ReadOnlyCollection<MSAst.Expression>(
                    new [] {
                        AstUtils.CodeContext(),                                                         // 1. Emit CodeContext
                        Ast.Constant(name),                                                             // 2. FunctionName
                        code,                                                                           // 3. delegate
                        names.Count == 0 ?                                                              // 4. parameter names
                            Ast.Constant(null, typeof(string[])) :
                            (MSAst.Expression)Ast.NewArrayInit(typeof(string), names),
                        defaults.Count == 0 ?                                                           // 5. default values
                            Ast.Constant(null, typeof(object[])) :
                            (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults),                                   
                        Ast.Constant(flags),                                                            // 6. flags
                        Ast.Constant(ag.GetDocumentation(_body), typeof(string)),                       // 7. doc string or null
                        Ast.Constant(this.Start.Line),                                                  // 8. line number
                        Ast.Constant(_sourceUnit.Path, typeof(string))                                  // 9. filename
                    }
                )
            );

            ret = ag.AddDecorators(ret, _decorators);

            return ret;
        }
        internal MSAst.Expression TransformToFunctionExpression(AstGenerator ag) {
            string name;

            if (IsLambda) {
                name = "<lambda$" + Interlocked.Increment(ref _lambdaId) + ">";
            } else {
                name = SymbolTable.IdToString(_name);
            }

            // Create AST generator to generate the body with
            AstGenerator bodyGen = new AstGenerator(ag, name, IsGenerator, MakeProfilerName(name));
            FunctionAttributes flags = ComputeFlags(_parameters);
            bool needsWrapperMethod = flags != FunctionAttributes.None || _parameters.Length > PythonCallTargets.MaxArgs;
            
            // Transform the parameters.
            // Populate the list of the parameter names and defaults.
            List<MSAst.Expression> defaults = new List<MSAst.Expression>(0);
            List<MSAst.Expression> names = new List<MSAst.Expression>();

            List<MSAst.Expression> init = new List<MSAst.Expression>();
            TransformParameters(ag, bodyGen, defaults, names, needsWrapperMethod, init);

            MSAst.Expression parentContext;
            
            parentContext = MSAst.Expression.Call(typeof(PythonOps).GetMethod("GetParentContextFromFunction"), _functionParam);

            bodyGen.AddHiddenVariable(ArrayGlobalAllocator._globalContext);
            init.Add(Ast.Assign(ArrayGlobalAllocator._globalContext, Ast.Call(typeof(PythonOps).GetMethod("GetGlobalContext"), parentContext)));
            init.AddRange(bodyGen.Globals.PrepareScope(bodyGen));

            // Create variables and references. Since references refer to
            // parameters, do this after parameters have been created.
            CreateVariables(bodyGen, parentContext, init, NeedsLocalsDictionary, NeedsLocalsDictionary);

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

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

            // 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(bodyGen, SourceSpan.None);
                statements.Add(s1);
            }

            if (NeedsLocalsDictionary || ContainsNestedFreeVariables) {
                bodyGen.CreateNestedContext();
            }

            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 = bodyGen.GetTemporary("$ex", typeof(Exception));
            }

            // Transform the body and add the resulting statements into the list
            if (!TryTransformBody(bodyGen, statements)) {
                // there's an error in the body
                return null;
            }

            if (ag.DebugMode) {
                // add beginning and ending break points for the function.
                if (GetExpressionEnd(statements[statements.Count - 1]) != Body.End) {
                    statements.Add(ag.AddDebugInfo(AstUtils.Empty(), new SourceSpan(Body.End, Body.End)));
                }
            }

            MSAst.Expression body = Ast.Block(new ReadOnlyCollection<MSAst.Expression>(statements.ToArray()));

            // 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(
                            AstGenerator.GetHelperMethod("SaveCurrentException")
                        )
                    ),
                    body
                ).Finally(
                    Ast.Call(
                        AstGenerator.GetHelperMethod("RestoreCurrentException"), extracted
                    )
                );
                body = s;
            }

            body = bodyGen.AddProfiling(body);
            body = bodyGen.WrapScopeStatements(body);
            body = bodyGen.AddReturnTarget(body);

            if (_canSetSysExcInfo) {
                flags |= FunctionAttributes.CanSetSysExcInfo;
            }
            MSAst.Expression bodyStmt = bodyGen.MakeBody(
                parentContext, 
                init.ToArray(), 
                body, 
                true
            );

            if (ContainsTryFinally) {
                flags |= FunctionAttributes.ContainsTryFinally;
            }

            MSAst.LambdaExpression code;
            Delegate originalDelegate;
            if (IsGenerator) {
                code = Ast.Lambda(
                    GetDelegateType(_parameters, needsWrapperMethod, out originalDelegate),
                    new PythonGeneratorExpression(bodyGen.Name + "$" + _lambdaId++, bodyStmt, ag.ShouldInterpret, ag.EmitDebugSymbols, bodyGen.Parameters, bodyGen.GeneratorLabel),
                    bodyGen.Name + "$" + _lambdaId++,
                    bodyGen.Parameters
                );
                flags |= FunctionAttributes.Generator;
            } else {
                code = Ast.Lambda(
                    GetDelegateType(_parameters, needsWrapperMethod, out originalDelegate),
                    AstGenerator.AddDefaultReturn(bodyStmt, typeof(object)),
                    bodyGen.Name + "$" + _lambdaId++,
                    bodyGen.Parameters
                );
            }

            MSAst.Expression startingDelegate;
            if (ag.Globals is SavableGlobalAllocator || ag.EmitDebugSymbols) {
                startingDelegate = code;
            } else {
                startingDelegate = Ast.Constant(originalDelegate);
            }

            MSAst.Expression ret = Ast.Call(
                null,                                                                                   // instance
                typeof(PythonOps).GetMethod("MakeFunction"),                                            // method
                new ReadOnlyCollection<MSAst.Expression>(
                    new [] {
                        ag.LocalContext,                                                                // 1. Emit CodeContext
                        startingDelegate,                                                               // 2. initial callable delegate
                        Ast.Constant(                                                                   // 3. function info
                            new FunctionInfo(                                                               
                                name, 
                                ag.GetDocumentation(_body), 
                                ArrayUtils.ConvertAll<Parameter, string>(_parameters, (val) => SymbolTable.IdToString(val.Name)),
                                flags, 
                                Start.Line, 
                                _sourceUnit.Path,
                                code,
                                ag.ShouldInterpret
                            )
                        ),
                        ((IPythonGlobalExpression)ag.Globals.GetVariable(ag, _nameVariable)).RawValue(),
                        defaults.Count == 0 ?                                                           // 4. default values
                            AstUtils.Constant(null, typeof(object[])) :
                            (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults)
                    }
                )
            );

            ret = ag.AddDecorators(ret, _decorators);

            return ret;
        }
Exemple #5
0
        internal override MSAst.Expression Transform(AstGenerator ag) {
            string className = SymbolTable.IdToString(_name);
            AstGenerator classGen = new AstGenerator(ag, className, false, "class " + className);
            classGen.Parameter(_parentContextParam);
            // we always need to create a nested context for class defs
            classGen.CreateNestedContext();

            List<MSAst.Expression> init = new List<MSAst.Expression>();
            
            classGen.AddHiddenVariable(ArrayGlobalAllocator._globalContext);
            init.Add(Ast.Assign(ArrayGlobalAllocator._globalContext, Ast.Call(typeof(PythonOps).GetMethod("GetGlobalContext"), _parentContextParam)));
            init.AddRange(classGen.Globals.PrepareScope(classGen));

            CreateVariables(classGen, _parentContextParam, init, true, NeedsLocalsDictionary);

            List<MSAst.Expression> statements = new List<MSAst.Expression>();
            // Create the body
            MSAst.Expression bodyStmt = classGen.Transform(_body);
            
            // __module__ = __name__
            MSAst.Expression modStmt = classGen.Globals.Assign(
                classGen.Globals.GetVariable(classGen, _modVariable), 
                classGen.Globals.GetVariable(classGen, _modNameVariable));

            string doc = classGen.GetDocumentation(_body);
            if (doc != null) {
                statements.Add(
                    classGen.Globals.Assign(
                        classGen.Globals.GetVariable(classGen, _docVariable),
                        AstUtils.Constant(doc)
                    )
                );
            }

            bodyStmt = classGen.WrapScopeStatements(
                Ast.Block(
                    statements.Count == 0 ?
                        AstGenerator.EmptyBlock :
                        Ast.Block(new ReadOnlyCollection<MSAst.Expression>(statements)),
                    modStmt,
                    bodyStmt,
                    classGen.LocalContext    // return value
                )
            );

            var lambda = Ast.Lambda<Func<CodeContext, CodeContext>>(
                classGen.MakeBody(_parentContextParam, init.ToArray(), bodyStmt, false),
                classGen.Name + "$" + _classId++,
                classGen.Parameters
            );

            MSAst.Expression classDef = Ast.Call(
                AstGenerator.GetHelperMethod("MakeClass"),
                ag.EmitDebugSymbols ? 
                    (MSAst.Expression)lambda : 
                    (MSAst.Expression)Ast.Constant(new LazyCode<Func<CodeContext, CodeContext>>(lambda, ag.ShouldInterpret), typeof(object)),
                ag.LocalContext,
                AstUtils.Constant(SymbolTable.IdToString(_name)),
                Ast.NewArrayInit(
                    typeof(object),
                    ag.TransformAndConvert(_bases, typeof(object))
                ),
                AstUtils.Constant(FindSelfNames())
            );

            classDef = ag.AddDecorators(classDef, _decorators);

            return ag.AddDebugInfo(ag.Globals.Assign(ag.Globals.GetVariable(ag, _variable), classDef), new SourceSpan(Start, Header));
        }
Exemple #6
0
        internal override MSAst.Expression Transform(AstGenerator ag) {
            MSAst.Expression bases = Ast.NewArrayInit(
                typeof(object),
                ag.TransformAndConvert(_bases, typeof(object))
            );
            ag.DisableInterpreter = true;
            AstGenerator body = new AstGenerator(ag, SymbolTable.IdToString(_name), false, false);

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

            // Create the body
            MSAst.Expression bodyStmt = body.Transform(_body);
            MSAst.Expression modStmt = AstUtils.Assign(_modVariable.Variable, _modNameVariable.Variable);

            MSAst.Expression docStmt;
            string doc = ag.GetDocumentation(_body);
            if (doc != null) {
                docStmt =
                    AstUtils.Assign(
                        _docVariable.Variable,
                        Ast.Constant(doc)
                    );
            } else {
                docStmt = Ast.Empty();
            }

            MSAst.Expression returnStmt = Ast.Return(body.ReturnLabel, AstUtils.CodeContext());

            body.Block.Dictionary = true;
            body.Block.Visible = false;
            body.Block.Body = body.WrapScopeStatements(
                Ast.Block(
                    init.Count == 0 ? 
                        AstGenerator.EmptyBlock : 
                        Ast.Block(new ReadOnlyCollection<MSAst.Expression>(init)),
                    modStmt,
                    docStmt,
                    bodyStmt,
                    returnStmt,
                    Ast.Empty()
                )
            );
            body.Block.Body = body.AddReturnTarget(body.Block.Body);

            MSAst.LambdaExpression lambda = body.Block.MakeLambda(typeof(IronPython.Compiler.CallTarget0));
            MSAst.Expression classDef = Ast.Call(
                AstGenerator.GetHelperMethod("MakeClass"),
                AstUtils.CodeContext(),
                Ast.Constant(SymbolTable.IdToString(_name)),
                bases,
                Ast.Constant(FindSelfNames()),
                lambda
            );

            classDef = ag.AddDecorators(classDef, _decorators);

            return ag.AddDebugInfo(AstUtils.Assign(_variable.Variable, classDef), new SourceSpan(Start, Header));
        }
        internal MSAst.Expression TransformToFunctionExpression(AstGenerator ag) {
            string name;

            if (IsLambda) {
                name = "<lambda$" + Interlocked.Increment(ref _lambdaId) + ">";
            } else {
                name = _name;
            }

            if (ag.PyContext.PythonOptions.FullFrames) {
                // force a dictionary if we have enabled full frames for sys._getframe support
                NeedsLocalsDictionary = true;
            }

            // Create AST generator to generate the body with
            AstGenerator bodyGen = new AstGenerator(ag, name, IsGenerator, MakeProfilerName(name));

            FunctionAttributes flags = ComputeFlags(_parameters);
            bool needsWrapperMethod = _parameters.Length > PythonCallTargets.MaxArgs;
            
            // Transform the parameters.
            // Populate the list of the parameter names and defaults.
            List<MSAst.Expression> defaults = new List<MSAst.Expression>(0);
            List<MSAst.Expression> names = new List<MSAst.Expression>();

            List<MSAst.Expression> init = new List<MSAst.Expression>();
            init.Add(Ast.ClearDebugInfo(ag.Document));

            TransformParameters(ag, bodyGen, defaults, names, needsWrapperMethod, init);

            MSAst.Expression parentContext;

            parentContext = MSAst.Expression.Call(_GetParentContextFromFunction, _functionParam);

            bodyGen.AddHiddenVariable(ArrayGlobalAllocator._globalContext);
            init.Add(Ast.Assign(ArrayGlobalAllocator._globalContext, Ast.Call(_GetGlobalContext, parentContext)));
            init.AddRange(bodyGen.Globals.PrepareScope(bodyGen));

            // Create variables and references. Since references refer to
            // parameters, do this after parameters have been created.
            CreateVariables(bodyGen, parentContext, init, NeedsLocalsDictionary, NeedsLocalsDictionary);

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

            List<MSAst.Expression> statements = new List<MSAst.Expression>();
            // add beginning sequence point
            statements.Add(bodyGen.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(bodyGen, SourceSpan.None);
                statements.Add(s1);
            }

            if (NeedsLocalsDictionary || ContainsNestedFreeVariables) {
                bodyGen.CreateNestedContext();
            }

            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 = bodyGen.GetTemporary("$ex", typeof(Exception));
            }

            // Transform the body and add the resulting statements into the list
            if (!TryTransformBody(bodyGen, statements)) {
                // there's an error in the body
                return null;
            }

            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(
                            AstGenerator.GetHelperMethod("SaveCurrentException")
                        )
                    ),
                    body
                ).Finally(
                    Ast.Call(
                        AstGenerator.GetHelperMethod("RestoreCurrentException"), extracted
                    )
                );
                body = s;
            }

            if (_body.CanThrow && ag.PyContext.PythonOptions.Frames) {
                body = AstGenerator.AddFrame(bodyGen.LocalContext, Ast.Property(_functionParam, typeof(PythonFunction).GetProperty("__code__")), body);
                bodyGen.AddHiddenVariable(AstGenerator._functionStack);
            }

            body = bodyGen.AddProfiling(body);
            body = bodyGen.WrapScopeStatements(body);
            body = bodyGen.AddReturnTarget(body);

            if (_canSetSysExcInfo) {
                flags |= FunctionAttributes.CanSetSysExcInfo;
            }

            if (ContainsTryFinally) {
                flags |= FunctionAttributes.ContainsTryFinally;
            }

            if (IsGenerator) {
                flags |= FunctionAttributes.Generator;
            }

            MSAst.Expression bodyStmt = bodyGen.MakeBody(
                parentContext, 
                init.ToArray(), 
                body
            );

            Delegate originalDelegate;
            MSAst.LambdaExpression code = Ast.Lambda(
                GetDelegateType(_parameters, needsWrapperMethod, out originalDelegate),
                AstGenerator.AddDefaultReturn(bodyStmt, typeof(object)),
                bodyGen.Name + "$" + _lambdaId++,
                bodyGen.Parameters
            );

            // create the function code object which all function instances will share
            MSAst.Expression funcCode = ag.Globals.GetConstant(
                new FunctionCode(
                    ag.PyContext,
                    EmitDebugFunction(ag) ? null : originalDelegate,
                    code,
                    name,
                    ag.GetDocumentation(_body),
                    ArrayUtils.ConvertAll(_parameters, (val) => val.Name),
                    flags,
                    Span,
                    _sourceUnit.Path,
                    ag.EmitDebugSymbols,
                    ag.ShouldInterpret,
                    FreeVariables,
                    GlobalVariables,
                    CellVariables,
                    GetVarNames(),
                    Variables == null ? 0 : Variables.Count,
                    bodyGen.LoopLocationsNoCreate,
                    bodyGen.HandlerLocationsNoCreate
                )                
            );
            bodyGen.FuncCodeExpr = funcCode;

            MSAst.Expression ret;
            if (EmitDebugFunction(ag)) {
                // we need to compile all of the debuggable code together at once otherwise mdbg gets confused.  If we're
                // in tracing mode we'll still compile things one off though just to keep things simple.  The code will still
                // be debuggable but naive debuggers like mdbg will have more issues.
                ret = Ast.Call(
                    _MakeFunctionDebug,                                                             // method
                    ag.LocalContext,                                                                // 1. Emit CodeContext
                    funcCode,                                                                       // 2. FunctionCode
                    ((IPythonGlobalExpression)ag.Globals.GetVariable(ag, _nameVariable)).RawValue(),// 3. module name
                    defaults.Count == 0 ?                                                           // 4. default values
                        AstUtils.Constant(null, typeof(object[])) :
                        (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults),
                    IsGenerator ? 
                        (MSAst.Expression)new PythonGeneratorExpression(code) :
                        (MSAst.Expression)code
                );
            } else {
                ret = Ast.Call(
                    _MakeFunction,                                                                  // method
                    ag.LocalContext,                                                                // 1. Emit CodeContext
                    funcCode,                                                                       // 2. FunctionCode
                    ((IPythonGlobalExpression)ag.Globals.GetVariable(ag, _nameVariable)).RawValue(),// 3. module name
                    defaults.Count == 0 ?                                                           // 4. default values
                        AstUtils.Constant(null, typeof(object[])) :
                        (MSAst.Expression)Ast.NewArrayInit(typeof(object), defaults)
                );
            }

            ret = ag.AddDecorators(ret, _decorators);

            return ret;
        }