Esempio n. 1
0
        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;
        }
Esempio n. 2
0
        internal ScriptCode/*!*/ TransformToAst(CompilationMode mode, CompilerContext/*!*/ context) {
            // Create the ast generator
            // Use the PrintExpression value for the body (global level code)
            PythonCompilerOptions pco = context.Options as PythonCompilerOptions;
            Debug.Assert(pco != null);
            
            string name;
            if (!context.SourceUnit.HasPath || (pco.Module & ModuleOptions.ExecOrEvalCode) != 0) {
                name = "<module>";
            } else {
                name = context.SourceUnit.Path;
            }

            AstGenerator ag = new AstGenerator(mode, context, _body.Span, name, false, _printExpressions);

            
            MSAst.Expression body = Ast.Block(
                Ast.Call(
                    AstGenerator.GetHelperMethod("ModuleStarted"),
                    ag.LocalContext,
                    AstUtils.Constant(ag.BinderState, typeof(object)),
                    AstUtils.Constant(_languageFeatures)
                ),
                ag.UpdateLineNumber(0),
                ag.UpdateLineUpdated(false),
                ag.WrapScopeStatements(Transform(ag)),   // new ComboActionRewriter().VisitNode(Transform(ag))
                AstUtils.Empty()
            );
            if (_isModule) {
                string moduleName = pco.ModuleName;
                if (moduleName == null) {
#if !SILVERLIGHT
                    if (context.SourceUnit.HasPath && context.SourceUnit.Path.IndexOfAny(Path.GetInvalidFileNameChars()) == -1) {
                        moduleName = Path.GetFileNameWithoutExtension(context.SourceUnit.Path);
#else
                    if (context.SourceUnit.HasPath) {                    
                        moduleName = context.SourceUnit.Path;
#endif
                    } else {
                        moduleName = "<module>";
                    }
                }

                Debug.Assert(moduleName != null);

                body = Ast.Block(
                    ag.Globals.Assign(ag.Globals.GetVariable(ag, _fileVariable), Ast.Constant(name)),
                    ag.Globals.Assign(ag.Globals.GetVariable(ag, _nameVariable), Ast.Constant(moduleName)),
                    body // already typed to void
                );

                if ((pco.Module & ModuleOptions.Initialize) != 0) {
                    MSAst.Expression tmp = ag.HiddenVariable(typeof(object), "$originalModule");
                    // TODO: Should be try/fault
                    body = AstUtils.Try(
                        Ast.Assign(tmp, Ast.Call(AstGenerator.GetHelperMethod("PublishModule"), ag.LocalContext, Ast.Constant(moduleName))),
                        body
                    ).Catch(
                        typeof(Exception),
                        Ast.Call(AstGenerator.GetHelperMethod("RemoveModule"), ag.LocalContext, Ast.Constant(moduleName), tmp),
                        Ast.Rethrow(body.Type)
                    );
                }
            }

            body = ag.AddProfiling(body);
            body = ag.AddReturnTarget(body);

            if (body.Type == typeof(void)) {
                body = Ast.Block(body, Ast.Constant(null));
            }

            return ag.MakeScriptCode(body, context, this);
        }
Esempio n. 3
0
        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;
        }