PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/DICK.B1/IronPython/Compiler/GeneratorRewriter.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 1016 lines | 755 code | 131 blank | 130 comment | 169 complexity | 76b7e354bb91e54930635dda8a37983e 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. #if !CLR2
  16. using System.Linq.Expressions;
  17. #endif
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Collections.ObjectModel;
  21. using System.Diagnostics;
  22. using System.Reflection;
  23. using System.Runtime.CompilerServices;
  24. using Microsoft.Scripting;
  25. using Microsoft.Scripting.Ast;
  26. using Microsoft.Scripting.Utils;
  27. using IronPython.Runtime;
  28. using IronPython.Runtime.Operations;
  29. using AstUtils = Microsoft.Scripting.Ast.Utils;
  30. namespace IronPython.Compiler {
  31. /// <summary>
  32. /// When finding a yield return or yield break, this rewriter flattens out
  33. /// containing blocks, scopes, and expressions with stack state. All
  34. /// scopes encountered have their variables promoted to the generator's
  35. /// closure, so they survive yields.
  36. /// </summary>
  37. internal sealed class GeneratorRewriter : ExpressionVisitor {
  38. private readonly Expression _body;
  39. private readonly string _name;
  40. private readonly StrongBox<Type> _tupleType = new StrongBox<Type>();
  41. private readonly StrongBox<ParameterExpression> _tupleExpr = new StrongBox<ParameterExpression>();
  42. // The one return label, or more than one if we're in a finally
  43. private readonly Stack<LabelTarget> _returnLabels = new Stack<LabelTarget>();
  44. private ParameterExpression _gotoRouter;
  45. private bool _inTryWithFinally;
  46. private readonly List<YieldMarker> _yields = new List<YieldMarker>();
  47. private readonly Dictionary<ParameterExpression, DelayedTupleExpression> _vars = new Dictionary<ParameterExpression, DelayedTupleExpression>();
  48. private readonly List<KeyValuePair<ParameterExpression, DelayedTupleExpression>> _orderedVars = new List<KeyValuePair<ParameterExpression, DelayedTupleExpression>>();
  49. // Possible optimization: reuse temps. Requires scoping them correctly,
  50. // and then storing them back in a free list
  51. private readonly List<ParameterExpression> _temps = new List<ParameterExpression>();
  52. private Expression _state, _current;
  53. // These two constants are used internally. They should not conflict
  54. // with valid yield states.
  55. private const int GotoRouterYielding = 0;
  56. private const int GotoRouterNone = -1;
  57. // The state of the generator before it starts and when it's done
  58. internal const int NotStarted = -1;
  59. internal const int Finished = 0;
  60. internal static ParameterExpression _generatorParam = Expression.Parameter(typeof(PythonGenerator), "$generator");
  61. internal GeneratorRewriter(string name, Expression body) {
  62. _body = body;
  63. _name = name;
  64. _returnLabels.Push(Expression.Label("retLabel"));
  65. _gotoRouter = Expression.Variable(typeof(int), "$gotoRouter");
  66. }
  67. internal Expression Reduce(bool shouldInterpret, bool emitDebugSymbols, int compilationThreshold,
  68. IList<ParameterExpression> parameters, Func<Expression<Func<MutableTuple, object>>,
  69. Expression<Func<MutableTuple, object>>> bodyConverter) {
  70. _state = LiftVariable(Expression.Parameter(typeof(int), "state"));
  71. _current = LiftVariable(Expression.Parameter(typeof(object), "current"));
  72. // lift the parameters into the tuple
  73. foreach (ParameterExpression pe in parameters) {
  74. LiftVariable(pe);
  75. }
  76. DelayedTupleExpression liftedGen = LiftVariable(_generatorParam);
  77. // Visit body
  78. Expression body = Visit(_body);
  79. Debug.Assert(_returnLabels.Count == 1);
  80. // Add the switch statement to the body
  81. int count = _yields.Count;
  82. var cases = new SwitchCase[count + 1];
  83. for (int i = 0; i < count; i++) {
  84. cases[i] = Expression.SwitchCase(Expression.Goto(_yields[i].Label), AstUtils.Constant(_yields[i].State));
  85. }
  86. cases[count] = Expression.SwitchCase(Expression.Goto(_returnLabels.Peek()), AstUtils.Constant(Finished));
  87. // Create the lambda for the PythonGeneratorNext, hoisting variables
  88. // into a tuple outside the lambda
  89. Expression[] tupleExprs = new Expression[_vars.Count];
  90. foreach (var variable in _orderedVars) {
  91. // first 2 are our state & out var
  92. if (variable.Value.Index >= 2 && variable.Value.Index < (parameters.Count + 2)) {
  93. tupleExprs[variable.Value.Index] = parameters[variable.Value.Index - 2];
  94. } else {
  95. tupleExprs[variable.Value.Index] = Expression.Default(variable.Key.Type);
  96. }
  97. }
  98. Expression newTuple = MutableTuple.Create(tupleExprs);
  99. Type tupleType = _tupleType.Value = newTuple.Type;
  100. ParameterExpression tupleExpr = _tupleExpr.Value = Expression.Parameter(tupleType, "tuple");
  101. ParameterExpression tupleArg = Expression.Parameter(typeof(MutableTuple), "tupleArg");
  102. _temps.Add(_gotoRouter);
  103. _temps.Add(tupleExpr);
  104. // temps for the outer lambda
  105. ParameterExpression tupleTmp = Expression.Parameter(tupleType, "tuple");
  106. ParameterExpression ret = Expression.Parameter(typeof(PythonGenerator), "ret");
  107. var innerLambda = Expression.Lambda<Func<MutableTuple, object>>(
  108. Expression.Block(
  109. _temps.ToArray(),
  110. Expression.Assign(
  111. tupleExpr,
  112. Expression.Convert(
  113. tupleArg,
  114. tupleType
  115. )
  116. ),
  117. Expression.Switch(Expression.Assign(_gotoRouter, _state), cases),
  118. body,
  119. MakeAssign(_state, AstUtils.Constant(Finished)),
  120. Expression.Label(_returnLabels.Peek()),
  121. _current
  122. ),
  123. _name,
  124. new ParameterExpression[] { tupleArg }
  125. );
  126. // Generate a call to PythonOps.MakeGeneratorClosure(Tuple data, object generatorCode)
  127. return Expression.Block(
  128. new[] { tupleTmp, ret },
  129. Expression.Assign(
  130. ret,
  131. Expression.Call(
  132. typeof(PythonOps).GetMethod("MakeGenerator"),
  133. parameters[0],
  134. Expression.Assign(tupleTmp, newTuple),
  135. emitDebugSymbols ?
  136. (Expression)bodyConverter(innerLambda) :
  137. (Expression)Expression.Constant(
  138. new LazyCode<Func<MutableTuple, object>>(
  139. bodyConverter(innerLambda),
  140. shouldInterpret,
  141. compilationThreshold
  142. ),
  143. typeof(object)
  144. )
  145. )
  146. ),
  147. new DelayedTupleAssign(
  148. new DelayedTupleExpression(liftedGen.Index, new StrongBox<ParameterExpression>(tupleTmp), _tupleType, typeof(PythonGenerator)),
  149. ret
  150. ),
  151. ret
  152. );
  153. }
  154. private YieldMarker GetYieldMarker(YieldExpression node) {
  155. YieldMarker result = new YieldMarker(_yields.Count + 1);
  156. _yields.Add(result);
  157. Debug.Assert(node.YieldMarker == -1);
  158. return result;
  159. }
  160. /// <summary>
  161. /// Spills the right side into a temp, and replaces it with its temp.
  162. /// Returns the expression that initializes the temp.
  163. /// </summary>
  164. private Expression ToTemp(ref Expression e) {
  165. Debug.Assert(e != null);
  166. var temp = LiftVariable(Expression.Variable(e.Type, "generatorTemp" + _temps.Count));
  167. var result = MakeAssign(temp, e);
  168. e = temp;
  169. return result;
  170. }
  171. /// <summary>
  172. /// Makes an assignment to this variable. Pushes the assignment as far
  173. /// into the right side as possible, to allow jumps into it.
  174. /// </summary>
  175. private Expression MakeAssign(Expression variable, Expression value) {
  176. // TODO: this is not complete.
  177. // It may end up generating a bad tree if any of these nodes
  178. // contain yield and return a value: Switch, Loop, Goto, or Label.
  179. // Those are not supported, but we can't throw here because we may
  180. // end up disallowing valid uses (if some other expression contains
  181. // yield, but not this one).
  182. switch (value.NodeType) {
  183. case ExpressionType.Block:
  184. return MakeAssignBlock(variable, value);
  185. case ExpressionType.Conditional:
  186. return MakeAssignConditional(variable, value);
  187. }
  188. return DelayedAssign(variable, value);
  189. }
  190. private Expression MakeAssignBlock(Expression variable, Expression value) {
  191. var node = (BlockExpression)value;
  192. var newBlock = new ReadOnlyCollectionBuilder<Expression>(node.Expressions);
  193. newBlock[newBlock.Count - 1] = MakeAssign(variable, newBlock[newBlock.Count - 1]);
  194. return Expression.Block(node.Variables, newBlock);
  195. }
  196. private Expression MakeAssignConditional(Expression variable, Expression value) {
  197. var node = (ConditionalExpression)value;
  198. return Expression.Condition(node.Test, MakeAssign(variable, node.IfTrue), MakeAssign(variable, node.IfFalse));
  199. }
  200. private BlockExpression ToTemp(ref ReadOnlyCollection<Expression> args) {
  201. int count = args.Count;
  202. var block = new Expression[count];
  203. var newArgs = new Expression[count];
  204. args.CopyTo(newArgs, 0);
  205. for (int i = 0; i < count; i++) {
  206. block[i] = ToTemp(ref newArgs[i]);
  207. }
  208. args = new ReadOnlyCollection<Expression>(newArgs);
  209. return Expression.Block(block);
  210. }
  211. #region VisitTry
  212. protected override Expression VisitTry(TryExpression node) {
  213. int startYields = _yields.Count;
  214. bool savedInTryWithFinally = _inTryWithFinally;
  215. if (node.Finally != null || node.Fault != null) {
  216. _inTryWithFinally = true;
  217. }
  218. Expression @try = Visit(node.Body);
  219. int tryYields = _yields.Count;
  220. IList<CatchBlock> handlers = Visit(node.Handlers, VisitCatchBlock);
  221. int catchYields = _yields.Count;
  222. // push a new return label in case the finally block yields
  223. _returnLabels.Push(Expression.Label("tryLabel"));
  224. // only one of these can be non-null
  225. Expression @finally = Visit(node.Finally);
  226. Expression fault = Visit(node.Fault);
  227. LabelTarget finallyReturn = _returnLabels.Pop();
  228. int finallyYields = _yields.Count;
  229. _inTryWithFinally = savedInTryWithFinally;
  230. if (@try == node.Body &&
  231. handlers == node.Handlers &&
  232. @finally == node.Finally &&
  233. fault == node.Fault) {
  234. return node;
  235. }
  236. // No yields, just return
  237. if (startYields == _yields.Count) {
  238. return Expression.MakeTry(null, @try, @finally, fault, handlers);
  239. }
  240. if (fault != null && finallyYields != catchYields) {
  241. // No one needs this yet, and it's not clear how we should get back to
  242. // the fault
  243. throw new NotSupportedException("yield in fault block is not supported");
  244. }
  245. // If try has yields, we need to build a new try body that
  246. // dispatches to the yield labels
  247. var tryStart = Expression.Label("tryStart");
  248. if (tryYields != startYields) {
  249. @try = Expression.Block(MakeYieldRouter(startYields, tryYields, tryStart), @try);
  250. }
  251. // Transform catches with yield to deferred handlers
  252. if (catchYields != tryYields) {
  253. var block = new List<Expression>();
  254. block.Add(MakeYieldRouter(tryYields, catchYields, tryStart));
  255. block.Add(null); // empty slot to fill in later
  256. for (int i = 0, n = handlers.Count; i < n; i++) {
  257. CatchBlock c = handlers[i];
  258. if (c == node.Handlers[i]) {
  259. continue;
  260. }
  261. if (handlers.IsReadOnly) {
  262. handlers = ArrayUtils.ToArray(handlers);
  263. }
  264. // the variable that will be scoped to the catch block
  265. var exceptionVar = Expression.Variable(c.Test, null);
  266. // the variable that the catch block body will use to
  267. // access the exception. We reuse the original variable if
  268. // the catch block had one. It needs to be hoisted because
  269. // the catch might contain yields.
  270. var deferredVar = c.Variable ?? Expression.Variable(c.Test, null);
  271. LiftVariable(deferredVar);
  272. // We need to ensure that filters can access the exception
  273. // variable
  274. Expression filter = c.Filter;
  275. if (filter != null && c.Variable != null) {
  276. filter = Expression.Block(new[] { c.Variable }, Expression.Assign(c.Variable, exceptionVar), filter);
  277. }
  278. // catch (ExceptionType exceptionVar) {
  279. // deferredVar = exceptionVar;
  280. // }
  281. handlers[i] = Expression.Catch(
  282. exceptionVar,
  283. Utils.Void(DelayedAssign(Visit(deferredVar), exceptionVar)),
  284. filter
  285. );
  286. // We need to rewrite rethrows into "throw deferredVar"
  287. var catchBody = new RethrowRewriter { Exception = deferredVar }.Visit(c.Body);
  288. // if (deferredVar != null) {
  289. // ... catch body ...
  290. // }
  291. block.Add(
  292. Expression.IfThen(
  293. Expression.NotEqual(Visit(deferredVar), AstUtils.Constant(null, deferredVar.Type)),
  294. catchBody
  295. )
  296. );
  297. }
  298. block[1] = Expression.MakeTry(null, @try, null, null, new ReadOnlyCollection<CatchBlock>(handlers));
  299. @try = Expression.Block(block);
  300. handlers = new CatchBlock[0]; // so we don't reuse these
  301. }
  302. if (finallyYields != catchYields) {
  303. // We need to add a catch block to save the exception, so we
  304. // can rethrow in case there is a yield in the finally. Also,
  305. // add logic for returning. It looks like this:
  306. //
  307. // try { ... } catch (Exception all) { saved = all; }
  308. // finally {
  309. // if (_finallyReturnVar) goto finallyReturn;
  310. // ...
  311. // if (saved != null) throw saved;
  312. // finallyReturn:
  313. // }
  314. // if (_finallyReturnVar) goto _return;
  315. // We need to add a catch(Exception), so if we have catches,
  316. // wrap them in a try
  317. if (handlers.Count > 0) {
  318. @try = Expression.MakeTry(null, @try, null, null, handlers);
  319. handlers = new CatchBlock[0];
  320. }
  321. // NOTE: the order of these routers is important
  322. // The first call changes the labels to all point at "tryEnd",
  323. // so the second router will jump to "tryEnd"
  324. var tryEnd = Expression.Label("tryEnd");
  325. Expression inFinallyRouter = MakeYieldRouter(catchYields, finallyYields, tryEnd);
  326. Expression inTryRouter = MakeYieldRouter(catchYields, finallyYields, tryStart);
  327. var all = Expression.Variable(typeof(Exception), "e");
  328. var saved = Expression.Variable(typeof(Exception), "$saved$" + _temps.Count);
  329. LiftVariable(saved);
  330. @try = Expression.Block(
  331. Expression.TryCatchFinally(
  332. Expression.Block(
  333. inTryRouter,
  334. @try,
  335. DelayedAssign(Visit(saved), AstUtils.Constant(null, saved.Type)),
  336. Expression.Label(tryEnd)
  337. ),
  338. Expression.Block(
  339. MakeSkipFinallyBlock(finallyReturn),
  340. inFinallyRouter,
  341. @finally,
  342. Expression.Condition(
  343. Expression.NotEqual(Visit(saved), AstUtils.Constant(null, saved.Type)),
  344. Expression.Throw(Visit(saved)),
  345. Utils.Empty()
  346. ),
  347. Expression.Label(finallyReturn)
  348. ),
  349. Expression.Catch(all, Utils.Void(DelayedAssign(Visit(saved), all)))
  350. ),
  351. Expression.Condition(
  352. Expression.Equal(_gotoRouter, AstUtils.Constant(GotoRouterYielding)),
  353. Expression.Goto(_returnLabels.Peek()),
  354. Utils.Empty()
  355. )
  356. );
  357. @finally = null;
  358. } else if (@finally != null) {
  359. // try or catch had a yield, modify finally so we can skip over it
  360. @finally = Expression.Block(
  361. MakeSkipFinallyBlock(finallyReturn),
  362. @finally,
  363. Expression.Label(finallyReturn)
  364. );
  365. }
  366. // Make the outer try, if needed
  367. if (handlers.Count > 0 || @finally != null || fault != null) {
  368. @try = Expression.MakeTry(null, @try, @finally, fault, handlers);
  369. }
  370. return Expression.Block(Expression.Label(tryStart), @try);
  371. }
  372. private class RethrowRewriter : ExpressionVisitor {
  373. internal Expression Exception;
  374. protected override Expression VisitUnary(UnaryExpression node) {
  375. if (node.NodeType == ExpressionType.Throw && node.Operand == null) {
  376. return Expression.Throw(Exception, node.Type);
  377. }
  378. return base.VisitUnary(node);
  379. }
  380. protected override Expression VisitLambda<T>(Expression<T> node) {
  381. return node; // don't recurse into lambdas
  382. }
  383. protected override Expression VisitTry(TryExpression node) {
  384. return node; // don't recurse into other try's
  385. }
  386. protected override Expression VisitExtension(Expression node) {
  387. if (node is DelayedTupleExpression) {
  388. return node;
  389. }
  390. return base.VisitExtension(node);
  391. }
  392. }
  393. // Skip the finally block if we are yielding, but not if we're doing a
  394. // yield break
  395. private Expression MakeSkipFinallyBlock(LabelTarget target) {
  396. return Expression.Condition(
  397. Expression.AndAlso(
  398. Expression.Equal(_gotoRouter, AstUtils.Constant(GotoRouterYielding)),
  399. Expression.NotEqual(_state, AstUtils.Constant(Finished))
  400. ),
  401. Expression.Goto(target),
  402. Utils.Empty()
  403. );
  404. }
  405. // Mostly copied from the base implementation.
  406. // - makes sure we disallow yield in filters
  407. // - lifts exception variable
  408. protected override CatchBlock VisitCatchBlock(CatchBlock node) {
  409. if (node.Variable != null) {
  410. LiftVariable(node.Variable);
  411. }
  412. Expression v = Visit(node.Variable);
  413. int yields = _yields.Count;
  414. Expression f = Visit(node.Filter);
  415. if (yields != _yields.Count) {
  416. // No one needs this yet, and it's not clear what it should even do
  417. throw new NotSupportedException("yield in filter is not allowed");
  418. }
  419. Expression b = Visit(node.Body);
  420. if (v == node.Variable && b == node.Body && f == node.Filter) {
  421. return node;
  422. }
  423. // if we have variable and no yields in the catch block then
  424. // we need to hoist the variable into a closure
  425. if (v != node.Variable && yields == _yields.Count) {
  426. return Expression.MakeCatchBlock(
  427. node.Test,
  428. node.Variable,
  429. Expression.Block(
  430. new DelayedTupleAssign(v, node.Variable),
  431. b
  432. ),
  433. f);
  434. }
  435. return Expression.MakeCatchBlock(node.Test, node.Variable, b, f);
  436. }
  437. #endregion
  438. private SwitchExpression MakeYieldRouter(int start, int end, LabelTarget newTarget) {
  439. Debug.Assert(end > start);
  440. var cases = new SwitchCase[end - start];
  441. for (int i = start; i < end; i++) {
  442. YieldMarker y = _yields[i];
  443. cases[i - start] = Expression.SwitchCase(Expression.Goto(y.Label), AstUtils.Constant(y.State));
  444. // Any jumps from outer switch statements should go to the this
  445. // router, not the original label (which they cannot legally jump to)
  446. y.Label = newTarget;
  447. }
  448. return Expression.Switch(_gotoRouter, cases);
  449. }
  450. protected override Expression VisitExtension(Expression node) {
  451. var yield = node as YieldExpression;
  452. if (yield != null) {
  453. return VisitYield(yield);
  454. }
  455. var ffc = node as FinallyFlowControlExpression;
  456. if (ffc != null) {
  457. return Visit(node.ReduceExtensions());
  458. }
  459. return Visit(node.ReduceExtensions());
  460. }
  461. private Expression VisitYield(YieldExpression node) {
  462. var value = Visit(node.Value);
  463. var block = new List<Expression>();
  464. if (value == null) {
  465. // Yield break
  466. block.Add(MakeAssign(_state, AstUtils.Constant(Finished)));
  467. if (_inTryWithFinally) {
  468. block.Add(Expression.Assign(_gotoRouter, AstUtils.Constant(GotoRouterYielding)));
  469. }
  470. block.Add(Expression.Goto(_returnLabels.Peek()));
  471. return Expression.Block(block);
  472. }
  473. // Yield return
  474. block.Add(MakeAssign(_current, value));
  475. YieldMarker marker = GetYieldMarker(node);
  476. block.Add(MakeAssign(_state, AstUtils.Constant(marker.State)));
  477. if (_inTryWithFinally) {
  478. block.Add(Expression.Assign(_gotoRouter, AstUtils.Constant(GotoRouterYielding)));
  479. }
  480. block.Add(Expression.Goto(_returnLabels.Peek()));
  481. block.Add(Expression.Label(marker.Label));
  482. block.Add(Expression.Assign(_gotoRouter, AstUtils.Constant(GotoRouterNone)));
  483. block.Add(Utils.Empty());
  484. return Expression.Block(block);
  485. }
  486. protected override Expression VisitBlock(BlockExpression node) {
  487. // save the variables for later
  488. // (they'll be hoisted outside of the lambda)
  489. foreach (ParameterExpression param in node.Variables) {
  490. LiftVariable(param);
  491. }
  492. int yields = _yields.Count;
  493. var b = Visit(node.Expressions);
  494. if (b == node.Expressions) {
  495. return node;
  496. }
  497. if (yields == _yields.Count) {
  498. return Expression.Block(node.Type, node.Variables, b);
  499. }
  500. // Return a new block expression with the rewritten body except for that
  501. // all the variables are removed.
  502. return Expression.Block(node.Type, b);
  503. }
  504. private DelayedTupleExpression LiftVariable(ParameterExpression param) {
  505. DelayedTupleExpression res;
  506. if (!_vars.TryGetValue(param, out res)) {
  507. _vars[param] = res = new DelayedTupleExpression(_vars.Count, _tupleExpr, _tupleType, param.Type);
  508. _orderedVars.Add(new KeyValuePair<ParameterExpression, DelayedTupleExpression>(param, res));
  509. }
  510. return res;
  511. }
  512. protected override Expression VisitParameter(ParameterExpression node) {
  513. return _vars[node];
  514. }
  515. protected override Expression VisitLambda<T>(Expression<T> node) {
  516. // don't recurse into nested lambdas
  517. return node;
  518. }
  519. #region stack spilling (to permit yield in the middle of an expression)
  520. private Expression VisitAssign(BinaryExpression node) {
  521. int yields = _yields.Count;
  522. Expression left = Visit(node.Left);
  523. Expression right = Visit(node.Right);
  524. if (left == node.Left && right == node.Right) {
  525. return node;
  526. }
  527. if (yields == _yields.Count) {
  528. if (left is DelayedTupleExpression) {
  529. return new DelayedTupleAssign(left, right);
  530. }
  531. return Expression.Assign(left, right);
  532. }
  533. var block = new List<Expression>();
  534. // If the left hand side did not rewrite itself, we may still need
  535. // to rewrite to ensure proper evaluation order. Essentially, we
  536. // want all of the left side evaluated first, then the value, then
  537. // the assignment
  538. if (left == node.Left) {
  539. switch (left.NodeType) {
  540. case ExpressionType.MemberAccess:
  541. var member = (MemberExpression)node.Left;
  542. Expression e = Visit(member.Expression);
  543. block.Add(ToTemp(ref e));
  544. left = Expression.MakeMemberAccess(e, member.Member);
  545. break;
  546. case ExpressionType.Index:
  547. var index = (IndexExpression)node.Left;
  548. Expression o = Visit(index.Object);
  549. ReadOnlyCollection<Expression> a = Visit(index.Arguments);
  550. if (o == index.Object && a == index.Arguments) {
  551. return index;
  552. }
  553. block.Add(ToTemp(ref o));
  554. block.Add(ToTemp(ref a));
  555. left = Expression.MakeIndex(o, index.Indexer, a);
  556. break;
  557. case ExpressionType.Parameter:
  558. // no action needed
  559. break;
  560. default:
  561. // Extension should've been reduced by Visit above,
  562. // and returned a different node
  563. throw Assert.Unreachable;
  564. }
  565. } else if (left is BlockExpression) {
  566. // Get the last expression of the rewritten left side
  567. var leftBlock = (BlockExpression)left;
  568. left = leftBlock.Expressions[leftBlock.Expressions.Count - 1];
  569. block.AddRange(leftBlock.Expressions);
  570. block.RemoveAt(block.Count - 1);
  571. }
  572. if (right != node.Right) {
  573. block.Add(ToTemp(ref right));
  574. }
  575. if (left is DelayedTupleExpression) {
  576. block.Add(DelayedAssign(left, right));
  577. } else {
  578. block.Add(Expression.Assign(left, right));
  579. }
  580. return Expression.Block(block);
  581. }
  582. protected override Expression VisitDynamic(DynamicExpression node) {
  583. int yields = _yields.Count;
  584. ReadOnlyCollection<Expression> a = Visit(node.Arguments);
  585. if (a == node.Arguments) {
  586. return node;
  587. }
  588. if (yields == _yields.Count) {
  589. return Expression.MakeDynamic(node.DelegateType, node.Binder, a);
  590. }
  591. return Expression.Block(
  592. ToTemp(ref a),
  593. Expression.MakeDynamic(node.DelegateType, node.Binder, a)
  594. );
  595. }
  596. protected override Expression VisitIndex(IndexExpression node) {
  597. int yields = _yields.Count;
  598. Expression o = Visit(node.Object);
  599. ReadOnlyCollection<Expression> a = Visit(node.Arguments);
  600. if (o == node.Object && a == node.Arguments) {
  601. return node;
  602. }
  603. if (yields == _yields.Count) {
  604. return Expression.MakeIndex(o, node.Indexer, a);
  605. }
  606. return Expression.Block(
  607. ToTemp(ref o),
  608. ToTemp(ref a),
  609. Expression.MakeIndex(o, node.Indexer, a)
  610. );
  611. }
  612. protected override Expression VisitInvocation(InvocationExpression node) {
  613. int yields = _yields.Count;
  614. Expression e = Visit(node.Expression);
  615. ReadOnlyCollection<Expression> a = Visit(node.Arguments);
  616. if (e == node.Expression && a == node.Arguments) {
  617. return node;
  618. }
  619. if (yields == _yields.Count) {
  620. return Expression.Invoke(e, a);
  621. }
  622. return Expression.Block(
  623. ToTemp(ref e),
  624. ToTemp(ref a),
  625. Expression.Invoke(e, a)
  626. );
  627. }
  628. protected override Expression VisitMethodCall(MethodCallExpression node) {
  629. int yields = _yields.Count;
  630. Expression o = Visit(node.Object);
  631. ReadOnlyCollection<Expression> a = Visit(node.Arguments);
  632. if (o == node.Object && a == node.Arguments) {
  633. return node;
  634. }
  635. if (yields == _yields.Count) {
  636. return Expression.Call(o, node.Method, a);
  637. }
  638. if (o == null) {
  639. return Expression.Block(
  640. ToTemp(ref a),
  641. Expression.Call(null, node.Method, a)
  642. );
  643. }
  644. return Expression.Block(
  645. ToTemp(ref o),
  646. ToTemp(ref a),
  647. Expression.Call(o, node.Method, a)
  648. );
  649. }
  650. protected override Expression VisitNew(NewExpression node) {
  651. int yields = _yields.Count;
  652. ReadOnlyCollection<Expression> a = Visit(node.Arguments);
  653. if (a == node.Arguments) {
  654. return node;
  655. }
  656. if (yields == _yields.Count) {
  657. return (node.Members != null)
  658. ? Expression.New(node.Constructor, a, node.Members)
  659. : Expression.New(node.Constructor, a);
  660. }
  661. return Expression.Block(
  662. ToTemp(ref a),
  663. (node.Members != null)
  664. ? Expression.New(node.Constructor, a, node.Members)
  665. : Expression.New(node.Constructor, a)
  666. );
  667. }
  668. protected override Expression VisitNewArray(NewArrayExpression node) {
  669. int yields = _yields.Count;
  670. ReadOnlyCollection<Expression> e = Visit(node.Expressions);
  671. if (e == node.Expressions) {
  672. return node;
  673. }
  674. if (yields == _yields.Count) {
  675. return (node.NodeType == ExpressionType.NewArrayInit)
  676. ? Expression.NewArrayInit(node.Type.GetElementType(), e)
  677. : Expression.NewArrayBounds(node.Type.GetElementType(), e);
  678. }
  679. return Expression.Block(
  680. ToTemp(ref e),
  681. (node.NodeType == ExpressionType.NewArrayInit)
  682. ? Expression.NewArrayInit(node.Type.GetElementType(), e)
  683. : Expression.NewArrayBounds(node.Type.GetElementType(), e)
  684. );
  685. }
  686. protected override Expression VisitMember(MemberExpression node) {
  687. int yields = _yields.Count;
  688. Expression e = Visit(node.Expression);
  689. if (e == node.Expression) {
  690. return node;
  691. }
  692. if (yields == _yields.Count) {
  693. return Expression.MakeMemberAccess(e, node.Member);
  694. }
  695. return Expression.Block(
  696. ToTemp(ref e),
  697. Expression.MakeMemberAccess(e, node.Member)
  698. );
  699. }
  700. protected override Expression VisitBinary(BinaryExpression node) {
  701. if (node.NodeType == ExpressionType.Assign) {
  702. return VisitAssign(node);
  703. }
  704. // For OpAssign nodes: if has a yield, we need to do the generator
  705. // transformation on the reduced value.
  706. if (node.CanReduce) {
  707. return Visit(node.Reduce());
  708. }
  709. int yields = _yields.Count;
  710. Expression left = Visit(node.Left);
  711. Expression right = Visit(node.Right);
  712. if (left == node.Left && right == node.Right) {
  713. return node;
  714. }
  715. if (yields == _yields.Count) {
  716. return Expression.MakeBinary(node.NodeType, left, right, node.IsLiftedToNull, node.Method, node.Conversion);
  717. }
  718. return Expression.Block(
  719. ToTemp(ref left),
  720. ToTemp(ref right),
  721. Expression.MakeBinary(node.NodeType, left, right, node.IsLiftedToNull, node.Method, node.Conversion)
  722. );
  723. }
  724. protected override Expression VisitTypeBinary(TypeBinaryExpression node) {
  725. int yields = _yields.Count;
  726. Expression e = Visit(node.Expression);
  727. if (e == node.Expression) {
  728. return node;
  729. }
  730. if (yields == _yields.Count) {
  731. return (node.NodeType == ExpressionType.TypeIs)
  732. ? Expression.TypeIs(e, node.TypeOperand)
  733. : Expression.TypeEqual(e, node.TypeOperand);
  734. }
  735. return Expression.Block(
  736. ToTemp(ref e),
  737. (node.NodeType == ExpressionType.TypeIs)
  738. ? Expression.TypeIs(e, node.TypeOperand)
  739. : Expression.TypeEqual(e, node.TypeOperand)
  740. );
  741. }
  742. protected override Expression VisitUnary(UnaryExpression node) {
  743. // For OpAssign nodes: if has a yield, we need to do the generator
  744. // transformation on the reduced value.
  745. if (node.CanReduce) {
  746. return Visit(node.Reduce());
  747. }
  748. int yields = _yields.Count;
  749. Expression o = Visit(node.Operand);
  750. if (o == node.Operand) {
  751. return node;
  752. }
  753. // Void convert can be jumped into, no need to spill
  754. // TODO: remove when that feature goes away.
  755. if (yields == _yields.Count ||
  756. (node.NodeType == ExpressionType.Convert && node.Type == typeof(void))) {
  757. return Expression.MakeUnary(node.NodeType, o, node.Type, node.Method);
  758. }
  759. return Expression.Block(
  760. ToTemp(ref o),
  761. Expression.MakeUnary(node.NodeType, o, node.Type, node.Method)
  762. );
  763. }
  764. protected override Expression VisitMemberInit(MemberInitExpression node) {
  765. // See if anything changed
  766. int yields = _yields.Count;
  767. Expression e = base.VisitMemberInit(node);
  768. if (yields == _yields.Count) {
  769. return e;
  770. }
  771. // It has a yield. Reduce to basic nodes so we can jump in
  772. return e.Reduce();
  773. }
  774. protected override Expression VisitListInit(ListInitExpression node) {
  775. // See if anything changed
  776. int yields = _yields.Count;
  777. Expression e = base.VisitListInit(node);
  778. if (yields == _yields.Count) {
  779. return e;
  780. }
  781. // It has a yield. Reduce to basic nodes so we can jump in
  782. return e.Reduce();
  783. }
  784. private static Expression DelayedAssign(Expression lhs, Expression rhs) {
  785. return new DelayedTupleAssign(lhs, rhs);
  786. }
  787. #endregion
  788. private sealed class YieldMarker {
  789. // Note: Label can be mutated as we generate try blocks
  790. internal LabelTarget Label = Expression.Label("yieldMarker");
  791. internal readonly int State;
  792. internal YieldMarker(int state) {
  793. State = state;
  794. }
  795. }
  796. }
  797. /// <summary>
  798. /// Accesses the property of a tuple. The node can be created first and then the tuple and index
  799. /// type can be filled in before the tree is actually generated. This enables creation of these
  800. /// nodes before the tuple type is actually known.
  801. /// </summary>
  802. sealed class DelayedTupleExpression : Expression {
  803. public readonly int Index;
  804. private readonly StrongBox<Type> _tupleType;
  805. private readonly StrongBox<ParameterExpression> _tupleExpr;
  806. private readonly Type _type;
  807. public DelayedTupleExpression(int index, StrongBox<ParameterExpression> tupleExpr, StrongBox<Type> tupleType, Type type) {
  808. Index = index;
  809. _tupleType = tupleType;
  810. _tupleExpr = tupleExpr;
  811. _type = type;
  812. }
  813. public override Expression Reduce() {
  814. Expression res = _tupleExpr.Value;
  815. foreach (PropertyInfo pi in MutableTuple.GetAccessPath(_tupleType.Value, Index)) {
  816. res = Expression.Property(res, pi);
  817. }
  818. return res;
  819. }
  820. public sealed override ExpressionType NodeType {
  821. get { return ExpressionType.Extension; }
  822. }
  823. public sealed override Type/*!*/ Type {
  824. get { return _type; }
  825. }
  826. public override bool CanReduce {
  827. get {
  828. return true;
  829. }
  830. }
  831. protected override Expression VisitChildren(ExpressionVisitor visitor) {
  832. return this;
  833. }
  834. }
  835. sealed class DelayedTupleAssign : Expression {
  836. private readonly Expression _lhs, _rhs;
  837. public DelayedTupleAssign(Expression lhs, Expression rhs) {
  838. _lhs = lhs;
  839. _rhs = rhs;
  840. }
  841. public override Expression Reduce() {
  842. return Expression.Assign(_lhs.Reduce(), _rhs);
  843. }
  844. public sealed override ExpressionType NodeType {
  845. get { return ExpressionType.Extension; }
  846. }
  847. public sealed override Type/*!*/ Type {
  848. get { return _lhs.Type; }
  849. }
  850. public override bool CanReduce {
  851. get {
  852. return true;
  853. }
  854. }
  855. protected override Expression VisitChildren(ExpressionVisitor visitor) {
  856. Expression rhs = visitor.Visit(_rhs);
  857. if (rhs != _rhs) {
  858. return new DelayedTupleAssign(_lhs, rhs);
  859. }
  860. return this;
  861. }
  862. }
  863. internal sealed class PythonGeneratorExpression : Expression {
  864. private readonly LambdaExpression _lambda;
  865. private readonly int _compilationThreshold;
  866. public PythonGeneratorExpression(LambdaExpression lambda, int compilationThreshold) {
  867. _lambda = lambda;
  868. _compilationThreshold = compilationThreshold;
  869. }
  870. public override Expression Reduce() {
  871. return _lambda.ToGenerator(false, true, _compilationThreshold);
  872. }
  873. public sealed override ExpressionType NodeType {
  874. get { return ExpressionType.Extension; }
  875. }
  876. public sealed override Type/*!*/ Type {
  877. get { return _lambda.Type; }
  878. }
  879. public override bool CanReduce {
  880. get {
  881. return true;
  882. }
  883. }
  884. }
  885. }