IteratorInstance.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. using System.Collections.Generic;
  2. using System.Globalization;
  3. using System.Linq;
  4. using Jint.Native.Array;
  5. using Jint.Native.Map;
  6. using Jint.Native.Object;
  7. using Jint.Native.RegExp;
  8. using Jint.Native.Set;
  9. using Jint.Runtime;
  10. using Jint.Runtime.Descriptors;
  11. namespace Jint.Native.Iterator
  12. {
  13. internal class IteratorInstance : ObjectInstance, IIterator
  14. {
  15. private readonly IEnumerator<JsValue> _enumerable;
  16. public IteratorInstance(Engine engine)
  17. : this(engine, Enumerable.Empty<JsValue>())
  18. {
  19. }
  20. public IteratorInstance(
  21. Engine engine,
  22. IEnumerable<JsValue> enumerable) : base(engine, ObjectClass.Iterator)
  23. {
  24. _enumerable = enumerable.GetEnumerator();
  25. }
  26. public override object ToObject()
  27. {
  28. throw new System.NotImplementedException();
  29. }
  30. public override bool Equals(JsValue other)
  31. {
  32. return false;
  33. }
  34. public virtual bool TryIteratorStep(out ObjectInstance nextItem)
  35. {
  36. if (_enumerable.MoveNext())
  37. {
  38. nextItem = new ValueIteratorPosition(_engine, _enumerable.Current);
  39. return true;
  40. }
  41. nextItem = ValueIteratorPosition.Done;
  42. return false;
  43. }
  44. public void Close(CompletionType completion)
  45. {
  46. }
  47. private ObjectInstance CreateIterResultObject(JsValue value, bool done)
  48. {
  49. var obj = _engine.Object.Construct(2);
  50. obj.SetDataProperty("value", value);
  51. obj.SetDataProperty("done", done);
  52. return obj;
  53. }
  54. private class KeyValueIteratorPosition : ObjectInstance
  55. {
  56. internal static readonly ObjectInstance Done = new KeyValueIteratorPosition(null, null, null);
  57. public KeyValueIteratorPosition(Engine engine, JsValue key, JsValue value) : base(engine)
  58. {
  59. var done = ReferenceEquals(null, key) && ReferenceEquals(null, value);
  60. if (!done)
  61. {
  62. var arrayInstance = engine.Array.ConstructFast(2);
  63. arrayInstance.SetIndexValue(0, key, false);
  64. arrayInstance.SetIndexValue(1, value, false);
  65. SetProperty("value", new PropertyDescriptor(arrayInstance, PropertyFlag.AllForbidden));
  66. }
  67. SetProperty("done", done ? PropertyDescriptor.AllForbiddenDescriptor.BooleanTrue : PropertyDescriptor.AllForbiddenDescriptor.BooleanFalse);
  68. }
  69. }
  70. private class ValueIteratorPosition : ObjectInstance
  71. {
  72. internal static readonly ObjectInstance Done = new KeyValueIteratorPosition(null, null, null);
  73. public ValueIteratorPosition(Engine engine, JsValue value) : base(engine)
  74. {
  75. var done = ReferenceEquals(null, value);
  76. if (!done)
  77. {
  78. SetProperty("value", new PropertyDescriptor(value, PropertyFlag.AllForbidden));
  79. }
  80. SetProperty("done", new PropertyDescriptor(done, PropertyFlag.AllForbidden));
  81. }
  82. }
  83. public class MapIterator : IteratorInstance
  84. {
  85. private readonly MapInstance _map;
  86. private int _position;
  87. public MapIterator(Engine engine, MapInstance map) : base(engine)
  88. {
  89. _map = map;
  90. _position = 0;
  91. }
  92. public override bool TryIteratorStep(out ObjectInstance nextItem)
  93. {
  94. if (_position < _map.GetSize())
  95. {
  96. var key = _map._map.GetKey(_position);
  97. var value = _map._map[key];
  98. _position++;
  99. nextItem = new KeyValueIteratorPosition(_engine, key, value);
  100. return true;
  101. }
  102. nextItem = KeyValueIteratorPosition.Done;
  103. return false;
  104. }
  105. }
  106. public class ArrayLikeIterator : IteratorInstance
  107. {
  108. private readonly ArrayOperations _array;
  109. private uint? _end;
  110. private uint _position;
  111. public ArrayLikeIterator(Engine engine, JsValue target) : base(engine)
  112. {
  113. if (!(target is ObjectInstance objectInstance))
  114. {
  115. ExceptionHelper.ThrowTypeError(engine, "Target must be an object");
  116. return;
  117. }
  118. _array = ArrayOperations.For(objectInstance);
  119. _position = 0;
  120. }
  121. public override bool TryIteratorStep(out ObjectInstance nextItem)
  122. {
  123. if (_end == null)
  124. {
  125. _end = _array.GetLength();
  126. }
  127. if (_position < _end.Value)
  128. {
  129. _array.TryGetValue(_position, out var value);
  130. nextItem = new KeyValueIteratorPosition(_engine, _position++, value);
  131. return true;
  132. }
  133. nextItem = KeyValueIteratorPosition.Done;
  134. return false;
  135. }
  136. }
  137. public class SetIterator : IteratorInstance
  138. {
  139. private readonly SetInstance _set;
  140. private int _position;
  141. public SetIterator(Engine engine, SetInstance set) : base(engine)
  142. {
  143. _set = set;
  144. _position = 0;
  145. }
  146. public override bool TryIteratorStep(out ObjectInstance nextItem)
  147. {
  148. if (_position < _set._set._list.Count)
  149. {
  150. var value = _set._set[_position];
  151. _position++;
  152. nextItem = new ValueIteratorPosition(_engine, value);
  153. return true;
  154. }
  155. nextItem = KeyValueIteratorPosition.Done;
  156. return false;
  157. }
  158. }
  159. public class SetEntryIterator : IteratorInstance
  160. {
  161. private readonly SetInstance _set;
  162. private int _position;
  163. public SetEntryIterator(Engine engine, SetInstance set) : base(engine)
  164. {
  165. _set = set;
  166. _position = 0;
  167. }
  168. public override bool TryIteratorStep(out ObjectInstance nextItem)
  169. {
  170. if (_position < _set._set._list.Count)
  171. {
  172. var value = _set._set[_position];
  173. _position++;
  174. nextItem = new KeyValueIteratorPosition(_engine, value, value);
  175. return true;
  176. }
  177. nextItem = KeyValueIteratorPosition.Done;
  178. return false;
  179. }
  180. }
  181. public class ListIterator : IteratorInstance
  182. {
  183. private readonly List<JsValue> _values;
  184. private int _position;
  185. private bool _closed;
  186. public ListIterator(Engine engine, List<JsValue> values) : base(engine)
  187. {
  188. _values = values;
  189. _position = 0;
  190. }
  191. public override bool TryIteratorStep(out ObjectInstance nextItem)
  192. {
  193. if (!_closed && _position < _values.Count)
  194. {
  195. var value = _values[_position];
  196. _position++;
  197. nextItem = new ValueIteratorPosition(_engine, value);
  198. return true;
  199. }
  200. _closed = true;
  201. nextItem = KeyValueIteratorPosition.Done;
  202. return false;
  203. }
  204. }
  205. public class ArrayLikeKeyIterator : IteratorInstance
  206. {
  207. private readonly ArrayOperations _operations;
  208. private uint _position;
  209. private bool _closed;
  210. public ArrayLikeKeyIterator(Engine engine, ObjectInstance objectInstance) : base(engine)
  211. {
  212. _operations = ArrayOperations.For(objectInstance);
  213. _position = 0;
  214. }
  215. public override bool TryIteratorStep(out ObjectInstance nextItem)
  216. {
  217. var length = _operations.GetLength();
  218. if (!_closed && _position < length)
  219. {
  220. nextItem = new ValueIteratorPosition(_engine, _position++);
  221. return true;
  222. }
  223. _closed = true;
  224. nextItem = KeyValueIteratorPosition.Done;
  225. return false;
  226. }
  227. }
  228. public class ArrayLikeValueIterator : IteratorInstance
  229. {
  230. private readonly ArrayOperations _operations;
  231. private uint _position;
  232. private bool _closed;
  233. public ArrayLikeValueIterator(Engine engine, ObjectInstance objectInstance) : base(engine)
  234. {
  235. _operations = ArrayOperations.For(objectInstance);
  236. _position = 0;
  237. }
  238. public override bool TryIteratorStep(out ObjectInstance nextItem)
  239. {
  240. var length = _operations.GetLength();
  241. if (!_closed && _position < length)
  242. {
  243. _operations.TryGetValue(_position++, out var value);
  244. nextItem = new ValueIteratorPosition(_engine, value);
  245. return true;
  246. }
  247. _closed = true;
  248. nextItem = KeyValueIteratorPosition.Done;
  249. return false;
  250. }
  251. }
  252. internal class ObjectWrapper : IIterator
  253. {
  254. private readonly ObjectInstance _target;
  255. private readonly ICallable _nextMethod;
  256. public ObjectWrapper(ObjectInstance target)
  257. {
  258. _target = target;
  259. _nextMethod = target.Get(CommonProperties.Next, target) as ICallable
  260. ?? ExceptionHelper.ThrowTypeError<ICallable>(target.Engine);
  261. }
  262. public bool TryIteratorStep(out ObjectInstance result)
  263. {
  264. result = IteratorNext();
  265. var done = result.Get(CommonProperties.Done);
  266. if (!done.IsUndefined() && TypeConverter.ToBoolean(done))
  267. {
  268. return false;
  269. }
  270. return true;
  271. }
  272. private ObjectInstance IteratorNext()
  273. {
  274. var jsValue = _nextMethod.Call(_target, Arguments.Empty);
  275. return jsValue as ObjectInstance ?? ExceptionHelper.ThrowTypeError<ObjectInstance>(_target.Engine, "Iterator result " + jsValue + " is not an object");
  276. }
  277. public void Close(CompletionType completion)
  278. {
  279. if (!_target.TryGetValue(CommonProperties.Return, out var func))
  280. {
  281. return;
  282. }
  283. var innerResult = Undefined;
  284. try
  285. {
  286. innerResult = ((ICallable) func).Call(_target, Arguments.Empty);
  287. }
  288. catch
  289. {
  290. if (completion != CompletionType.Throw)
  291. {
  292. throw;
  293. }
  294. }
  295. if (completion != CompletionType.Throw && !innerResult.IsObject())
  296. {
  297. ExceptionHelper.ThrowTypeError(_target.Engine);
  298. }
  299. }
  300. }
  301. internal class StringIterator : IteratorInstance
  302. {
  303. private readonly TextElementEnumerator _iterator;
  304. public StringIterator(Engine engine, string str) : base(engine)
  305. {
  306. _iterator = StringInfo.GetTextElementEnumerator(str);
  307. }
  308. public override bool TryIteratorStep(out ObjectInstance nextItem)
  309. {
  310. if (_iterator.MoveNext())
  311. {
  312. nextItem = new ValueIteratorPosition(_engine, (string) _iterator.Current);
  313. return true;
  314. }
  315. nextItem = KeyValueIteratorPosition.Done;
  316. return false;
  317. }
  318. }
  319. internal class RegExpStringIterator : IteratorInstance
  320. {
  321. private readonly RegExpInstance _iteratingRegExp;
  322. private readonly string _s;
  323. private readonly bool _global;
  324. private readonly bool _unicode;
  325. private bool _done;
  326. public RegExpStringIterator(Engine engine, ObjectInstance iteratingRegExp, string iteratedString, bool global, bool unicode) : base(engine)
  327. {
  328. if (!(iteratingRegExp is RegExpInstance r))
  329. {
  330. ExceptionHelper.ThrowTypeError(engine);
  331. return;
  332. }
  333. _iteratingRegExp = r;
  334. _s = iteratedString;
  335. _global = global;
  336. _unicode = unicode;
  337. }
  338. public override bool TryIteratorStep(out ObjectInstance nextItem)
  339. {
  340. if (_done)
  341. {
  342. nextItem = CreateIterResultObject(Undefined, true);
  343. return false;
  344. }
  345. var match = RegExpPrototype.RegExpExec(_iteratingRegExp, _s);
  346. if (match.IsNull())
  347. {
  348. _done = true;
  349. nextItem = CreateIterResultObject(Undefined, true);
  350. return false;
  351. }
  352. if (_global)
  353. {
  354. var macthStr = TypeConverter.ToString(match.Get(JsString.NumberZeroString));
  355. if (macthStr == "")
  356. {
  357. var thisIndex = TypeConverter.ToLength(_iteratingRegExp.Get(RegExpInstance.PropertyLastIndex));
  358. var nextIndex = thisIndex + 1;
  359. _iteratingRegExp.Set(RegExpInstance.PropertyLastIndex, nextIndex, true);
  360. }
  361. }
  362. else
  363. {
  364. _done = true;
  365. }
  366. nextItem = CreateIterResultObject(match, false);
  367. return false;
  368. }
  369. }
  370. }
  371. }