PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Scripting.Core/Ast/BlockExpression.cs

https://bitbucket.org/stefanrusek/xronos
C# | 801 lines | 515 code | 135 blank | 151 comment | 73 complexity | 583a974491360985620f6f72dca2ce01 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; using Microsoft;
  16. using System.Collections.Generic;
  17. using System.Collections.ObjectModel;
  18. using System.Diagnostics;
  19. #if CODEPLEX_40
  20. using System.Dynamic.Utils;
  21. #else
  22. using Microsoft.Scripting.Utils;
  23. #endif
  24. using System.Threading;
  25. #if CODEPLEX_40
  26. namespace System.Linq.Expressions {
  27. #else
  28. namespace Microsoft.Linq.Expressions {
  29. #endif
  30. /// <summary>
  31. /// Represents a block that contains a sequence of expressions where variables can be defined.
  32. /// </summary>
  33. #if !SILVERLIGHT
  34. [DebuggerTypeProxy(typeof(Expression.BlockExpressionProxy))]
  35. #endif
  36. public class BlockExpression : Expression {
  37. /// <summary>
  38. /// Gets the expressions in this block.
  39. /// </summary>
  40. public ReadOnlyCollection<Expression> Expressions {
  41. get { return GetOrMakeExpressions(); }
  42. }
  43. /// <summary>
  44. /// Gets the variables defined in this block.
  45. /// </summary>
  46. public ReadOnlyCollection<ParameterExpression> Variables {
  47. get {
  48. return GetOrMakeVariables();
  49. }
  50. }
  51. /// <summary>
  52. /// Gets the last expression in this block.
  53. /// </summary>
  54. public Expression Result {
  55. get {
  56. Debug.Assert(ExpressionCount > 0);
  57. return GetExpression(ExpressionCount - 1);
  58. }
  59. }
  60. internal BlockExpression() {
  61. }
  62. internal override Expression Accept(ExpressionVisitor visitor) {
  63. return visitor.VisitBlock(this);
  64. }
  65. /// <summary>
  66. /// Returns the node type of this Expression. Extension nodes should return
  67. /// ExpressionType.Extension when overriding this method.
  68. /// </summary>
  69. /// <returns>The <see cref="ExpressionType"/> of the expression.</returns>
  70. protected override ExpressionType NodeTypeImpl() {
  71. return ExpressionType.Block;
  72. }
  73. /// <summary>
  74. /// Gets the static type of the expression that this <see cref="Expression" /> represents.
  75. /// </summary>
  76. /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
  77. protected override Type TypeImpl() {
  78. return GetExpression(ExpressionCount - 1).Type;
  79. }
  80. internal virtual Expression GetExpression(int index) {
  81. throw ContractUtils.Unreachable;
  82. }
  83. internal virtual int ExpressionCount {
  84. get {
  85. throw ContractUtils.Unreachable;
  86. }
  87. }
  88. internal virtual ReadOnlyCollection<Expression> GetOrMakeExpressions() {
  89. throw ContractUtils.Unreachable;
  90. }
  91. internal virtual ParameterExpression GetVariable(int index) {
  92. throw ContractUtils.Unreachable;
  93. }
  94. internal virtual int VariableCount {
  95. get {
  96. return 0;
  97. }
  98. }
  99. internal virtual ReadOnlyCollection<ParameterExpression> GetOrMakeVariables() {
  100. return EmptyReadOnlyCollection<ParameterExpression>.Instance;
  101. }
  102. /// <summary>
  103. /// Makes a copy of this node replacing the parameters/args with the provided values. The
  104. /// shape of the parameters/args needs to match the shape of the current block - in other
  105. /// words there should be the same # of parameters and args.
  106. ///
  107. /// parameters can be null in which case the existing parameters are used.
  108. ///
  109. /// This helper is provided to allow re-writing of nodes to not depend on the specific optimized
  110. /// subclass of BlockExpression which is being used.
  111. /// </summary>
  112. internal virtual BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
  113. throw ContractUtils.Unreachable;
  114. }
  115. /// <summary>
  116. /// Helper used for ensuring we only return 1 instance of a ReadOnlyCollection of T.
  117. ///
  118. /// This is similar to the ReturnReadOnly which only takes a single argument. This version
  119. /// supports nodes which hold onto 5 Expressions and puts all of the arguments into the
  120. /// ReadOnlyCollection.
  121. ///
  122. /// Ultimately this means if we create the readonly collection we will be slightly more wasteful as we'll
  123. /// have a readonly collection + some fields in the type. The DLR internally avoids accessing anything
  124. /// which would force the readonly collection to be created.
  125. ///
  126. /// This is used by BlockExpression5 and MethodCallExpression5.
  127. /// </summary>
  128. internal static ReadOnlyCollection<Expression> ReturnReadOnlyExpressions(BlockExpression provider, ref object collection) {
  129. Expression tObj = collection as Expression;
  130. if (tObj != null) {
  131. // otherwise make sure only one readonly collection ever gets exposed
  132. Interlocked.CompareExchange(
  133. ref collection,
  134. new ReadOnlyCollection<Expression>(new BlockExpressionList(provider, tObj)),
  135. tObj
  136. );
  137. }
  138. // and return what is not guaranteed to be a readonly collection
  139. return (ReadOnlyCollection<Expression>)collection;
  140. }
  141. }
  142. #region Specialized Subclasses
  143. internal sealed class Block2 : BlockExpression {
  144. private object _arg0; // storage for the 1st argument or a readonly collection. See IArgumentProvider
  145. private readonly Expression _arg1; // storage for the 2nd argument.
  146. internal Block2(Expression arg0, Expression arg1) {
  147. _arg0 = arg0;
  148. _arg1 = arg1;
  149. }
  150. internal override Expression GetExpression(int index) {
  151. switch (index) {
  152. case 0: return ReturnObject<Expression>(_arg0);
  153. case 1: return _arg1;
  154. default: throw new InvalidOperationException();
  155. }
  156. }
  157. internal override int ExpressionCount {
  158. get {
  159. return 2;
  160. }
  161. }
  162. internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
  163. return ReturnReadOnlyExpressions(this, ref _arg0);
  164. }
  165. internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
  166. Debug.Assert(args.Length == 2);
  167. Debug.Assert(variables == null || variables.Count == 0);
  168. return new Block2(args[0], args[1]);
  169. }
  170. }
  171. internal sealed class Block3 : BlockExpression {
  172. private object _arg0; // storage for the 1st argument or a readonly collection. See IArgumentProvider
  173. private readonly Expression _arg1, _arg2; // storage for the 2nd and 3rd arguments.
  174. internal Block3(Expression arg0, Expression arg1, Expression arg2) {
  175. _arg0 = arg0;
  176. _arg1 = arg1;
  177. _arg2 = arg2;
  178. }
  179. internal override Expression GetExpression(int index) {
  180. switch (index) {
  181. case 0: return ReturnObject<Expression>(_arg0);
  182. case 1: return _arg1;
  183. case 2: return _arg2;
  184. default: throw new InvalidOperationException();
  185. }
  186. }
  187. internal override int ExpressionCount {
  188. get {
  189. return 3;
  190. }
  191. }
  192. internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
  193. return ReturnReadOnlyExpressions(this, ref _arg0);
  194. }
  195. internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
  196. Debug.Assert(args.Length == 3);
  197. Debug.Assert(variables == null || variables.Count == 0);
  198. return new Block3(args[0], args[1], args[2]);
  199. }
  200. }
  201. internal sealed class Block4 : BlockExpression {
  202. private object _arg0; // storage for the 1st argument or a readonly collection. See IArgumentProvider
  203. private readonly Expression _arg1, _arg2, _arg3; // storarg for the 2nd, 3rd, and 4th arguments.
  204. internal Block4(Expression arg0, Expression arg1, Expression arg2, Expression arg3) {
  205. _arg0 = arg0;
  206. _arg1 = arg1;
  207. _arg2 = arg2;
  208. _arg3 = arg3;
  209. }
  210. internal override Expression GetExpression(int index) {
  211. switch (index) {
  212. case 0: return ReturnObject<Expression>(_arg0);
  213. case 1: return _arg1;
  214. case 2: return _arg2;
  215. case 3: return _arg3;
  216. default: throw new InvalidOperationException();
  217. }
  218. }
  219. internal override int ExpressionCount {
  220. get {
  221. return 4;
  222. }
  223. }
  224. internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
  225. return ReturnReadOnlyExpressions(this, ref _arg0);
  226. }
  227. internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
  228. Debug.Assert(args.Length == 4);
  229. Debug.Assert(variables == null || variables.Count == 0);
  230. return new Block4(args[0], args[1], args[2], args[3]);
  231. }
  232. }
  233. internal sealed class Block5 : BlockExpression {
  234. private object _arg0; // storage for the 1st argument or a readonly collection. See IArgumentProvider
  235. private readonly Expression _arg1, _arg2, _arg3, _arg4; // storage for the 2nd - 5th args.
  236. internal Block5(Expression arg0, Expression arg1, Expression arg2, Expression arg3, Expression arg4) {
  237. _arg0 = arg0;
  238. _arg1 = arg1;
  239. _arg2 = arg2;
  240. _arg3 = arg3;
  241. _arg4 = arg4;
  242. }
  243. internal override Expression GetExpression(int index) {
  244. switch (index) {
  245. case 0: return ReturnObject<Expression>(_arg0);
  246. case 1: return _arg1;
  247. case 2: return _arg2;
  248. case 3: return _arg3;
  249. case 4: return _arg4;
  250. default: throw new InvalidOperationException();
  251. }
  252. }
  253. internal override int ExpressionCount {
  254. get {
  255. return 5;
  256. }
  257. }
  258. internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
  259. return ReturnReadOnlyExpressions(this, ref _arg0);
  260. }
  261. internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
  262. Debug.Assert(args.Length == 5);
  263. Debug.Assert(variables == null || variables.Count == 0);
  264. return new Block5(args[0], args[1], args[2], args[3], args[4]);
  265. }
  266. }
  267. internal class BlockN : BlockExpression {
  268. private IList<Expression> _expressions; // either the original IList<Expression> or a ReadOnlyCollection if the user has accessed it.
  269. internal BlockN(IList<Expression> expressions) {
  270. Debug.Assert(expressions.Count != 0);
  271. _expressions = expressions;
  272. }
  273. internal override Expression GetExpression(int index) {
  274. Debug.Assert(index >= 0 && index < _expressions.Count);
  275. return _expressions[index];
  276. }
  277. internal override int ExpressionCount {
  278. get {
  279. return _expressions.Count;
  280. }
  281. }
  282. internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
  283. return ReturnReadOnly(ref _expressions);
  284. }
  285. internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
  286. Debug.Assert(variables == null || variables.Count == 0);
  287. return new BlockN(args);
  288. }
  289. }
  290. internal class ScopeExpression : BlockExpression {
  291. private IList<ParameterExpression> _variables; // list of variables or ReadOnlyCollection if the user has accessed the readonly collection
  292. internal ScopeExpression(IList<ParameterExpression> variables) {
  293. _variables = variables;
  294. }
  295. internal override int VariableCount {
  296. get {
  297. return _variables.Count;
  298. }
  299. }
  300. internal override ParameterExpression GetVariable(int index) {
  301. return _variables[index];
  302. }
  303. internal override ReadOnlyCollection<ParameterExpression> GetOrMakeVariables() {
  304. return ReturnReadOnly(ref _variables);
  305. }
  306. protected IList<ParameterExpression> VariablesList {
  307. get {
  308. return _variables;
  309. }
  310. }
  311. // Used for rewrite of the nodes to either reuse existing set of variables if not rewritten.
  312. internal IList<ParameterExpression> ReuseOrValidateVariables(ReadOnlyCollection<ParameterExpression> variables) {
  313. if (variables != null && variables != VariablesList) {
  314. // Need to validate the new variables (uniqueness, not byref)
  315. ValidateVariables(variables, "variables");
  316. return variables;
  317. } else {
  318. return VariablesList;
  319. }
  320. }
  321. }
  322. internal sealed class Scope1 : ScopeExpression {
  323. private object _body;
  324. internal Scope1(IList<ParameterExpression> variables, Expression body)
  325. : base(variables) {
  326. _body = body;
  327. }
  328. internal override Expression GetExpression(int index) {
  329. switch (index) {
  330. case 0: return ReturnObject<Expression>(_body);
  331. default: throw new InvalidOperationException();
  332. }
  333. }
  334. internal override int ExpressionCount {
  335. get {
  336. return 1;
  337. }
  338. }
  339. internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
  340. return ReturnReadOnlyExpressions(this, ref _body);
  341. }
  342. internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
  343. Debug.Assert(args.Length == 1);
  344. Debug.Assert(variables == null || variables.Count == VariableCount);
  345. return new Scope1(ReuseOrValidateVariables(variables), args[0]);
  346. }
  347. }
  348. internal class ScopeN : ScopeExpression {
  349. private IList<Expression> _body;
  350. internal ScopeN(IList<ParameterExpression> variables, IList<Expression> body)
  351. : base(variables) {
  352. _body = body;
  353. }
  354. internal override Expression GetExpression(int index) {
  355. return _body[index];
  356. }
  357. internal override int ExpressionCount {
  358. get {
  359. return _body.Count;
  360. }
  361. }
  362. internal override ReadOnlyCollection<Expression> GetOrMakeExpressions() {
  363. return ReturnReadOnly(ref _body);
  364. }
  365. internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
  366. Debug.Assert(args.Length == ExpressionCount);
  367. Debug.Assert(variables == null || variables.Count == VariableCount);
  368. return new ScopeN(ReuseOrValidateVariables(variables), args);
  369. }
  370. }
  371. internal class ScopeWithType : ScopeN {
  372. private readonly Type _type;
  373. internal ScopeWithType(IList<ParameterExpression> variables, IList<Expression> expressions, Type type)
  374. : base(variables, expressions) {
  375. _type = type;
  376. }
  377. protected override Type TypeImpl() {
  378. return _type;
  379. }
  380. internal override BlockExpression Rewrite(ReadOnlyCollection<ParameterExpression> variables, Expression[] args) {
  381. Debug.Assert(args.Length == ExpressionCount);
  382. Debug.Assert(variables == null || variables.Count == VariableCount);
  383. return new ScopeWithType(ReuseOrValidateVariables(variables), args, _type);
  384. }
  385. }
  386. #endregion
  387. #region Block List Classes
  388. /// <summary>
  389. /// Provides a wrapper around an IArgumentProvider which exposes the argument providers
  390. /// members out as an IList of Expression. This is used to avoid allocating an array
  391. /// which needs to be stored inside of a ReadOnlyCollection. Instead this type has
  392. /// the same amount of overhead as an array without duplicating the storage of the
  393. /// elements. This ensures that internally we can avoid creating and copying arrays
  394. /// while users of the Expression trees also don't pay a size penalty for this internal
  395. /// optimization. See IArgumentProvider for more general information on the Expression
  396. /// tree optimizations being used here.
  397. /// </summary>
  398. internal class BlockExpressionList : IList<Expression> {
  399. private readonly BlockExpression _block;
  400. private readonly Expression _arg0;
  401. internal BlockExpressionList(BlockExpression provider, Expression arg0) {
  402. _block = provider;
  403. _arg0 = arg0;
  404. }
  405. #region IList<Expression> Members
  406. public int IndexOf(Expression item) {
  407. if (_arg0 == item) {
  408. return 0;
  409. }
  410. for (int i = 1; i < _block.ExpressionCount; i++) {
  411. if (_block.GetExpression(i) == item) {
  412. return i;
  413. }
  414. }
  415. return -1;
  416. }
  417. public void Insert(int index, Expression item) {
  418. throw ContractUtils.Unreachable;
  419. }
  420. public void RemoveAt(int index) {
  421. throw ContractUtils.Unreachable;
  422. }
  423. public Expression this[int index] {
  424. get {
  425. if (index == 0) {
  426. return _arg0;
  427. }
  428. return _block.GetExpression(index);
  429. }
  430. set {
  431. throw ContractUtils.Unreachable;
  432. }
  433. }
  434. #endregion
  435. #region ICollection<Expression> Members
  436. public void Add(Expression item) {
  437. throw ContractUtils.Unreachable;
  438. }
  439. public void Clear() {
  440. throw ContractUtils.Unreachable;
  441. }
  442. public bool Contains(Expression item) {
  443. return IndexOf(item) != -1;
  444. }
  445. public void CopyTo(Expression[] array, int arrayIndex) {
  446. array[arrayIndex++] = _arg0;
  447. for (int i = 1; i < _block.ExpressionCount; i++) {
  448. array[arrayIndex++] = _block.GetExpression(i);
  449. }
  450. }
  451. public int Count {
  452. get { return _block.ExpressionCount; }
  453. }
  454. public bool IsReadOnly {
  455. get { return true; }
  456. }
  457. public bool Remove(Expression item) {
  458. throw ContractUtils.Unreachable;
  459. }
  460. #endregion
  461. #region IEnumerable<Expression> Members
  462. public IEnumerator<Expression> GetEnumerator() {
  463. yield return _arg0;
  464. for (int i = 1; i < _block.ExpressionCount; i++) {
  465. yield return _block.GetExpression(i);
  466. }
  467. }
  468. #endregion
  469. #region IEnumerable Members
  470. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
  471. yield return _arg0;
  472. for (int i = 1; i < _block.ExpressionCount; i++) {
  473. yield return _block.GetExpression(i);
  474. }
  475. }
  476. #endregion
  477. }
  478. #endregion
  479. public partial class Expression {
  480. /// <summary>
  481. /// Creates a <see cref="BlockExpression"/> that contains two expressions and has no variables.
  482. /// </summary>
  483. /// <param name="arg0">The first expression in the block.</param>
  484. /// <param name="arg1">The second expression in the block.</param>
  485. /// <returns>The created <see cref="BlockExpression"/>.</returns>
  486. public static BlockExpression Block(Expression arg0, Expression arg1) {
  487. RequiresCanRead(arg0, "arg0");
  488. RequiresCanRead(arg1, "arg1");
  489. return new Block2(arg0, arg1);
  490. }
  491. /// <summary>
  492. /// Creates a <see cref="BlockExpression"/> that contains three expressions and has no variables.
  493. /// </summary>
  494. /// <param name="arg0">The first expression in the block.</param>
  495. /// <param name="arg1">The second expression in the block.</param>
  496. /// <param name="arg2">The third expression in the block.</param>
  497. /// <returns>The created <see cref="BlockExpression"/>.</returns>
  498. public static BlockExpression Block(Expression arg0, Expression arg1, Expression arg2) {
  499. RequiresCanRead(arg0, "arg0");
  500. RequiresCanRead(arg1, "arg1");
  501. RequiresCanRead(arg2, "arg2");
  502. return new Block3(arg0, arg1, arg2);
  503. }
  504. /// <summary>
  505. /// Creates a <see cref="BlockExpression"/> that contains four expressions and has no variables.
  506. /// </summary>
  507. /// <param name="arg0">The first expression in the block.</param>
  508. /// <param name="arg1">The second expression in the block.</param>
  509. /// <param name="arg2">The third expression in the block.</param>
  510. /// <param name="arg3">The fourth expression in the block.</param>
  511. /// <returns>The created <see cref="BlockExpression"/>.</returns>
  512. public static BlockExpression Block(Expression arg0, Expression arg1, Expression arg2, Expression arg3) {
  513. RequiresCanRead(arg0, "arg0");
  514. RequiresCanRead(arg1, "arg1");
  515. RequiresCanRead(arg2, "arg2");
  516. RequiresCanRead(arg3, "arg3");
  517. return new Block4(arg0, arg1, arg2, arg3);
  518. }
  519. /// <summary>
  520. /// Creates a <see cref="BlockExpression"/> that contains five expressions and has no variables.
  521. /// </summary>
  522. /// <param name="arg0">The first expression in the block.</param>
  523. /// <param name="arg1">The second expression in the block.</param>
  524. /// <param name="arg2">The third expression in the block.</param>
  525. /// <param name="arg3">The fourth expression in the block.</param>
  526. /// <param name="arg4">The fifth expression in the block.</param>
  527. /// <returns>The created <see cref="BlockExpression"/>.</returns>
  528. public static BlockExpression Block(Expression arg0, Expression arg1, Expression arg2, Expression arg3, Expression arg4) {
  529. RequiresCanRead(arg0, "arg0");
  530. RequiresCanRead(arg1, "arg1");
  531. RequiresCanRead(arg2, "arg2");
  532. RequiresCanRead(arg3, "arg3");
  533. RequiresCanRead(arg4, "arg4");
  534. return new Block5(arg0, arg1, arg2, arg3, arg4);
  535. }
  536. /// <summary>
  537. /// Creates a <see cref="BlockExpression"/> that contains the given expressions and has no variables.
  538. /// </summary>
  539. /// <param name="expressions">The expressions in the block.</param>
  540. /// <returns>The created <see cref="BlockExpression"/>.</returns>
  541. public static BlockExpression Block(params Expression[] expressions) {
  542. ContractUtils.RequiresNotNull(expressions, "expressions");
  543. switch (expressions.Length) {
  544. case 2: return Block(expressions[0], expressions[1]);
  545. case 3: return Block(expressions[0], expressions[1], expressions[2]);
  546. case 4: return Block(expressions[0], expressions[1], expressions[2], expressions[3]);
  547. case 5: return Block(expressions[0], expressions[1], expressions[2], expressions[3], expressions[4]);
  548. default:
  549. ContractUtils.RequiresNotEmpty(expressions, "expressions");
  550. RequiresCanRead(expressions, "expressions");
  551. return new BlockN(expressions.Copy());
  552. }
  553. }
  554. /// <summary>
  555. /// Creates a <see cref="BlockExpression"/> that contains the given expressions and has no variables.
  556. /// </summary>
  557. /// <param name="expressions">The expressions in the block.</param>
  558. /// <returns>The created <see cref="BlockExpression"/>.</returns>
  559. public static BlockExpression Block(IEnumerable<Expression> expressions) {
  560. return Block(EmptyReadOnlyCollection<ParameterExpression>.Instance, expressions);
  561. }
  562. /// <summary>
  563. /// Creates a <see cref="BlockExpression"/> that contains the given expressions, has no variables and has specific result type.
  564. /// </summary>
  565. /// <param name="type">The result type of the block.</param>
  566. /// <param name="expressions">The expressions in the block.</param>
  567. /// <returns>The created <see cref="BlockExpression"/>.</returns>
  568. public static BlockExpression Block(Type type, params Expression[] expressions) {
  569. ContractUtils.RequiresNotNull(expressions, "expressions");
  570. return Block(type, (IEnumerable<Expression>)expressions);
  571. }
  572. /// <summary>
  573. /// Creates a <see cref="BlockExpression"/> that contains the given expressions, has no variables and has specific result type.
  574. /// </summary>
  575. /// <param name="type">The result type of the block.</param>
  576. /// <param name="expressions">The expressions in the block.</param>
  577. /// <returns>The created <see cref="BlockExpression"/>.</returns>
  578. public static BlockExpression Block(Type type, IEnumerable<Expression> expressions) {
  579. return Block(type, EmptyReadOnlyCollection<ParameterExpression>.Instance, expressions);
  580. }
  581. /// <summary>
  582. /// Creates a <see cref="BlockExpression"/> that contains the given variables and expressions.
  583. /// </summary>
  584. /// <param name="variables">The variables in the block.</param>
  585. /// <param name="expressions">The expressions in the block.</param>
  586. /// <returns>The created <see cref="BlockExpression"/>.</returns>
  587. public static BlockExpression Block(IEnumerable<ParameterExpression> variables, params Expression[] expressions) {
  588. return Block(variables, (IEnumerable<Expression>)expressions);
  589. }
  590. /// <summary>
  591. /// Creates a <see cref="BlockExpression"/> that contains the given variables and expressions.
  592. /// </summary>
  593. /// <param name="type">The result type of the block.</param>
  594. /// <param name="variables">The variables in the block.</param>
  595. /// <param name="expressions">The expressions in the block.</param>
  596. /// <returns>The created <see cref="BlockExpression"/>.</returns>
  597. public static BlockExpression Block(Type type, IEnumerable<ParameterExpression> variables, params Expression[] expressions) {
  598. return Block(type, variables, (IEnumerable<Expression>)expressions);
  599. }
  600. /// <summary>
  601. /// Creates a <see cref="BlockExpression"/> that contains the given variables and expressions.
  602. /// </summary>
  603. /// <param name="variables">The variables in the block.</param>
  604. /// <param name="expressions">The expressions in the block.</param>
  605. /// <returns>The created <see cref="BlockExpression"/>.</returns>
  606. public static BlockExpression Block(IEnumerable<ParameterExpression> variables, IEnumerable<Expression> expressions) {
  607. ContractUtils.RequiresNotNull(expressions, "expressions");
  608. var expressionList = expressions.ToReadOnly();
  609. ContractUtils.RequiresNotEmpty(expressionList, "expressions");
  610. RequiresCanRead(expressionList, "expressions");
  611. return Block(expressionList.Last().Type, variables, expressionList);
  612. }
  613. /// <summary>
  614. /// Creates a <see cref="BlockExpression"/> that contains the given variables and expressions.
  615. /// </summary>
  616. /// <param name="type">The result type of the block.</param>
  617. /// <param name="variables">The variables in the block.</param>
  618. /// <param name="expressions">The expressions in the block.</param>
  619. /// <returns>The created <see cref="BlockExpression"/>.</returns>
  620. public static BlockExpression Block(Type type, IEnumerable<ParameterExpression> variables, IEnumerable<Expression> expressions) {
  621. ContractUtils.RequiresNotNull(type, "type");
  622. ContractUtils.RequiresNotNull(expressions, "expressions");
  623. var expressionList = expressions.ToReadOnly();
  624. var variableList = variables.ToReadOnly();
  625. ContractUtils.RequiresNotEmpty(expressionList, "expressions");
  626. RequiresCanRead(expressionList, "expressions");
  627. ValidateVariables(variableList, "variables");
  628. Expression last = expressionList.Last();
  629. if (type != typeof(void)) {
  630. if (!TypeUtils.AreReferenceAssignable(type, last.Type)) {
  631. throw Error.ArgumentTypesMustMatch();
  632. }
  633. }
  634. if (type != last.Type) {
  635. return new ScopeWithType(variableList, expressionList, type);
  636. } else {
  637. if (expressionList.Count == 1) {
  638. return new Scope1(variableList, expressionList[0]);
  639. } else {
  640. return new ScopeN(variableList, expressionList);
  641. }
  642. }
  643. }
  644. // Checks that all variables are non-null, not byref, and unique.
  645. internal static void ValidateVariables(ReadOnlyCollection<ParameterExpression> varList, string collectionName) {
  646. if (varList.Count == 0) {
  647. return;
  648. }
  649. int count = varList.Count;
  650. var set = new Set<ParameterExpression>(count);
  651. for (int i = 0; i < count; i++) {
  652. ParameterExpression v = varList[i];
  653. if (v == null) {
  654. throw new ArgumentNullException(string.Format(System.Globalization.CultureInfo.CurrentCulture, "{0}[{1}]", collectionName, set.Count));
  655. }
  656. if (v.IsByRef) {
  657. throw Error.VariableMustNotBeByRef(v, v.Type);
  658. }
  659. if (set.Contains(v)) {
  660. throw Error.DuplicateVariable(v);
  661. }
  662. set.Add(v);
  663. }
  664. }
  665. }
  666. }