PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.Core/System.Linq.jvm/ExpressionInterpreter.cs

https://bitbucket.org/danipen/mono
C# | 937 lines | 738 code | 173 blank | 26 comment | 97 complexity | 11819ed32304e57d3de1397cb59ad473 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //
  2. // ExpressionInterpreter.cs
  3. //
  4. // (C) 2008 Mainsoft, Inc. (http://www.mainsoft.com)
  5. // (C) 2008 db4objects, Inc. (http://www.db4o.com)
  6. // (C) 2010 Novell, Inc. (http://www.novell.com)
  7. //
  8. // Permission is hereby granted, free of charge, to any person obtaining
  9. // a copy of this software and associated documentation files (the
  10. // "Software"), to deal in the Software without restriction, including
  11. // without limitation the rights to use, copy, modify, merge, publish,
  12. // distribute, sublicense, and/or sell copies of the Software, and to
  13. // permit persons to whom the Software is furnished to do so, subject to
  14. // the following conditions:
  15. //
  16. // The above copyright notice and this permission notice shall be
  17. // included in all copies or substantial portions of the Software.
  18. //
  19. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  20. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  22. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  23. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  24. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  25. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26. //
  27. using System.Collections.Generic;
  28. using System.Collections.ObjectModel;
  29. using System.Linq.Expressions;
  30. using System.Reflection;
  31. namespace System.Linq.jvm {
  32. struct LambdaInfo {
  33. public readonly LambdaExpression Lambda;
  34. public readonly object [] Arguments;
  35. public LambdaInfo (LambdaExpression lambda, object [] arguments)
  36. {
  37. this.Lambda = lambda;
  38. this.Arguments = arguments;
  39. }
  40. }
  41. class HoistedVariableDetector : ExpressionVisitor {
  42. readonly Dictionary<ParameterExpression, LambdaExpression> parameter_to_lambda =
  43. new Dictionary<ParameterExpression, LambdaExpression> ();
  44. Dictionary<LambdaExpression, List<ParameterExpression>> hoisted_map;
  45. LambdaExpression lambda;
  46. public Dictionary<LambdaExpression, List<ParameterExpression>> Process (LambdaExpression lambda)
  47. {
  48. Visit (lambda);
  49. return hoisted_map;
  50. }
  51. protected override void VisitLambda (LambdaExpression lambda)
  52. {
  53. this.lambda = lambda;
  54. foreach (var parameter in lambda.Parameters)
  55. parameter_to_lambda [parameter] = lambda;
  56. base.VisitLambda (lambda);
  57. }
  58. protected override void VisitParameter (ParameterExpression parameter)
  59. {
  60. if (lambda.Parameters.Contains (parameter))
  61. return;
  62. Hoist (parameter);
  63. }
  64. void Hoist (ParameterExpression parameter)
  65. {
  66. LambdaExpression lambda;
  67. if (!parameter_to_lambda.TryGetValue (parameter, out lambda))
  68. return;
  69. if (hoisted_map == null)
  70. hoisted_map = new Dictionary<LambdaExpression, List<ParameterExpression>> ();
  71. List<ParameterExpression> hoisted;
  72. if (!hoisted_map.TryGetValue (lambda, out hoisted)) {
  73. hoisted = new List<ParameterExpression> ();
  74. hoisted_map [lambda] = hoisted;
  75. }
  76. hoisted.Add (parameter);
  77. }
  78. }
  79. class ExpressionInterpreter : ExpressionVisitor {
  80. readonly Stack<LambdaInfo> lambdas = new Stack<LambdaInfo> ();
  81. readonly Stack<object> stack = new Stack<object> ();
  82. readonly Dictionary<LambdaExpression, List<ParameterExpression>> hoisted_map;
  83. readonly Dictionary<ParameterExpression, object> hoisted_values;
  84. void Push (object value)
  85. {
  86. stack.Push (value);
  87. }
  88. object Pop ()
  89. {
  90. return stack.Pop ();
  91. }
  92. public ExpressionInterpreter (LambdaExpression lambda)
  93. {
  94. hoisted_map = new HoistedVariableDetector ().Process (lambda);
  95. if (hoisted_map != null)
  96. hoisted_values = new Dictionary<ParameterExpression, object> ();
  97. }
  98. private void VisitCoalesce (BinaryExpression binary)
  99. {
  100. Visit (binary.Left);
  101. var left = Pop ();
  102. if (left == null) {
  103. Visit (binary.Right);
  104. return;
  105. }
  106. if (binary.Conversion == null) {
  107. Push (left);
  108. return;
  109. }
  110. Push (Invoke (binary.Conversion.Compile (this), new [] { left }));
  111. }
  112. void VisitAndAlso (BinaryExpression binary)
  113. {
  114. object left = null;
  115. object right = null;
  116. Visit (binary.Left);
  117. left = Pop ();
  118. if (left == null || ((bool) left)) {
  119. Visit (binary.Right);
  120. right = Pop ();
  121. }
  122. Push (Math.And (left, right));
  123. }
  124. void VisitUserDefinedAndAlso (BinaryExpression binary)
  125. {
  126. object left = null;
  127. object right = null;
  128. Visit (binary.Left);
  129. left = Pop ();
  130. if (InvokeFalseOperator (binary, left)) {
  131. Push (left);
  132. return;
  133. }
  134. Visit (binary.Right);
  135. right = Pop ();
  136. if (binary.IsLiftedToNull && right == null) {
  137. Push (null);
  138. return;
  139. }
  140. Push (InvokeMethod (binary.Method, null, new [] { left, right }));
  141. }
  142. static bool InvokeTrueOperator (BinaryExpression binary, object target)
  143. {
  144. return (bool) InvokeMethod (GetTrueOperator (binary), null, new [] { target });
  145. }
  146. static bool InvokeFalseOperator (BinaryExpression binary, object target)
  147. {
  148. return (bool) InvokeMethod (GetFalseOperator (binary), null, new [] { target });
  149. }
  150. static MethodInfo GetFalseOperator (BinaryExpression binary)
  151. {
  152. return Expression.GetFalseOperator (binary.Left.Type.GetNotNullableType ());
  153. }
  154. static MethodInfo GetTrueOperator (BinaryExpression binary)
  155. {
  156. return Expression.GetTrueOperator (binary.Left.Type.GetNotNullableType ());
  157. }
  158. void VisitOrElse (BinaryExpression binary)
  159. {
  160. object left = null;
  161. object right = null;
  162. Visit (binary.Left);
  163. left = Pop ();
  164. if (left == null || !((bool) left)) {
  165. Visit (binary.Right);
  166. right = Pop ();
  167. }
  168. Push (Math.Or (left, right));
  169. }
  170. void VisitUserDefinedOrElse (BinaryExpression binary)
  171. {
  172. object left = null;
  173. object right = null;
  174. Visit (binary.Left);
  175. left = Pop ();
  176. if (InvokeTrueOperator (binary, left)) {
  177. Push (left);
  178. return;
  179. }
  180. Visit (binary.Right);
  181. right = Pop ();
  182. if (binary.IsLiftedToNull && right == null) {
  183. Push (null);
  184. return;
  185. }
  186. Push (InvokeMethod (binary.Method, null, new [] { left, right }));
  187. }
  188. void VisitLogicalBinary (BinaryExpression binary)
  189. {
  190. Visit (binary.Left);
  191. Visit (binary.Right);
  192. var right = Pop ();
  193. var left = Pop ();
  194. Push (Math.Evaluate (left, right, binary.Type, binary.NodeType));
  195. }
  196. void VisitArithmeticBinary (BinaryExpression binary)
  197. {
  198. Visit (binary.Left);
  199. Visit (binary.Right);
  200. if (IsNullBinaryLifting (binary))
  201. return;
  202. var right = Pop ();
  203. var left = Pop ();
  204. switch (binary.NodeType) {
  205. case ExpressionType.RightShift:
  206. Push (Math.RightShift (left, Convert.ToInt32 (right), Type.GetTypeCode (binary.Type.GetNotNullableType ())));
  207. return;
  208. case ExpressionType.LeftShift:
  209. Push (Math.LeftShift (left, Convert.ToInt32 (right), Type.GetTypeCode (binary.Type.GetNotNullableType ())));
  210. return;
  211. default:
  212. Push (Math.Evaluate (left, right, binary.Type, binary.NodeType));
  213. break;
  214. }
  215. }
  216. bool IsNullRelationalBinaryLifting (BinaryExpression binary)
  217. {
  218. var right = Pop ();
  219. var left = Pop ();
  220. if (binary.IsLifted && (left == null || right == null)) {
  221. if (binary.IsLiftedToNull) {
  222. Push (null);
  223. return true;
  224. }
  225. switch (binary.NodeType) {
  226. case ExpressionType.Equal:
  227. Push (BinaryEqual (binary, left, right));
  228. break;
  229. case ExpressionType.NotEqual:
  230. Push (BinaryNotEqual (binary, left, right));
  231. break;
  232. default:
  233. Push (false);
  234. break;
  235. }
  236. return true;
  237. }
  238. Push (left);
  239. Push (right);
  240. return false;
  241. }
  242. void VisitRelationalBinary (BinaryExpression binary)
  243. {
  244. Visit (binary.Left);
  245. Visit (binary.Right);
  246. if (IsNullRelationalBinaryLifting (binary))
  247. return;
  248. var right = Pop ();
  249. var left = Pop ();
  250. switch (binary.NodeType) {
  251. case ExpressionType.Equal:
  252. Push (BinaryEqual (binary, left, right));
  253. return;
  254. case ExpressionType.NotEqual:
  255. Push (BinaryNotEqual (binary, left, right));
  256. return;
  257. case ExpressionType.LessThan:
  258. Push (Comparer<object>.Default.Compare (left, right) < 0);
  259. return;
  260. case ExpressionType.LessThanOrEqual:
  261. Push (Comparer<object>.Default.Compare (left, right) <= 0);
  262. return;
  263. case ExpressionType.GreaterThan:
  264. Push (Comparer<object>.Default.Compare (left, right) > 0);
  265. return;
  266. case ExpressionType.GreaterThanOrEqual:
  267. Push (Comparer<object>.Default.Compare (left, right) >= 0);
  268. return;
  269. }
  270. }
  271. void VisitLogicalShortCircuitBinary (BinaryExpression binary)
  272. {
  273. switch (binary.NodeType) {
  274. case ExpressionType.AndAlso:
  275. VisitAndAlso (binary);
  276. return;
  277. case ExpressionType.OrElse:
  278. VisitOrElse (binary);
  279. return;
  280. }
  281. }
  282. void VisitArrayIndex (BinaryExpression binary)
  283. {
  284. Visit (binary.Left);
  285. var left = Pop ();
  286. Visit (binary.Right);
  287. var right = Pop ();
  288. Push (((Array) left).GetValue ((int) right));
  289. }
  290. bool IsNullBinaryLifting (BinaryExpression binary)
  291. {
  292. var right = Pop ();
  293. var left = Pop ();
  294. if (binary.IsLifted && (right == null || left == null)) {
  295. if (binary.IsLiftedToNull)
  296. Push (null);
  297. else
  298. Push (GetDefaultValue (binary.Type));
  299. return true;
  300. }
  301. Push (left);
  302. Push (right);
  303. return false;
  304. }
  305. static object GetDefaultValue (Type type)
  306. {
  307. var array = (Array) Array.CreateInstance (type, 1);
  308. return array.GetValue (0);
  309. }
  310. void VisitUserDefinedBinary (BinaryExpression binary)
  311. {
  312. switch (binary.NodeType) {
  313. case ExpressionType.AndAlso:
  314. case ExpressionType.OrElse:
  315. VisitUserDefinedLogicalShortCircuitBinary (binary);
  316. return;
  317. case ExpressionType.Equal:
  318. case ExpressionType.NotEqual:
  319. VisitUserDefinedRelationalBinary (binary);
  320. return;
  321. default:
  322. VisitUserDefinedCommonBinary (binary);
  323. return;
  324. }
  325. }
  326. void VisitUserDefinedLogicalShortCircuitBinary (BinaryExpression binary)
  327. {
  328. switch (binary.NodeType) {
  329. case ExpressionType.AndAlso:
  330. VisitUserDefinedAndAlso (binary);
  331. return;
  332. case ExpressionType.OrElse:
  333. VisitUserDefinedOrElse (binary);
  334. return;
  335. }
  336. }
  337. void VisitUserDefinedRelationalBinary (BinaryExpression binary)
  338. {
  339. Visit (binary.Left);
  340. Visit (binary.Right);
  341. if (IsNullRelationalBinaryLifting (binary))
  342. return;
  343. var right = Pop ();
  344. var left = Pop ();
  345. Push (InvokeBinary (binary, left, right));
  346. }
  347. void VisitUserDefinedCommonBinary (BinaryExpression binary)
  348. {
  349. Visit (binary.Left);
  350. Visit (binary.Right);
  351. if (IsNullBinaryLifting (binary))
  352. return;
  353. var right = Pop ();
  354. var left = Pop ();
  355. Push (InvokeBinary (binary, left, right));
  356. }
  357. object InvokeBinary (BinaryExpression binary, object left, object right)
  358. {
  359. return InvokeMethod (binary.Method, null, new [] { left, right });
  360. }
  361. bool BinaryEqual (BinaryExpression binary, object left, object right)
  362. {
  363. if (typeof (ValueType).IsAssignableFrom (binary.Right.Type))
  364. return ValueType.Equals (left, right);
  365. else
  366. return left == right;
  367. }
  368. bool BinaryNotEqual (BinaryExpression binary, object left, object right)
  369. {
  370. if (typeof (ValueType).IsAssignableFrom (binary.Right.Type))
  371. return !ValueType.Equals (left, right);
  372. else
  373. return left != right;
  374. }
  375. protected override void VisitBinary (BinaryExpression binary)
  376. {
  377. if (binary.Method != null) {
  378. VisitUserDefinedBinary (binary);
  379. return;
  380. }
  381. switch (binary.NodeType) {
  382. case ExpressionType.ArrayIndex:
  383. VisitArrayIndex (binary);
  384. return;
  385. case ExpressionType.Coalesce:
  386. VisitCoalesce (binary);
  387. return;
  388. case ExpressionType.AndAlso:
  389. case ExpressionType.OrElse:
  390. VisitLogicalShortCircuitBinary (binary);
  391. return;
  392. case ExpressionType.Equal:
  393. case ExpressionType.NotEqual:
  394. case ExpressionType.GreaterThan:
  395. case ExpressionType.GreaterThanOrEqual:
  396. case ExpressionType.LessThan:
  397. case ExpressionType.LessThanOrEqual:
  398. VisitRelationalBinary (binary);
  399. return;
  400. case ExpressionType.And:
  401. case ExpressionType.Or:
  402. VisitLogicalBinary (binary);
  403. return;
  404. case ExpressionType.Power:
  405. case ExpressionType.Add:
  406. case ExpressionType.AddChecked:
  407. case ExpressionType.Divide:
  408. case ExpressionType.ExclusiveOr:
  409. case ExpressionType.LeftShift:
  410. case ExpressionType.Modulo:
  411. case ExpressionType.Multiply:
  412. case ExpressionType.MultiplyChecked:
  413. case ExpressionType.RightShift:
  414. case ExpressionType.Subtract:
  415. case ExpressionType.SubtractChecked:
  416. VisitArithmeticBinary (binary);
  417. return;
  418. }
  419. }
  420. void VisitTypeAs (UnaryExpression unary)
  421. {
  422. Visit (unary.Operand);
  423. var value = Pop ();
  424. if (value == null || !Math.IsType (unary.Type, value))
  425. Push (null);
  426. else
  427. Push (value);
  428. }
  429. void VisitArrayLength (UnaryExpression unary)
  430. {
  431. Visit (unary.Operand);
  432. var array = (Array) Pop ();
  433. Push (array.Length);
  434. }
  435. void VisitConvert (UnaryExpression unary)
  436. {
  437. if (unary.NodeType == ExpressionType.ConvertChecked)
  438. VisitConvertChecked (unary);
  439. else
  440. VisitConvertUnchecked (unary);
  441. }
  442. void VisitConvertChecked (UnaryExpression unary)
  443. {
  444. VisitConvert (unary, Math.ConvertToTypeChecked);
  445. }
  446. void VisitConvertUnchecked (UnaryExpression unary)
  447. {
  448. VisitConvert (unary, Math.ConvertToTypeUnchecked);
  449. }
  450. void VisitConvert (UnaryExpression unary, Func<object, Type, Type, object> converter)
  451. {
  452. Visit (unary.Operand);
  453. Push (converter (Pop (), unary.Operand.Type, unary.Type));
  454. }
  455. bool IsNullUnaryLifting (UnaryExpression unary)
  456. {
  457. var value = Pop ();
  458. if (unary.IsLifted && value == null) {
  459. if (unary.IsLiftedToNull) {
  460. Push (null);
  461. return true;
  462. } else {
  463. throw new InvalidOperationException ();
  464. }
  465. }
  466. Push (value);
  467. return false;
  468. }
  469. void VisitQuote (UnaryExpression unary)
  470. {
  471. Push (unary.Operand);
  472. }
  473. void VisitUserDefinedUnary (UnaryExpression unary)
  474. {
  475. Visit (unary.Operand);
  476. if (IsNullUnaryLifting (unary))
  477. return;
  478. var value = Pop ();
  479. Push (InvokeUnary (unary, value));
  480. }
  481. object InvokeUnary (UnaryExpression unary, object value)
  482. {
  483. return InvokeMethod (unary.Method, null, new [] { value });
  484. }
  485. void VisitArithmeticUnary (UnaryExpression unary)
  486. {
  487. Visit (unary.Operand);
  488. if (IsNullUnaryLifting (unary))
  489. return;
  490. var value = Pop ();
  491. switch (unary.NodeType) {
  492. case ExpressionType.Not:
  493. if (unary.Type.GetNotNullableType () == typeof (bool))
  494. Push (!Convert.ToBoolean (value));
  495. else
  496. Push (~Convert.ToInt32 (value));
  497. return;
  498. case ExpressionType.Negate:
  499. Push (Math.Negate (value, Type.GetTypeCode (unary.Type.GetNotNullableType ())));
  500. return;
  501. case ExpressionType.NegateChecked:
  502. Push (Math.NegateChecked (value, Type.GetTypeCode (unary.Type.GetNotNullableType ())));
  503. return;
  504. case ExpressionType.UnaryPlus:
  505. Push (value);
  506. return;
  507. }
  508. }
  509. protected override void VisitUnary (UnaryExpression unary)
  510. {
  511. if (unary.Method != null) {
  512. VisitUserDefinedUnary (unary);
  513. return;
  514. }
  515. switch (unary.NodeType) {
  516. case ExpressionType.Quote:
  517. VisitQuote (unary);
  518. return;
  519. case ExpressionType.TypeAs:
  520. VisitTypeAs (unary);
  521. return;
  522. case ExpressionType.ArrayLength:
  523. VisitArrayLength (unary);
  524. return;
  525. case ExpressionType.Convert:
  526. case ExpressionType.ConvertChecked:
  527. VisitConvert (unary);
  528. return;
  529. case ExpressionType.Negate:
  530. case ExpressionType.NegateChecked:
  531. case ExpressionType.Not:
  532. case ExpressionType.UnaryPlus:
  533. VisitArithmeticUnary (unary);
  534. return;
  535. default:
  536. throw new NotImplementedException (unary.NodeType.ToString ());
  537. }
  538. }
  539. protected override void VisitNew (NewExpression nex)
  540. {
  541. if (nex.Constructor == null)
  542. Push (Activator.CreateInstance (nex.Type));
  543. else
  544. Push (InvokeConstructor (nex.Constructor, VisitListExpressions (nex.Arguments)));
  545. }
  546. static object InvokeConstructor (ConstructorInfo constructor, object [] arguments)
  547. {
  548. try {
  549. return constructor.Invoke (arguments);
  550. } catch (TargetInvocationException e) {
  551. throw e.InnerException;
  552. }
  553. }
  554. protected override void VisitTypeIs (TypeBinaryExpression type)
  555. {
  556. Visit (type.Expression);
  557. Push (Math.IsType (type.TypeOperand, Pop ()));
  558. }
  559. void VisitMemberInfo (MemberInfo mi)
  560. {
  561. mi.OnFieldOrProperty (
  562. field => {
  563. object target = null;
  564. if (!field.IsStatic)
  565. target = Pop ();
  566. Push (field.GetValue (target));
  567. },
  568. property => {
  569. object target = null;
  570. var getter = property.GetGetMethod (true);
  571. if (!getter.IsStatic)
  572. target = Pop ();
  573. Push (property.GetValue (target, null));
  574. });
  575. }
  576. protected override void VisitMemberAccess (MemberExpression member)
  577. {
  578. Visit (member.Expression);
  579. VisitMemberInfo (member.Member);
  580. }
  581. protected override void VisitNewArray (NewArrayExpression newArray)
  582. {
  583. switch (newArray.NodeType) {
  584. case ExpressionType.NewArrayInit:
  585. VisitNewArrayInit (newArray);
  586. return;
  587. case ExpressionType.NewArrayBounds:
  588. VisitNewArrayBounds (newArray);
  589. return;
  590. }
  591. throw new NotSupportedException ();
  592. }
  593. void VisitNewArrayBounds (NewArrayExpression newArray)
  594. {
  595. var lengths = new int [newArray.Expressions.Count];
  596. for (int i = 0; i < lengths.Length; i++) {
  597. Visit (newArray.Expressions [i]);
  598. lengths [i] = (int) Pop ();
  599. }
  600. Push (Array.CreateInstance (newArray.Type.GetElementType (), lengths));
  601. }
  602. void VisitNewArrayInit (NewArrayExpression newArray)
  603. {
  604. var array = Array.CreateInstance (
  605. newArray.Type.GetElementType (),
  606. newArray.Expressions.Count);
  607. for (int i = 0; i < array.Length; i++) {
  608. Visit (newArray.Expressions [i]);
  609. array.SetValue (Pop (), i);
  610. }
  611. Push (array);
  612. }
  613. protected override void VisitConditional (ConditionalExpression conditional)
  614. {
  615. Visit (conditional.Test);
  616. if ((bool) Pop ())
  617. Visit (conditional.IfTrue);
  618. else
  619. Visit (conditional.IfFalse);
  620. }
  621. protected override void VisitMethodCall (MethodCallExpression call)
  622. {
  623. object instance = null;
  624. if (call.Object != null) {
  625. Visit (call.Object);
  626. instance = Pop ();
  627. }
  628. Push (InvokeMethod (call.Method, instance, VisitListExpressions (call.Arguments)));
  629. }
  630. protected override void VisitParameter (ParameterExpression parameter)
  631. {
  632. var info = lambdas.Peek ();
  633. var lambda = info.Lambda;
  634. var arguments = info.Arguments;
  635. var index = GetParameterIndex (lambda, parameter);
  636. if (index >= 0) {
  637. Push (arguments [index]);
  638. return;
  639. }
  640. object value;
  641. if (hoisted_values.TryGetValue (parameter, out value)) {
  642. Push (value);
  643. return;
  644. }
  645. throw new ArgumentException ();
  646. }
  647. protected override void VisitConstant (ConstantExpression constant)
  648. {
  649. Push (constant.Value);
  650. }
  651. protected override void VisitInvocation (InvocationExpression invocation)
  652. {
  653. Visit (invocation.Expression);
  654. Push (Invoke ((Delegate) Pop (), VisitListExpressions (invocation.Arguments)));
  655. }
  656. static object Invoke (Delegate dlg, object [] arguments)
  657. {
  658. return InvokeMethod (dlg.Method, dlg.Target, arguments);
  659. }
  660. static object InvokeMethod (MethodBase method, object obj, object [] arguments)
  661. {
  662. try {
  663. return method.Invoke (obj, arguments);
  664. } catch (TargetInvocationException e) {
  665. throw e.InnerException;
  666. }
  667. }
  668. protected override void VisitMemberListBinding (MemberListBinding binding)
  669. {
  670. var value = Pop ();
  671. Push (value);
  672. VisitMemberInfo (binding.Member);
  673. VisitElementInitializerList (binding.Initializers);
  674. Pop (); // pop the member
  675. Push (value); // push the original target
  676. }
  677. protected override void VisitElementInitializer (ElementInit initializer)
  678. {
  679. object target = null;
  680. if (!initializer.AddMethod.IsStatic)
  681. target = Pop ();
  682. var arguments = VisitListExpressions (initializer.Arguments);
  683. InvokeMethod (initializer.AddMethod, target, arguments);
  684. if (!initializer.AddMethod.IsStatic)
  685. Push (target);
  686. }
  687. protected override void VisitMemberMemberBinding (MemberMemberBinding binding)
  688. {
  689. var value = Pop ();
  690. Push (value);
  691. VisitMemberInfo (binding.Member);
  692. VisitBindingList (binding.Bindings);
  693. Pop ();
  694. Push (value);
  695. }
  696. protected override void VisitMemberAssignment (MemberAssignment assignment)
  697. {
  698. Visit (assignment.Expression);
  699. var value = Pop ();
  700. assignment.Member.OnFieldOrProperty (
  701. field => {
  702. object target = null;
  703. if (!field.IsStatic)
  704. target = Pop ();
  705. field.SetValue (target, value);
  706. if (!field.IsStatic)
  707. Push (target);
  708. },
  709. property => {
  710. object target = null;
  711. var getter = property.GetGetMethod (true);
  712. if (!getter.IsStatic)
  713. target = Pop ();
  714. property.SetValue (target, value, null);
  715. if (!getter.IsStatic)
  716. Push (target);
  717. });
  718. }
  719. protected override void VisitLambda (LambdaExpression lambda)
  720. {
  721. Push (lambda.Compile (this));
  722. }
  723. private object [] VisitListExpressions (ReadOnlyCollection<Expression> collection)
  724. {
  725. object [] results = new object [collection.Count];
  726. for (int i = 0; i < results.Length; i++) {
  727. Visit (collection [i]);
  728. results [i] = Pop ();
  729. }
  730. return results;
  731. }
  732. void StoreHoistedVariables (LambdaExpression lambda, object [] arguments)
  733. {
  734. if (hoisted_map == null)
  735. return;
  736. List<ParameterExpression> variables;
  737. if (!hoisted_map.TryGetValue (lambda, out variables))
  738. return;
  739. foreach (var variable in variables)
  740. StoreHoistedVariable (variable, lambda, arguments);
  741. }
  742. void StoreHoistedVariable (ParameterExpression variable, LambdaExpression lambda, object [] arguments)
  743. {
  744. var index = GetParameterIndex (lambda, variable);
  745. if (index < 0)
  746. return;
  747. hoisted_values [variable] = arguments [index];
  748. }
  749. static int GetParameterIndex (LambdaExpression lambda, ParameterExpression parameter)
  750. {
  751. return lambda.Parameters.IndexOf (parameter);
  752. }
  753. public object Interpret (LambdaExpression lambda, object [] arguments)
  754. {
  755. lambdas.Push (new LambdaInfo (lambda, arguments));
  756. StoreHoistedVariables (lambda, arguments);
  757. Visit (lambda.Body);
  758. lambdas.Pop ();
  759. if (lambda.GetReturnType () != typeof (void))
  760. return Pop ();
  761. return null;
  762. }
  763. }
  764. }