private Expression ParseLambdaHelperEnd(FunctionDefinition func, Expression expr) { // Pep 342 in Python 2.5 allows Yield Expressions, which can occur inside a Lambda body. // In this case, the lambda is a generator and will yield it's final result instead of just return it. Statement body; if (func.IsGenerator) { YieldExpression y = new YieldExpression(expr); y.SetLoc(_globalParent, expr.IndexSpan); body = new ExpressionStatement(y); } else { body = new ReturnStatement(expr); } body.SetLoc(_globalParent, expr.StartIndex, expr.EndIndex); FunctionDefinition func2 = PopFunction(); System.Diagnostics.Debug.Assert(func == func2); func.Body = body; func.EndIndex = GetEnd(); LambdaExpression ret = new LambdaExpression(func); func.SetLoc(_globalParent, func.IndexSpan); ret.SetLoc(_globalParent, func.IndexSpan); return ret; }
/// <summary> /// Peek if the next token is a 'yield' and parse a yield expression. Else return null. /// /// Called w/ yield already eaten. /// </summary> /// <returns>A yield expression if present, else null. </returns> // yield_expression: "yield" [expression_list] private Expression ParseYieldExpression() { // Mark that this function is actually a generator. // If we're in a generator expression, then we don't have a function yet. // g=((yield i) for i in range(5)) // In that acse, the genexp will mark IsGenerator. FunctionDefinition current = CurrentFunction; if (current != null) { current.IsGenerator = true; } var start = GetStart(); // Parse expression list after yield. This can be: // 1) empty, in which case it becomes 'yield None' // 2) a single expression // 3) multiple expression, in which case it's wrapped in a tuple. Expression yieldResult; bool trailingComma; List<Expression> l = ParseExpressionList(out trailingComma); if (l.Count == 0) { // Check empty expression and convert to 'none' yieldResult = new ConstantExpression(null); } else if (l.Count != 1) { // make a tuple yieldResult = MakeTupleOrExpr(l, trailingComma); } else { // just take the single expression yieldResult = l[0]; } Expression yieldExpression = new YieldExpression(yieldResult); yieldExpression.SetLoc(_globalParent, start, GetEnd()); return yieldExpression; }
public override bool Walk(YieldExpression node) { Yield = node; return false; }
internal Yield(YieldExpression expr) : this() { // expr.Expression is never null _value = Convert(expr.Expression); }
public override void PostWalk(YieldExpression node) { }
public override bool Walk(YieldExpression node) { sink.Add(src, "YIELD statement is not supported.", node.Span, UNSUPPORTED_STATEMENT, Severity.FatalError); return false; }
/// <summary> /// Peek if the next token is a 'yield' and parse a yield expression. Else return null. /// /// Called w/ yield already eaten. /// </summary> /// <returns>A yield expression if present, else null. </returns> // yield_expression: "yield" [expression_list] private Expression ParseYieldExpression() { // Mark that this function is actually a generator. // If we're in a generator expression, then we don't have a function yet. // g=((yield i) for i in range(5)) // In that acse, the genexp will mark IsGenerator. FunctionDefinition current = CurrentFunction; if (current != null) { current.IsGenerator = true; } SourceLocation start = GetStart(); // Parse expression list after yield. This can be: // 1) empty, in which case it becomes 'yield None' // 2) a single expression // 3) multiple expression, in which case it's wrapped in a tuple. const bool allowEmptyExpr = true; Expression yieldResult = ParseTestListAsExpr(allowEmptyExpr); // Check empty expression and convert to 'none' TupleExpression t = yieldResult as TupleExpression; if (t != null) { if (t.Items.Length == 0) { yieldResult = new ConstantExpression(null); } } Expression yieldExpression = new YieldExpression(yieldResult); yieldExpression.SetLoc(start, GetEnd()); return yieldExpression; }
// YieldExpression public override bool Walk(YieldExpression node) { node.Parent = _currentScope; return(base.Walk(node)); }
/// <summary> /// Creates the LambdaExpression which implements the body of the function. /// /// The functions signature is either "object Function(PythonFunction, ...)" /// where there is one object parameter for each user defined parameter or /// object Function(PythonFunction, object[]) for functions which take more /// than PythonCallTargets.MaxArgs arguments. /// </summary> private LightLambdaExpression CreateFunctionLambda() { bool needsWrapperMethod = _parameters.Length > PythonCallTargets.MaxArgs; Delegate originalDelegate; Type delegateType = GetDelegateType(_parameters, needsWrapperMethod, out originalDelegate); MSAst.ParameterExpression localContext = null; ReadOnlyCollectionBuilder <MSAst.ParameterExpression> locals = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>(); if (NeedsLocalContext) { localContext = LocalCodeContextVariable; locals.Add(localContext); } MSAst.ParameterExpression[] parameters = CreateParameters(needsWrapperMethod, locals); List <MSAst.Expression> init = new List <MSAst.Expression>(); foreach (var param in _parameters) { IPythonVariableExpression pyVar = GetVariableExpression(param.PythonVariable) as IPythonVariableExpression; if (pyVar != null) { var varInit = pyVar.Create(); if (varInit != null) { init.Add(varInit); } } } // Transform the parameters. init.Add(Ast.ClearDebugInfo(GlobalParent.Document)); locals.Add(PythonAst._globalContext); init.Add(Ast.Assign(PythonAst._globalContext, new GetGlobalContextExpression(_parentContext))); GlobalParent.PrepareScope(locals, init); // Create variables and references. Since references refer to // parameters, do this after parameters have been created. CreateFunctionVariables(locals, init); // If the __class__ variable is used the a class method then we need to initialize it. // This must be done before parameter initialization (in case one of the parameters is called __class__). ClassDefinition parent = FindParentOfType <ClassDefinition>(); PythonVariable pVar; if (parent != null && TryGetVariable("__class__", out pVar)) { init.Add( AssignValue( GetVariableExpression(pVar), Ast.Call(AstMethods.LookupName, parent.Parent.LocalContext, Ast.Constant(parent.Name)) ) ); } // Initialize parameters - unpack tuples. // Since tuples unpack into locals, this must be done after locals have been created. InitializeParameters(init, needsWrapperMethod, parameters); List <MSAst.Expression> statements = new List <MSAst.Expression>(); // add beginning sequence point var start = GlobalParent.IndexToLocation(StartIndex); statements.Add(GlobalParent.AddDebugInfo( AstUtils.Empty(), new SourceSpan(new SourceLocation(0, start.Line, start.Column), new SourceLocation(0, start.Line, Int32.MaxValue)))); // For generators, we need to do a check before the first statement for Generator.Throw() / Generator.Close(). // The exception traceback needs to come from the generator's method body, and so we must do the check and throw // from inside the generator. if (IsGenerator) { MSAst.Expression s1 = YieldExpression.CreateCheckThrowExpression(SourceSpan.None); statements.Add(s1); } MSAst.ParameterExpression extracted = null; if (!IsGenerator && _canSetSysExcInfo) { // need to allocate the exception here so we don't share w/ exceptions made & freed // during the body. extracted = Ast.Parameter(typeof(Exception), "$ex"); locals.Add(extracted); } if (_body.CanThrow && !(_body is SuiteStatement) && _body.StartIndex != -1) { statements.Add(UpdateLineNumber(GlobalParent.IndexToLocation(_body.StartIndex).Line)); } statements.Add(Body); MSAst.Expression body = Ast.Block(statements); // If this function can modify sys.exc_info() (_canSetSysExcInfo), then it must restore the result on finish. // // Wrap in // $temp = PythonOps.SaveCurrentException() // <body> // PythonOps.RestoreCurrentException($temp) // Skip this if we're a generator. For generators, the try finally is handled by the PythonGenerator class // before it's invoked. This is because the restoration must occur at every place the function returns from // a yield point. That's different than the finally semantics in a generator. if (extracted != null) { MSAst.Expression s = AstUtils.Try( Ast.Assign( extracted, Ast.Call(AstMethods.SaveCurrentException) ), body ).Finally( Ast.Call( AstMethods.RestoreCurrentException, extracted ) ); body = s; } if (_body.CanThrow && GlobalParent.PyContext.PythonOptions.Frames) { body = AddFrame(LocalContext, Ast.Property(_functionParam, typeof(PythonFunction).GetProperty("__code__")), body); locals.Add(FunctionStackVariable); } body = AddProfiling(body); body = WrapScopeStatements(body, _body.CanThrow); body = Ast.Block(body, AstUtils.Empty()); body = AddReturnTarget(body); MSAst.Expression bodyStmt = body; if (localContext != null) { var createLocal = CreateLocalContext(_parentContext); init.Add( Ast.Assign( localContext, createLocal ) ); } init.Add(bodyStmt); bodyStmt = Ast.Block(init); // wrap a scope if needed bodyStmt = Ast.Block(locals.ToReadOnlyCollection(), bodyStmt); return(AstUtils.LightLambda( typeof(object), delegateType, AddDefaultReturn(bodyStmt, typeof(object)), Name + "$" + Interlocked.Increment(ref _lambdaId), parameters )); }
/// <summary> /// Creates the LambdaExpression which implements the body of the function. /// /// The functions signature is either "object Function(PythonFunction, ...)" /// where there is one object parameter for each user defined parameter or /// object Function(PythonFunction, object[]) for functions which take more /// than PythonCallTargets.MaxArgs arguments. /// </summary> private LightLambdaExpression CreateFunctionLambda() { bool needsWrapperMethod = _parameters.Length > PythonCallTargets.MaxArgs; Type delegateType = GetDelegateType(_parameters, needsWrapperMethod, out _); MSAst.ParameterExpression localContext = null; ReadOnlyCollectionBuilder <MSAst.ParameterExpression> locals = new ReadOnlyCollectionBuilder <MSAst.ParameterExpression>(); if (NeedsLocalContext) { localContext = LocalCodeContextVariable; locals.Add(localContext); } MSAst.ParameterExpression[] parameters = CreateParameters(needsWrapperMethod, locals); List <MSAst.Expression> init = new List <MSAst.Expression>(); foreach (var param in _parameters) { if (GetVariableExpression(param.PythonVariable) is IPythonVariableExpression pyVar) { var varInit = pyVar.Create(); if (varInit != null) { init.Add(varInit); } } } // Transform the parameters. init.Add(Ast.ClearDebugInfo(GlobalParent.Document)); locals.Add(PythonAst._globalContext); init.Add(Ast.Assign(PythonAst._globalContext, new GetGlobalContextExpression(_parentContext))); GlobalParent.PrepareScope(locals, init); // Create variables and references. Since references refer to // parameters, do this after parameters have been created. CreateFunctionVariables(locals, init); // If the __class__ variable is used in a class method then we need to initialize it. // This must be done before parameter initialization (in case one of the parameters is called __class__). ClassDefinition parent = FindParentOfType <ClassDefinition>(); if (parent != null && TryGetVariable("__class__", out PythonVariable pVar)) { init.Add( AssignValue( GetVariableExpression(pVar), Ast.Call(AstMethods.LookupName, parent.Parent.LocalContext, Ast.Constant(parent.Name)) ) ); } // Initialize parameters - unpack tuples. // Since tuples unpack into locals, this must be done after locals have been created. InitializeParameters(init, needsWrapperMethod, parameters); List <MSAst.Expression> statements = new List <MSAst.Expression>(); // add beginning sequence point var start = GlobalParent.IndexToLocation(StartIndex); statements.Add(GlobalParent.AddDebugInfo( AstUtils.Empty(), new SourceSpan(new SourceLocation(0, start.Line, start.Column), new SourceLocation(0, start.Line, int.MaxValue)))); // For generators, we need to do a check before the first statement for Generator.Throw() / Generator.Close(). // The exception traceback needs to come from the generator's method body, and so we must do the check and throw // from inside the generator. if (IsGenerator) { MSAst.Expression s1 = YieldExpression.CreateCheckThrowExpression(SourceSpan.None); statements.Add(s1); } if (Body.CanThrow && !(Body is SuiteStatement) && Body.StartIndex != -1) { statements.Add(UpdateLineNumber(GlobalParent.IndexToLocation(Body.StartIndex).Line)); } statements.Add(Body); MSAst.Expression body = Ast.Block(statements); if (Body.CanThrow && GlobalParent.PyContext.PythonOptions.Frames) { body = AddFrame(LocalContext, Ast.Property(_functionParam, typeof(PythonFunction).GetProperty(nameof(PythonFunction.__code__))), body); locals.Add(FunctionStackVariable); } body = AddProfiling(body); body = WrapScopeStatements(body, Body.CanThrow); body = Ast.Block(body, AstUtils.Empty()); body = AddReturnTarget(body); MSAst.Expression bodyStmt = body; if (localContext != null) { var createLocal = CreateLocalContext(_parentContext); init.Add( Ast.Assign( localContext, createLocal ) ); } init.Add(bodyStmt); bodyStmt = Ast.Block(init); // wrap a scope if needed bodyStmt = Ast.Block(locals.ToReadOnlyCollection(), bodyStmt); return(AstUtils.LightLambda( typeof(object), delegateType, AddDefaultReturn(bodyStmt, typeof(object)), Name + "$" + Interlocked.Increment(ref _lambdaId), parameters )); }
public string Visit(PyAst.YieldExpression node) => throw CreateNotImplementedEx();