public override System.Linq.Expressions.Expression[] PrepareScope(AstGenerator gen) { gen.AddHiddenVariable(GlobalArray); return new MSAst.Expression[] { Ast.Assign( GlobalArray, Ast.Call( typeof(PythonOps).GetMethod("GetGlobalArrayFromContext"), ArrayGlobalAllocator._globalContext ) ) }; }
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)); }
public override MSAst.Expression[] PrepareScope(AstGenerator/*!*/ gen) { gen.AddHiddenVariable(_globalArray); return new MSAst.Expression[] { Ast.Assign(_globalArray, _array) }; }
// This is a compound comparison operator like: a < b < c. // That's represented as binary operators, but it's not the same as (a<b) < c, so we do special transformations. // We need to: // - return true iff (a<b) && (b<c), but ensure that b is only evaluated once. // - ensure evaluation order is correct (a,b,c) // - don't evaluate c if a<b is false. private MSAst.Expression FinishCompare(MSAst.Expression left, AstGenerator ag) { Debug.Assert(_right is BinaryExpression); BinaryExpression bright = (BinaryExpression)_right; // Transform the left child of my right child (the next node in sequence) MSAst.Expression rleft = ag.Transform(bright.Left); // Store it in the temp MSAst.ParameterExpression temp = ag.GetTemporary("chained_comparison"); // Create binary operation: left <_op> (temp = rleft) MSAst.Expression comparison = MakeBinaryOperation( ag, _op, left, Ast.Assign(temp, AstUtils.Convert(rleft, temp.Type)), typeof(object), Span ); MSAst.Expression rright; // Transform rright, comparing to temp if (IsComparison(bright._right)) { rright = bright.FinishCompare(temp, ag); } else { MSAst.Expression transformedRight = ag.Transform(bright.Right); rright = MakeBinaryOperation( ag, bright.Operator, temp, transformedRight, typeof(object), bright.Span ); } ag.FreeTemp(temp); // return (left (op) (temp = rleft)) and (rright) MSAst.ParameterExpression tmp; MSAst.Expression res = AstUtils.CoalesceTrue( comparison, rright, AstGenerator.GetHelperMethod("IsTrue"), out tmp ); ag.AddHiddenVariable(tmp); return res; }
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) { 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)); }
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; }