ArgumentsObject.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. using System;
  2. using System.Collections.Generic;
  3. using Jint.Native.Function;
  4. using Jint.Native.Object;
  5. using Jint.Runtime;
  6. using Jint.Runtime.Descriptors;
  7. using Jint.Runtime.Descriptors.Specialized;
  8. using Jint.Runtime.Environments;
  9. namespace Jint.Native.Argument
  10. {
  11. /// <summary>
  12. /// http://www.ecma-international.org/ecma-262/5.1/#sec-10.6
  13. /// </summary>
  14. public class ArgumentsInstance : ObjectInstance
  15. {
  16. public ArgumentsInstance(Engine engine) : base(engine)
  17. {
  18. // todo: complete implementation
  19. }
  20. public bool Strict { get; set; }
  21. public static ArgumentsInstance CreateArgumentsObject(Engine engine, FunctionInstance func, string[] names, JsValue[] args, EnvironmentRecord env, bool strict)
  22. {
  23. var len = args.Length;
  24. var obj = new ArgumentsInstance(engine);
  25. obj.Prototype = engine.Object.PrototypeObject;
  26. obj.Extensible = true;
  27. obj.FastAddProperty("length", len, true, false, true);
  28. obj.Strict = strict;
  29. var map = engine.Object.Construct(Arguments.Empty);
  30. var mappedNamed = new List<string>();
  31. var indx = 0;
  32. while (indx <= len - 1)
  33. {
  34. var indxStr = TypeConverter.ToString(indx);
  35. var val = args[indx];
  36. obj.FastAddProperty(indxStr, val, true, true, true);
  37. if (indx < names.Length)
  38. {
  39. var name = names[indx];
  40. if (!strict && !mappedNamed.Contains(name))
  41. {
  42. mappedNamed.Add(name);
  43. Func<JsValue, JsValue> g = n => env.GetBindingValue(name, false);
  44. var p = new Action<JsValue, JsValue>((n, o) => env.SetMutableBinding(name, o, true));
  45. map.DefineOwnProperty(indxStr, new ClrAccessDescriptor(engine, g, p) { Configurable = true }, false);
  46. }
  47. }
  48. indx++;
  49. }
  50. // step 12
  51. if (mappedNamed.Count > 0)
  52. {
  53. obj.ParameterMap = map;
  54. }
  55. // step 13
  56. if (!strict)
  57. {
  58. obj.FastAddProperty("callee",func, true, false, true);
  59. }
  60. // step 14
  61. else
  62. {
  63. var thrower = engine.Function.ThrowTypeError;
  64. obj.DefineOwnProperty("caller", new PropertyDescriptor(get: thrower, set: thrower, enumerable:false, configurable:false), false);
  65. obj.DefineOwnProperty("callee", new PropertyDescriptor(get: thrower, set: thrower, enumerable: false, configurable: false), false);
  66. }
  67. return obj;
  68. }
  69. public ObjectInstance ParameterMap { get; set; }
  70. public override string Class
  71. {
  72. get
  73. {
  74. return "Arguments";
  75. }
  76. }
  77. public override PropertyDescriptor GetOwnProperty(string propertyName)
  78. {
  79. if (!Strict && ParameterMap != null)
  80. {
  81. var desc = base.GetOwnProperty(propertyName);
  82. if (desc == PropertyDescriptor.Undefined)
  83. {
  84. return desc;
  85. }
  86. var isMapped = ParameterMap.GetOwnProperty(propertyName);
  87. if (isMapped != PropertyDescriptor.Undefined)
  88. {
  89. desc.Value = ParameterMap.Get(propertyName);
  90. }
  91. return desc;
  92. }
  93. return base.GetOwnProperty(propertyName);
  94. }
  95. /// Implementation from ObjectInstance official specs as the one
  96. /// in ObjectInstance is optimized for the general case and wouldn't work
  97. /// for arrays
  98. public override void Put(string propertyName, JsValue value, bool throwOnError)
  99. {
  100. if (!CanPut(propertyName))
  101. {
  102. if (throwOnError)
  103. {
  104. throw new JavaScriptException(Engine.TypeError);
  105. }
  106. return;
  107. }
  108. var ownDesc = GetOwnProperty(propertyName);
  109. if (ownDesc.IsDataDescriptor())
  110. {
  111. var valueDesc = new PropertyDescriptor(value: value, writable: null, enumerable: null, configurable: null);
  112. DefineOwnProperty(propertyName, valueDesc, throwOnError);
  113. return;
  114. }
  115. // property is an accessor or inherited
  116. var desc = GetProperty(propertyName);
  117. if (desc.IsAccessorDescriptor())
  118. {
  119. var setter = desc.Set.Value.TryCast<ICallable>();
  120. setter.Call(new JsValue(this), new[] { value });
  121. }
  122. else
  123. {
  124. var newDesc = new PropertyDescriptor(value, true, true, true);
  125. DefineOwnProperty(propertyName, newDesc, throwOnError);
  126. }
  127. }
  128. public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
  129. {
  130. if (!Strict && ParameterMap != null)
  131. {
  132. var map = ParameterMap;
  133. var isMapped = map.GetOwnProperty(propertyName);
  134. var allowed = base.DefineOwnProperty(propertyName, desc, false);
  135. if (!allowed)
  136. {
  137. if (throwOnError)
  138. {
  139. throw new JavaScriptException(Engine.TypeError);
  140. }
  141. }
  142. if (isMapped != PropertyDescriptor.Undefined)
  143. {
  144. if (desc.IsAccessorDescriptor())
  145. {
  146. map.Delete(propertyName, false);
  147. }
  148. else
  149. {
  150. if (desc.Value.HasValue && desc.Value.Value != Undefined.Instance)
  151. {
  152. map.Put(propertyName, desc.Value.Value, throwOnError);
  153. }
  154. if (desc.Writable.HasValue && desc.Writable.Value == false)
  155. {
  156. map.Delete(propertyName, false);
  157. }
  158. }
  159. }
  160. return true;
  161. }
  162. return base.DefineOwnProperty(propertyName, desc, throwOnError);
  163. }
  164. public override bool Delete(string propertyName, bool throwOnError)
  165. {
  166. if (!Strict && ParameterMap != null)
  167. {
  168. var map = ParameterMap;
  169. var isMapped = map.GetOwnProperty(propertyName);
  170. var result = base.Delete(propertyName, throwOnError);
  171. if (result && isMapped != PropertyDescriptor.Undefined)
  172. {
  173. map.Delete(propertyName, false);
  174. }
  175. return result;
  176. }
  177. return base.Delete(propertyName, throwOnError);
  178. }
  179. }
  180. }