PageRenderTime 36ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 1ms

/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
  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. using System; using Microsoft;
  16. using System.Diagnostics;
  17. using Microsoft.Scripting;
  18. using IronPython.Runtime.Operations;
  19. using AstUtils = Microsoft.Scripting.Ast.Utils;
  20. using MSAst = Microsoft.Linq.Expressions;
  21. namespace IronPython.Compiler.Ast {
  22. using Ast = Microsoft.Linq.Expressions.Expression;
  23. // New in Pep342 for Python 2.5. Yield is an expression with a return value.
  24. // x = yield z
  25. // The return value (x) is provided by calling Generator.Send()
  26. public class YieldExpression : Expression {
  27. private readonly Expression _expression;
  28. public YieldExpression(Expression expression) {
  29. _expression = expression;
  30. }
  31. public Expression Expression {
  32. get { return _expression; }
  33. }
  34. // Generate AST statement to call $gen.CheckThrowable() on the Python Generator.
  35. // This needs to be injected at any yield suspension points, mainly:
  36. // - at the start of the generator body
  37. // - after each yield statement.
  38. static internal MSAst.Expression CreateCheckThrowExpression(AstGenerator ag, SourceSpan span) {
  39. if (!ag.IsGenerator) {
  40. // This can fail if yield is used outside of a function body.
  41. // Normally, we'd like the parser to catch this and just assert there. But yield could be in practically any expression,
  42. // and the parser can't catch all cases.
  43. // Consider using ag.AddError(). However, consumers expect Expression transforms to be non-null, so if we don't throw,
  44. // we'd still need to return something.
  45. throw PythonOps.SyntaxError(IronPython.Resources.MisplacedYield, ag.Context.SourceUnit, span, IronPython.Hosting.ErrorCodes.SyntaxError);
  46. }
  47. MSAst.Expression instance = ag.GeneratorParameter;
  48. Debug.Assert(instance.Type == typeof(IronPython.Runtime.PythonGenerator));
  49. MSAst.Expression s2 = Ast.Call(
  50. typeof(PythonOps).GetMethod("GeneratorCheckThrowableAndReturnSendValue"),
  51. instance
  52. );
  53. return s2;
  54. }
  55. internal override MSAst.Expression Transform(AstGenerator ag, Type type) {
  56. // (yield z) becomes:
  57. // .comma (1) {
  58. // .void ( .yield_statement (_expression) ),
  59. // $gen.CheckThrowable() // <-- has return result from send
  60. // }
  61. return Ast.Comma(
  62. AstUtils.YieldReturn(
  63. ag.GeneratorLabel,
  64. Ast.ConvertHelper(ag.Transform(_expression), typeof(object)),
  65. Ast.Annotate(Span)
  66. ),
  67. CreateCheckThrowExpression(ag, this.Span) // emits ($gen.CheckThrowable())
  68. );
  69. }
  70. public override void Walk(PythonWalker walker) {
  71. if (walker.Walk(this)) {
  72. if (_expression != null) {
  73. _expression.Walk(walker);
  74. }
  75. }
  76. walker.PostWalk(this);
  77. }
  78. public override string NodeName {
  79. get {
  80. return "yield expression";
  81. }
  82. }
  83. }
  84. }