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); }
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; }
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.LambdaExpression/*!*/ TransformToAst(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(context, _body.Span, name, false, _printExpressions); ag.Block.Global = true; ag.Block.Body = Ast.Block( Ast.Call( AstGenerator.GetHelperMethod("ModuleStarted"), AstUtils.CodeContext(), Ast.Constant(ag.BinderState, typeof(object)), Ast.Constant(_languageFeatures) ), ag.UpdateLineNumber(0), ag.UpdateLineUpdated(false), ag.WrapScopeStatements(Transform(ag)), // new ComboActionRewriter().VisitNode(Transform(ag)) Ast.Empty() ); if (_isModule) { Debug.Assert(pco.ModuleName != null); ag.Block.Body = Ast.Block( AstUtils.Assign(_fileVariable.Variable, Ast.Constant(name)), AstUtils.Assign(_nameVariable.Variable, Ast.Constant(pco.ModuleName)), ag.Block.Body // already typed to void ); if ((pco.Module & ModuleOptions.Initialize) != 0) { MSAst.Expression tmp = ag.Block.HiddenVariable(typeof(object), "$originalModule"); // TODO: Should be try/fault ag.Block.Body = AstUtils.Try( Ast.Assign(tmp, Ast.Call(AstGenerator.GetHelperMethod("PublishModule"), AstUtils.CodeContext(), Ast.Constant(pco.ModuleName))), ag.Block.Body ).Catch( typeof(Exception), Ast.Call(AstGenerator.GetHelperMethod("RemoveModule"), AstUtils.CodeContext(), Ast.Constant(pco.ModuleName), tmp), Ast.Rethrow(ag.Block.Body.Type) ); } } ag.Block.Body = ag.AddReturnTarget(ag.Block.Body); DisableInterpreter = ag.DisableInterpreter; return ag.Block.MakeLambda(); }
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; }