/IronPython_2_0/Src/IronPython/Compiler/Ast/YieldExpression.cs
C# | 97 lines | 53 code | 13 blank | 31 comment | 5 complexity | 8bed6fe7b2720c53ad126777463322a6 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Microsoft Public License. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Microsoft Public License, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Microsoft Public License.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- using System; using Microsoft;
- using System.Diagnostics;
- using Microsoft.Scripting;
- using IronPython.Runtime.Operations;
- using AstUtils = Microsoft.Scripting.Ast.Utils;
- using MSAst = Microsoft.Linq.Expressions;
-
- namespace IronPython.Compiler.Ast {
- using Ast = Microsoft.Linq.Expressions.Expression;
-
- // New in Pep342 for Python 2.5. Yield is an expression with a return value.
- // x = yield z
- // The return value (x) is provided by calling Generator.Send()
- public class YieldExpression : Expression {
- private readonly Expression _expression;
-
- public YieldExpression(Expression expression) {
- _expression = expression;
- }
-
- public Expression Expression {
- get { return _expression; }
- }
-
- // Generate AST statement to call $gen.CheckThrowable() on the Python Generator.
- // This needs to be injected at any yield suspension points, mainly:
- // - at the start of the generator body
- // - after each yield statement.
- static internal MSAst.Expression CreateCheckThrowExpression(AstGenerator ag, SourceSpan span) {
- if (!ag.IsGenerator) {
- // This can fail if yield is used outside of a function body.
- // Normally, we'd like the parser to catch this and just assert there. But yield could be in practically any expression,
- // and the parser can't catch all cases.
-
- // Consider using ag.AddError(). However, consumers expect Expression transforms to be non-null, so if we don't throw,
- // we'd still need to return something.
- throw PythonOps.SyntaxError(IronPython.Resources.MisplacedYield, ag.Context.SourceUnit, span, IronPython.Hosting.ErrorCodes.SyntaxError);
- }
-
- MSAst.Expression instance = ag.GeneratorParameter;
- Debug.Assert(instance.Type == typeof(IronPython.Runtime.PythonGenerator));
-
- MSAst.Expression s2 = Ast.Call(
- typeof(PythonOps).GetMethod("GeneratorCheckThrowableAndReturnSendValue"),
- instance
- );
- return s2;
- }
-
- internal override MSAst.Expression Transform(AstGenerator ag, Type type) {
- // (yield z) becomes:
- // .comma (1) {
- // .void ( .yield_statement (_expression) ),
- // $gen.CheckThrowable() // <-- has return result from send
- // }
-
- return Ast.Comma(
- AstUtils.YieldReturn(
- ag.GeneratorLabel,
- Ast.ConvertHelper(ag.Transform(_expression), typeof(object)),
- Ast.Annotate(Span)
- ),
- CreateCheckThrowExpression(ag, this.Span) // emits ($gen.CheckThrowable())
- );
- }
-
- public override void Walk(PythonWalker walker) {
- if (walker.Walk(this)) {
- if (_expression != null) {
- _expression.Walk(walker);
- }
- }
- walker.PostWalk(this);
- }
-
- public override string NodeName {
- get {
- return "yield expression";
- }
- }
- }
- }