PageRenderTime 7ms CodeModel.GetById 2ms app.highlight 3ms RepoModel.GetById 1ms app.codeStats 0ms

/IronPython_2_0/Src/IronPython/Compiler/Ast/YieldExpression.cs

#
C# | 97 lines | 53 code | 13 blank | 31 comment | 5 complexity | 8bed6fe7b2720c53ad126777463322a6 MD5 | raw file
 1/* ****************************************************************************
 2 *
 3 * Copyright (c) Microsoft Corporation. 
 4 *
 5 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 6 * copy of the license can be found in the License.html file at the root of this distribution. If 
 7 * you cannot locate the  Microsoft Public License, please send an email to 
 8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 9 * by the terms of the Microsoft Public License.
10 *
11 * You must not remove this notice, or any other, from this software.
12 *
13 *
14 * ***************************************************************************/
15
16using System; using Microsoft;
17using System.Diagnostics;
18using Microsoft.Scripting;
19using IronPython.Runtime.Operations;
20using AstUtils = Microsoft.Scripting.Ast.Utils;
21using MSAst = Microsoft.Linq.Expressions;
22
23namespace IronPython.Compiler.Ast {
24    using Ast = Microsoft.Linq.Expressions.Expression;
25
26    // New in Pep342 for Python 2.5. Yield is an expression with a return value.
27    //    x = yield z
28    // The return value (x) is provided by calling Generator.Send()
29    public class YieldExpression : Expression { 
30        private readonly Expression _expression;
31
32        public YieldExpression(Expression expression) {
33            _expression = expression;
34        }
35
36        public Expression Expression {
37            get { return _expression; }
38        }
39
40        // Generate AST statement to call $gen.CheckThrowable() on the Python Generator.
41        // This needs to be injected at any yield suspension points, mainly:
42        // - at the start of the generator body
43        // - after each yield statement.
44        static internal MSAst.Expression CreateCheckThrowExpression(AstGenerator ag, SourceSpan span) {
45            if (!ag.IsGenerator) {
46                // This can fail if yield is used outside of a function body. 
47                // Normally, we'd like the parser to catch this and just assert there. But yield could be in practically any expression,
48                // and the parser can't catch all cases. 
49
50                // Consider using ag.AddError(). However, consumers expect Expression transforms to be non-null, so if we don't throw,
51                // we'd still need to return something. 
52                throw PythonOps.SyntaxError(IronPython.Resources.MisplacedYield, ag.Context.SourceUnit, span, IronPython.Hosting.ErrorCodes.SyntaxError);
53            }
54
55            MSAst.Expression instance = ag.GeneratorParameter;
56            Debug.Assert(instance.Type == typeof(IronPython.Runtime.PythonGenerator));
57
58            MSAst.Expression s2 = Ast.Call(
59                typeof(PythonOps).GetMethod("GeneratorCheckThrowableAndReturnSendValue"),
60                instance
61            );
62            return s2;
63        }
64
65        internal override MSAst.Expression Transform(AstGenerator ag, Type type) {
66            // (yield z) becomes:
67            // .comma (1) {
68            //    .void ( .yield_statement (_expression) ),
69            //    $gen.CheckThrowable() // <-- has return result from send            
70            //  }
71
72            return Ast.Comma(
73                AstUtils.YieldReturn(
74                    ag.GeneratorLabel,
75                    Ast.ConvertHelper(ag.Transform(_expression), typeof(object)),
76                    Ast.Annotate(Span)
77                ),
78                CreateCheckThrowExpression(ag, this.Span) // emits ($gen.CheckThrowable())
79            );
80        }
81
82        public override void Walk(PythonWalker walker) {
83            if (walker.Walk(this)) {
84                if (_expression != null) {
85                    _expression.Walk(walker);
86                }
87            }
88            walker.PostWalk(this);
89        }
90
91        public override string NodeName {
92            get {
93                return "yield expression";
94            }
95        }
96    }
97}