PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython/Compiler/Ast/AssignmentStatement.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 161 lines | 84 code | 30 blank | 47 comment | 15 complexity | 904a7f696629a07e92a1ed18409d744b 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. using System;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using Microsoft.Scripting;
  19. using Microsoft.Scripting.Runtime;
  20. using IronPython.Runtime.Binding;
  21. using IronPython.Runtime.Operations;
  22. #if !CLR2
  23. using MSAst = System.Linq.Expressions;
  24. #else
  25. using MSAst = Microsoft.Scripting.Ast;
  26. #endif
  27. using AstUtils = Microsoft.Scripting.Ast.Utils;
  28. namespace IronPython.Compiler.Ast {
  29. using Ast = MSAst.Expression;
  30. public class AssignmentStatement : Statement {
  31. // _left.Length is 1 for simple assignments like "x = 1"
  32. // _left.Length will be 3 for "x = y = z = 1"
  33. private readonly Expression[] _left;
  34. private readonly Expression _right;
  35. public AssignmentStatement(Expression[] left, Expression right) {
  36. _left = left;
  37. _right = right;
  38. }
  39. public IList<Expression> Left {
  40. get { return _left; }
  41. }
  42. public Expression Right {
  43. get { return _right; }
  44. }
  45. public override MSAst.Expression Reduce() {
  46. if (_left.Length == 1) {
  47. // Do not need temps for simple assignment
  48. return AssignOne();
  49. } else {
  50. return AssignComplex(_right);
  51. }
  52. }
  53. private MSAst.Expression AssignComplex(MSAst.Expression right) {
  54. // Python assignment semantics:
  55. // - only evaluate RHS once.
  56. // - evaluates assignment from left to right
  57. // - does not evaluate getters.
  58. //
  59. // So
  60. // a=b[c]=d=f()
  61. // should be:
  62. // $temp = f()
  63. // a = $temp
  64. // b[c] = $temp
  65. // d = $temp
  66. List<MSAst.Expression> statements = new List<MSAst.Expression>();
  67. // 1. Create temp variable for the right value
  68. MSAst.ParameterExpression right_temp = Expression.Variable(typeof(object), "assignment");
  69. // 2. right_temp = right
  70. statements.Add(MakeAssignment(right_temp, right));
  71. // Do left to right assignment
  72. foreach (Expression e in _left) {
  73. if (e == null) {
  74. continue;
  75. }
  76. // 3. e = right_temp
  77. MSAst.Expression transformed = e.TransformSet(Span, right_temp, PythonOperationKind.None);
  78. statements.Add(transformed);
  79. }
  80. // 4. Create and return the resulting suite
  81. statements.Add(AstUtils.Empty());
  82. return GlobalParent.AddDebugInfoAndVoid(
  83. Ast.Block(new[] { right_temp }, statements.ToArray()),
  84. Span
  85. );
  86. }
  87. private MSAst.Expression AssignOne() {
  88. Debug.Assert(_left.Length == 1);
  89. SequenceExpression seLeft = _left[0] as SequenceExpression;
  90. SequenceExpression seRight = _right as SequenceExpression;
  91. if (seLeft != null && seRight != null && seLeft.Items.Count == seRight.Items.Count) {
  92. int cnt = seLeft.Items.Count;
  93. // a, b = 1, 2, or [a,b] = 1,2 - not something like a, b = range(2)
  94. // we can do a fast parallel assignment
  95. MSAst.ParameterExpression[] tmps = new MSAst.ParameterExpression[cnt];
  96. MSAst.Expression[] body = new MSAst.Expression[cnt * 2 + 1];
  97. // generate the body, the 1st n are the temporary assigns, the
  98. // last n are the assignments to the left hand side
  99. // 0: tmp0 = right[0]
  100. // ...
  101. // n-1: tmpn-1 = right[n-1]
  102. // n: right[0] = tmp0
  103. // ...
  104. // n+n-1: right[n-1] = tmpn-1
  105. // allocate the temps first before transforming so we don't pick up a bad temp...
  106. for (int i = 0; i < cnt; i++) {
  107. MSAst.Expression tmpVal = seRight.Items[i];
  108. tmps[i] = Ast.Variable(tmpVal.Type, "parallelAssign");
  109. body[i] = Ast.Assign(tmps[i], tmpVal);
  110. }
  111. // then transform which can allocate more temps
  112. for (int i = 0; i < cnt; i++) {
  113. body[i + cnt] = seLeft.Items[i].TransformSet(SourceSpan.None, tmps[i], PythonOperationKind.None);
  114. }
  115. // 4. Create and return the resulting suite
  116. body[cnt * 2] = AstUtils.Empty();
  117. return GlobalParent.AddDebugInfoAndVoid(Ast.Block(tmps, body), Span);
  118. }
  119. return _left[0].TransformSet(Span, _right, PythonOperationKind.None);
  120. }
  121. public override void Walk(PythonWalker walker) {
  122. if (walker.Walk(this)) {
  123. foreach (Expression e in _left) {
  124. e.Walk(walker);
  125. }
  126. _right.Walk(walker);
  127. }
  128. walker.PostWalk(this);
  129. }
  130. }
  131. }