ObjectConstructor.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using Jint.Native.Function;
  4. using Jint.Native.String;
  5. using Jint.Runtime;
  6. using Jint.Runtime.Descriptors;
  7. using Jint.Runtime.Interop;
  8. namespace Jint.Native.Object
  9. {
  10. public sealed class ObjectConstructor : FunctionInstance, IConstructor
  11. {
  12. private readonly Engine _engine;
  13. private ObjectConstructor(Engine engine) : base(engine, null, null, false)
  14. {
  15. _engine = engine;
  16. }
  17. public static ObjectConstructor CreateObjectConstructor(Engine engine)
  18. {
  19. var obj = new ObjectConstructor(engine);
  20. obj.Extensible = true;
  21. obj.PrototypeObject = ObjectPrototype.CreatePrototypeObject(engine, obj);
  22. obj.FastAddProperty("length", 1, false, false, false);
  23. obj.FastAddProperty("prototype", obj.PrototypeObject, false, false, false);
  24. return obj;
  25. }
  26. public void Configure()
  27. {
  28. Prototype = Engine.Function.PrototypeObject;
  29. FastAddProperty("getPrototypeOf", new ClrFunctionInstance(Engine, GetPrototypeOf, 1), true, false, true);
  30. FastAddProperty("getOwnPropertyDescriptor", new ClrFunctionInstance(Engine, GetOwnPropertyDescriptor, 2), true, false, true);
  31. FastAddProperty("getOwnPropertyNames", new ClrFunctionInstance(Engine, GetOwnPropertyNames, 1), true, false, true);
  32. FastAddProperty("create", new ClrFunctionInstance(Engine, Create, 2), true, false, true);
  33. FastAddProperty("defineProperty", new ClrFunctionInstance(Engine, DefineProperty, 3), true, false, true);
  34. FastAddProperty("defineProperties", new ClrFunctionInstance(Engine, DefineProperties, 2), true, false, true);
  35. FastAddProperty("seal", new ClrFunctionInstance(Engine, Seal, 1), true, false, true);
  36. FastAddProperty("freeze", new ClrFunctionInstance(Engine, Freeze, 1), true, false, true);
  37. FastAddProperty("preventExtensions", new ClrFunctionInstance(Engine, PreventExtensions, 1), true, false, true);
  38. FastAddProperty("isSealed", new ClrFunctionInstance(Engine, IsSealed, 1), true, false, true);
  39. FastAddProperty("isFrozen", new ClrFunctionInstance(Engine, IsFrozen, 1), true, false, true);
  40. FastAddProperty("isExtensible", new ClrFunctionInstance(Engine, IsExtensible, 1), true, false, true);
  41. FastAddProperty("keys", new ClrFunctionInstance(Engine, Keys, 1), true, false, true);
  42. }
  43. public ObjectPrototype PrototypeObject { get; private set; }
  44. /// <summary>
  45. /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.1.1
  46. /// </summary>
  47. /// <param name="thisObject"></param>
  48. /// <param name="arguments"></param>
  49. /// <returns></returns>
  50. public override JsValue Call(JsValue thisObject, JsValue[] arguments)
  51. {
  52. if (arguments.Length == 0)
  53. {
  54. return Construct(arguments);
  55. }
  56. if(arguments[0] == Null.Instance || arguments[0] == Undefined.Instance)
  57. {
  58. return Construct(arguments);
  59. }
  60. return TypeConverter.ToObject(_engine, arguments[0]);
  61. }
  62. /// <summary>
  63. /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.2.1
  64. /// </summary>
  65. /// <param name="arguments"></param>
  66. /// <returns></returns>
  67. public ObjectInstance Construct(JsValue[] arguments)
  68. {
  69. if (arguments.Length > 0)
  70. {
  71. var value = arguments[0];
  72. var valueObj = value.TryCast<ObjectInstance>();
  73. if (valueObj != null)
  74. {
  75. return valueObj;
  76. }
  77. var type = value.Type;
  78. if (type == Types.String || type == Types.Number || type == Types.Boolean)
  79. {
  80. return TypeConverter.ToObject(_engine, value);
  81. }
  82. }
  83. var obj = new ObjectInstance(_engine)
  84. {
  85. Extensible = true,
  86. Prototype = Engine.Object.PrototypeObject
  87. };
  88. return obj;
  89. }
  90. public JsValue GetPrototypeOf(JsValue thisObject, JsValue[] arguments)
  91. {
  92. var oArg = arguments.At(0);
  93. var o = oArg.TryCast<ObjectInstance>();
  94. if (o == null)
  95. {
  96. throw new JavaScriptException(Engine.TypeError);
  97. }
  98. return o.Prototype ?? Null.Instance;
  99. }
  100. public JsValue GetOwnPropertyDescriptor(JsValue thisObject, JsValue[] arguments)
  101. {
  102. var oArg = arguments.At(0);
  103. var o = oArg.TryCast<ObjectInstance>();
  104. if (o == null)
  105. {
  106. throw new JavaScriptException(Engine.TypeError);
  107. }
  108. var p = arguments.At(1);
  109. var name = TypeConverter.ToString(p);
  110. var desc = o.GetOwnProperty(name);
  111. return PropertyDescriptor.FromPropertyDescriptor(Engine, desc);
  112. }
  113. public JsValue GetOwnPropertyNames(JsValue thisObject, JsValue[] arguments)
  114. {
  115. var oArg = arguments.At(0);
  116. var o = oArg.TryCast<ObjectInstance>();
  117. if (o == null)
  118. {
  119. throw new JavaScriptException(Engine.TypeError);
  120. }
  121. var array = Engine.Array.Construct(Arguments.Empty);
  122. var n = 0;
  123. var s = o as StringInstance;
  124. if (s != null)
  125. {
  126. for (var i = 0; i < s.PrimitiveValue.AsString().Length; i++)
  127. {
  128. array.DefineOwnProperty(n.ToString(), new PropertyDescriptor(i.ToString(), true, true, true), false);
  129. n++;
  130. }
  131. }
  132. foreach (var p in o.GetOwnProperties())
  133. {
  134. array.DefineOwnProperty(n.ToString(), new PropertyDescriptor(p.Key, true, true, true), false);
  135. n++;
  136. }
  137. return array;
  138. }
  139. public JsValue Create(JsValue thisObject, JsValue[] arguments)
  140. {
  141. var oArg = arguments.At(0);
  142. var o = oArg.TryCast<ObjectInstance>();
  143. if (o == null && oArg != Null.Instance)
  144. {
  145. throw new JavaScriptException(Engine.TypeError);
  146. }
  147. var obj = Engine.Object.Construct(Arguments.Empty);
  148. obj.Prototype = o;
  149. var properties = arguments.At(1);
  150. if (properties != Undefined.Instance)
  151. {
  152. DefineProperties(thisObject, new [] {obj, properties});
  153. }
  154. return obj;
  155. }
  156. public JsValue DefineProperty(JsValue thisObject, JsValue[] arguments)
  157. {
  158. var oArg = arguments.At(0);
  159. var o = oArg.TryCast<ObjectInstance>();
  160. if (o == null)
  161. {
  162. throw new JavaScriptException(Engine.TypeError);
  163. }
  164. var p = arguments.At(1);
  165. var name = TypeConverter.ToString(p);
  166. var attributes = arguments.At(2);
  167. var desc = PropertyDescriptor.ToPropertyDescriptor(Engine, attributes);
  168. o.DefineOwnProperty(name, desc, true);
  169. return o;
  170. }
  171. public JsValue DefineProperties(JsValue thisObject, JsValue[] arguments)
  172. {
  173. var oArg = arguments.At(0);
  174. var o = oArg.TryCast<ObjectInstance>();
  175. if (o == null)
  176. {
  177. throw new JavaScriptException(Engine.TypeError);
  178. }
  179. var properties = arguments.At(1);
  180. var props = TypeConverter.ToObject(Engine, properties);
  181. var descriptors = new List<KeyValuePair<string, PropertyDescriptor>>();
  182. foreach (var p in props.GetOwnProperties())
  183. {
  184. if (!p.Value.Enumerable.HasValue || !p.Value.Enumerable.Value)
  185. {
  186. continue;
  187. }
  188. var descObj = props.Get(p.Key);
  189. var desc = PropertyDescriptor.ToPropertyDescriptor(Engine, descObj);
  190. descriptors.Add(new KeyValuePair<string, PropertyDescriptor>(p.Key, desc));
  191. }
  192. foreach (var pair in descriptors)
  193. {
  194. o.DefineOwnProperty(pair.Key, pair.Value, true);
  195. }
  196. return o;
  197. }
  198. public JsValue Seal(JsValue thisObject, JsValue[] arguments)
  199. {
  200. var oArg = arguments.At(0);
  201. var o = oArg.TryCast<ObjectInstance>();
  202. if (o == null)
  203. {
  204. throw new JavaScriptException(Engine.TypeError);
  205. }
  206. foreach (var prop in o.GetOwnProperties())
  207. {
  208. if (prop.Value.Configurable.HasValue && prop.Value.Configurable.Value)
  209. {
  210. prop.Value.Configurable = false;
  211. }
  212. o.DefineOwnProperty(prop.Key, prop.Value, true);
  213. }
  214. o.Extensible = false;
  215. return o;
  216. }
  217. public JsValue Freeze(JsValue thisObject, JsValue[] arguments)
  218. {
  219. var oArg = arguments.At(0);
  220. var o = oArg.TryCast<ObjectInstance>();
  221. if (o == null)
  222. {
  223. throw new JavaScriptException(Engine.TypeError);
  224. }
  225. var keys = o.GetOwnProperties().Select(x => x.Key);
  226. foreach (var p in keys)
  227. {
  228. var desc = o.GetOwnProperty(p);
  229. if (desc.IsDataDescriptor())
  230. {
  231. if (desc.Writable.HasValue && desc.Writable.Value)
  232. {
  233. desc.Writable = false;
  234. }
  235. }
  236. if (desc.Configurable.HasValue && desc.Configurable.Value)
  237. {
  238. desc.Configurable = false;
  239. }
  240. o.DefineOwnProperty(p, desc, true);
  241. }
  242. o.Extensible = false;
  243. return o;
  244. }
  245. public JsValue PreventExtensions(JsValue thisObject, JsValue[] arguments)
  246. {
  247. var oArg = arguments.At(0);
  248. var o = oArg.TryCast<ObjectInstance>();
  249. if (o == null)
  250. {
  251. throw new JavaScriptException(Engine.TypeError);
  252. }
  253. o.Extensible = false;
  254. return o;
  255. }
  256. public JsValue IsSealed(JsValue thisObject, JsValue[] arguments)
  257. {
  258. var oArg = arguments.At(0);
  259. var o = oArg.TryCast<ObjectInstance>();
  260. if (o == null)
  261. {
  262. throw new JavaScriptException(Engine.TypeError);
  263. }
  264. foreach (var prop in o.GetOwnProperties())
  265. {
  266. if (prop.Value.Configurable.Value == true)
  267. {
  268. return false;
  269. }
  270. }
  271. if (o.Extensible == false)
  272. {
  273. return true;
  274. }
  275. return false;
  276. }
  277. public JsValue IsFrozen(JsValue thisObject, JsValue[] arguments)
  278. {
  279. var oArg = arguments.At(0);
  280. var o = oArg.TryCast<ObjectInstance>();
  281. if (o == null)
  282. {
  283. throw new JavaScriptException(Engine.TypeError);
  284. }
  285. foreach (var p in o.GetOwnProperties().Select(x => x.Key))
  286. {
  287. var desc = o.GetOwnProperty(p);
  288. if (desc.IsDataDescriptor())
  289. {
  290. if (desc.Writable.HasValue && desc.Writable.Value)
  291. {
  292. return false;
  293. }
  294. }
  295. if (desc.Configurable.HasValue && desc.Configurable.Value)
  296. {
  297. return false;
  298. }
  299. }
  300. if (o.Extensible == false)
  301. {
  302. return true;
  303. }
  304. return false;
  305. }
  306. public JsValue IsExtensible(JsValue thisObject, JsValue[] arguments)
  307. {
  308. var oArg = arguments.At(0);
  309. var o = oArg.TryCast<ObjectInstance>();
  310. if (o == null)
  311. {
  312. throw new JavaScriptException(Engine.TypeError);
  313. }
  314. return o.Extensible;
  315. }
  316. public JsValue Keys(JsValue thisObject, JsValue[] arguments)
  317. {
  318. var oArg = arguments.At(0);
  319. var o = oArg.TryCast<ObjectInstance>();
  320. if (o == null)
  321. {
  322. throw new JavaScriptException(Engine.TypeError);
  323. }
  324. var enumerableProperties = o.GetOwnProperties()
  325. .Where(x => x.Value.Enumerable.HasValue && x.Value.Enumerable.Value)
  326. .ToArray();
  327. var n = enumerableProperties.Length;
  328. var array = Engine.Array.Construct(new JsValue[] {n});
  329. var index = 0;
  330. foreach (var prop in enumerableProperties)
  331. {
  332. var p = prop.Key;
  333. array.DefineOwnProperty(
  334. TypeConverter.ToString(index),
  335. new PropertyDescriptor(p, true, true, true),
  336. false);
  337. index++;
  338. }
  339. return array;
  340. }
  341. }
  342. }