PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/IronPython_2_6/Src/Runtime/Microsoft.Dynamic/Actions/Calls/ParamsArgBuilder.cs

#
C# | 184 lines | 131 code | 31 blank | 22 comment | 14 complexity | e73d3fcf71485ee1353df6985310115c MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if !CLR2
  16. using System.Linq.Expressions;
  17. #else
  18. using Microsoft.Scripting.Ast;
  19. #endif
  20. using System;
  21. using System.Collections.Generic;
  22. using System.Dynamic;
  23. using System.Reflection;
  24. using System.Diagnostics;
  25. using Microsoft.Scripting.Utils;
  26. using AstUtils = Microsoft.Scripting.Ast.Utils;
  27. namespace Microsoft.Scripting.Actions.Calls {
  28. using Ast = Expression;
  29. internal sealed class ParamsArgBuilder : ArgBuilder {
  30. private readonly int _start;
  31. private readonly int _expandedCount;
  32. private readonly Type _elementType;
  33. internal ParamsArgBuilder(ParameterInfo info, Type elementType, int start, int expandedCount)
  34. : base(info) {
  35. Assert.NotNull(elementType);
  36. Debug.Assert(start >= 0);
  37. Debug.Assert(expandedCount >= 0);
  38. _start = start;
  39. _expandedCount = expandedCount;
  40. _elementType = elementType;
  41. }
  42. // Consumes all expanded arguments.
  43. // Collapsed arguments are fetched from resolver provided storage, not from actual argument expressions.
  44. public override int ConsumedArgumentCount {
  45. get { return _expandedCount; }
  46. }
  47. public override int Priority {
  48. get { return 4; }
  49. }
  50. internal protected override Expression ToExpression(OverloadResolver resolver, RestrictedArguments args, bool[] hasBeenUsed) {
  51. var actualArgs = resolver.GetActualArguments();
  52. int splatIndex = actualArgs.SplatIndex;
  53. int collapsedCount = actualArgs.CollapsedCount;
  54. int firstSplatted = actualArgs.FirstSplattedArg;
  55. var result = new Expression[2 + _expandedCount + (collapsedCount > 0 ? 2 : 0)];
  56. var arrayVariable = resolver.GetTemporary(_elementType.MakeArrayType(), "a");
  57. int e = 0;
  58. result[e++] = Ast.Assign(arrayVariable, Ast.NewArrayBounds(_elementType, Ast.Constant(_expandedCount + collapsedCount)));
  59. int itemIndex = 0;
  60. int i = _start;
  61. while (true) {
  62. // inject loop copying collapsed items:
  63. if (i == splatIndex) {
  64. var indexVariable = resolver.GetTemporary(typeof(int), "t");
  65. // for (int t = 0; t <= {collapsedCount}; t++) {
  66. // a[{itemIndex} + t] = CONVERT<ElementType>(list.get_Item({splatIndex - firstSplatted} + t))
  67. // }
  68. result[e++] = Ast.Assign(indexVariable, AstUtils.Constant(0));
  69. result[e++] = AstUtils.Loop(
  70. Ast.LessThan(indexVariable, Ast.Constant(collapsedCount)),
  71. // TODO: not implemented in the old interpreter
  72. // Ast.PostIncrementAssign(indexVariable),
  73. Ast.Assign(indexVariable, Ast.Add(indexVariable, AstUtils.Constant(1))),
  74. Ast.Assign(
  75. Ast.ArrayAccess(arrayVariable, Ast.Add(AstUtils.Constant(itemIndex), indexVariable)),
  76. resolver.Convert(
  77. new DynamicMetaObject(
  78. resolver.GetSplattedItemExpression(Ast.Add(AstUtils.Constant(splatIndex - firstSplatted), indexVariable)),
  79. BindingRestrictions.Empty
  80. ),
  81. null,
  82. ParameterInfo,
  83. _elementType
  84. )
  85. ),
  86. null
  87. );
  88. itemIndex += collapsedCount;
  89. }
  90. if (i >= _start + _expandedCount) {
  91. break;
  92. }
  93. Debug.Assert(!hasBeenUsed[i]);
  94. hasBeenUsed[i] = true;
  95. result[e++] = Ast.Assign(
  96. Ast.ArrayAccess(arrayVariable, AstUtils.Constant(itemIndex++)),
  97. resolver.Convert(args.GetObject(i), args.GetType(i), ParameterInfo, _elementType)
  98. );
  99. i++;
  100. }
  101. result[e++] = arrayVariable;
  102. Debug.Assert(e == result.Length);
  103. return Ast.Block(result);
  104. }
  105. protected internal override Func<object[], object> ToDelegate(OverloadResolver resolver, RestrictedArguments args, bool[] hasBeenUsed) {
  106. if (resolver.GetActualArguments().CollapsedCount > 0) {
  107. return null;
  108. }
  109. var indexes = new List<Func<object[], object>>(_expandedCount);
  110. for (int i = _start; i < _start + _expandedCount; i++) {
  111. if (!hasBeenUsed[i]) {
  112. indexes.Add(resolver.GetConvertor(i + 1, args.GetObject(i), ParameterInfo, _elementType));
  113. hasBeenUsed[i] = true;
  114. }
  115. }
  116. if (_elementType == typeof(object)) {
  117. return new ParamArrayDelegate<object>(indexes.ToArray(), _start).MakeParamsArray;
  118. }
  119. Type genType = typeof(ParamArrayDelegate<>).MakeGenericType(_elementType);
  120. return (Func<object[], object>)Delegate.CreateDelegate(
  121. typeof(Func<object[], object>),
  122. Activator.CreateInstance(genType, indexes.ToArray(), _start),
  123. genType.GetMethod("MakeParamsArray"));
  124. }
  125. class ParamArrayDelegate<T> {
  126. private readonly Func<object[], object>[] _indexes;
  127. private readonly int _start;
  128. public ParamArrayDelegate(Func<object[], object>[] indexes, int start) {
  129. _indexes = indexes;
  130. _start = start;
  131. }
  132. public T[] MakeParamsArray(object[] args) {
  133. T[] res = new T[_indexes.Length];
  134. for (int i = 0; i < _indexes.Length; i++) {
  135. if (_indexes[i] == null) {
  136. res[i] = (T)args[_start + i + 1];
  137. } else {
  138. res[i] = (T)_indexes[i](args);
  139. }
  140. }
  141. return res;
  142. }
  143. }
  144. public override Type Type {
  145. get {
  146. return _elementType.MakeArrayType();
  147. }
  148. }
  149. public override ArgBuilder Clone(ParameterInfo newType) {
  150. return new ParamsArgBuilder(newType, newType.ParameterType.GetElementType(), _start, _expandedCount);
  151. }
  152. }
  153. }