JavascriptRegExpConstructor.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeLibraryPch.h"
  6. #include "RegexPattern.h"
  7. namespace Js
  8. {
  9. // The VS2013 linker treats this as a redefinition of an already
  10. // defined constant and complains. So skip the declaration if we're compiling
  11. // with VS2013 or below.
  12. #if !defined(_MSC_VER) || _MSC_VER >= 1900
  13. const int JavascriptRegExpConstructor::NumCtorCaptures;
  14. #endif
  15. JavascriptRegExpConstructor::JavascriptRegExpConstructor(DynamicType* type, ConstructorCache* cache) :
  16. RuntimeFunction(type, &JavascriptRegExp::EntryInfo::NewInstance, cache),
  17. reset(false),
  18. invalidatedLastMatch(false),
  19. lastPattern(nullptr),
  20. lastMatch() // undefined
  21. {
  22. DebugOnly(VerifyEntryPoint());
  23. ScriptContext* scriptContext = this->GetScriptContext();
  24. JavascriptString* emptyString = scriptContext->GetLibrary()->GetEmptyString();
  25. this->lastInput = emptyString;
  26. this->index = JavascriptNumber::ToVar(-1, scriptContext);
  27. this->lastIndex = JavascriptNumber::ToVar(-1, scriptContext);
  28. this->lastParen = emptyString;
  29. this->leftContext = emptyString;
  30. this->rightContext = emptyString;
  31. for (int i = 0; i < NumCtorCaptures; i++)
  32. {
  33. this->captures[i] = emptyString;
  34. }
  35. }
  36. BOOL JavascriptRegExpConstructor::GetEnumerator(JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext* requestContext, EnumeratorCache * enumeratorCache)
  37. {
  38. return GetEnumeratorWithPrefix(
  39. RecyclerNew(GetScriptContext()->GetRecycler(), JavascriptRegExpEnumerator, this, flags, requestContext),
  40. enumerator, flags, requestContext, enumeratorCache);
  41. }
  42. void JavascriptRegExpConstructor::SetLastMatch(UnifiedRegex::RegexPattern* lastPattern, JavascriptString* lastInput, UnifiedRegex::GroupInfo lastMatch)
  43. {
  44. AssertMsg(!lastMatch.IsUndefined(), "SetLastMatch should only be called if there's a successful match");
  45. AssertMsg(lastPattern != nullptr, "lastPattern should not be null");
  46. AssertMsg(lastInput != nullptr, "lastInput should not be null");
  47. AssertMsg(JavascriptOperators::GetTypeId(lastInput) != TypeIds_Null, "lastInput should not be JavaScript null");
  48. this->lastPattern = lastPattern;
  49. this->lastInput = lastInput;
  50. this->lastMatch = lastMatch;
  51. this->reset = true;
  52. this->invalidatedLastMatch = false;
  53. }
  54. void JavascriptRegExpConstructor::InvalidateLastMatch(UnifiedRegex::RegexPattern* lastPattern, JavascriptString* lastInput)
  55. {
  56. AssertMsg(lastPattern != nullptr, "lastPattern should not be null");
  57. AssertMsg(lastInput != nullptr, "lastInput should not be null");
  58. AssertMsg(JavascriptOperators::GetTypeId(lastInput) != TypeIds_Null, "lastInput should not be JavaScript null");
  59. this->lastPattern = lastPattern;
  60. this->lastInput = lastInput;
  61. this->lastMatch.Reset();
  62. this->reset = true;
  63. this->invalidatedLastMatch = true;
  64. }
  65. void JavascriptRegExpConstructor::EnsureValues()
  66. {
  67. if (reset)
  68. {
  69. ScriptContext* scriptContext = this->GetScriptContext();
  70. const CharCount lastInputLen = lastInput->GetLength();
  71. const char16* lastInputStr = lastInput->GetString();
  72. UnifiedRegex::RegexPattern* pattern = lastPattern;
  73. // When we perform a regex test operation it's possible the result of the operation will be loaded from a cache and the match will not be computed and updated in the ctor.
  74. // In that case we invalidate the last match stored in the ctor and will need to compute it before it will be accessible via $1 etc.
  75. // Since we only do this for the case of RegExp.prototype.test cache hit, we know several things:
  76. // - The regex is not global or sticky
  77. // - There was a match (test returned true)
  78. if (invalidatedLastMatch)
  79. {
  80. this->lastMatch = RegexHelper::SimpleMatch(scriptContext, pattern, lastInputStr, lastInputLen, 0);
  81. invalidatedLastMatch = false;
  82. }
  83. Assert(!lastMatch.IsUndefined());
  84. JavascriptString* emptyString = scriptContext->GetLibrary()->GetEmptyString();
  85. CharCount lastIndexVal = lastMatch.EndOffset();
  86. this->index = JavascriptNumber::ToVar(lastMatch.offset, scriptContext);
  87. this->lastIndex = JavascriptNumber::ToVar(lastIndexVal, scriptContext);
  88. this->leftContext = lastMatch.offset > 0 ? SubString::New(lastInput, 0, lastMatch.offset) : emptyString;
  89. this->rightContext = lastIndexVal > 0 && lastIndexVal < lastInputLen ? SubString::New(lastInput, lastIndexVal, lastInputLen - lastIndexVal) : emptyString;
  90. Var nonMatchValue = RegexHelper::NonMatchValue(scriptContext, true);
  91. captures[0] = RegexHelper::GetString(scriptContext, lastInput, nonMatchValue, lastMatch);
  92. int numGroups = pattern->NumGroups();
  93. if (numGroups > 1)
  94. {
  95. // The RegExp constructor's lastMatch holds the last *successful* match on any regular expression.
  96. // That regular expression may since have been used for *unsuccessful* matches, in which case
  97. // its groups will have been reset. Updating the RegExp constructor with the group binding after
  98. // every match is prohibitively slow. Instead, run the match again using the known last input string.
  99. if (!pattern->WasLastMatchSuccessful())
  100. {
  101. RegexHelper::SimpleMatch(scriptContext, pattern, lastInputStr, lastInputLen, lastMatch.offset);
  102. }
  103. Assert(pattern->WasLastMatchSuccessful());
  104. for (int groupId = 1; groupId < min(numGroups, NumCtorCaptures); groupId++)
  105. captures[groupId] = RegexHelper::GetGroup(scriptContext, pattern, lastInput, nonMatchValue, groupId);
  106. this->lastParen = numGroups <= NumCtorCaptures ?
  107. PointerValue(captures[numGroups - 1]) :
  108. RegexHelper::GetGroup(scriptContext, pattern, lastInput, nonMatchValue, numGroups - 1);
  109. }
  110. else
  111. {
  112. this->lastParen = emptyString;
  113. }
  114. for (int groupId = numGroups; groupId < NumCtorCaptures; groupId++)
  115. captures[groupId] = emptyString;
  116. reset = false;
  117. }
  118. else
  119. {
  120. // If we are not resetting the values, the last match cannot be invalidated.
  121. Assert(!invalidatedLastMatch);
  122. }
  123. }
  124. /*static*/
  125. PropertyId const JavascriptRegExpConstructor::specialPropertyIds[] =
  126. {
  127. PropertyIds::$_,
  128. PropertyIds::$Ampersand,
  129. PropertyIds::$Plus,
  130. PropertyIds::$BackTick,
  131. PropertyIds::$Tick,
  132. PropertyIds::index,
  133. };
  134. PropertyId const JavascriptRegExpConstructor::specialEnumPropertyIds[] =
  135. {
  136. PropertyIds::$1,
  137. PropertyIds::$2,
  138. PropertyIds::$3,
  139. PropertyIds::$4,
  140. PropertyIds::$5,
  141. PropertyIds::$6,
  142. PropertyIds::$7,
  143. PropertyIds::$8,
  144. PropertyIds::$9,
  145. PropertyIds::input,
  146. PropertyIds::rightContext,
  147. PropertyIds::leftContext,
  148. PropertyIds::lastParen,
  149. PropertyIds::lastMatch,
  150. };
  151. PropertyId const JavascriptRegExpConstructor::specialnonEnumPropertyIds[] =
  152. {
  153. PropertyIds::$_,
  154. PropertyIds::$Ampersand,
  155. PropertyIds::$Plus,
  156. PropertyIds::$BackTick,
  157. PropertyIds::$Tick,
  158. PropertyIds::index,
  159. };
  160. PropertyQueryFlags JavascriptRegExpConstructor::HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info)
  161. {
  162. switch (propertyId)
  163. {
  164. case PropertyIds::lastMatch:
  165. case PropertyIds::$Ampersand:
  166. case PropertyIds::lastParen:
  167. case PropertyIds::$Plus:
  168. case PropertyIds::leftContext:
  169. case PropertyIds::$BackTick:
  170. case PropertyIds::rightContext:
  171. case PropertyIds::$Tick:
  172. case PropertyIds::index:
  173. case PropertyIds::input:
  174. case PropertyIds::$_:
  175. case PropertyIds::$1:
  176. case PropertyIds::$2:
  177. case PropertyIds::$3:
  178. case PropertyIds::$4:
  179. case PropertyIds::$5:
  180. case PropertyIds::$6:
  181. case PropertyIds::$7:
  182. case PropertyIds::$8:
  183. case PropertyIds::$9:
  184. return PropertyQueryFlags::Property_Found;
  185. default:
  186. return JavascriptFunction::HasPropertyQuery(propertyId, info);
  187. }
  188. }
  189. PropertyQueryFlags JavascriptRegExpConstructor::GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  190. {
  191. return JavascriptRegExpConstructor::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext);
  192. }
  193. PropertyQueryFlags JavascriptRegExpConstructor::GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  194. {
  195. BOOL result;
  196. if (GetPropertyBuiltIns(propertyId, value, &result))
  197. {
  198. return JavascriptConversion::BooleanToPropertyQueryFlags(result);
  199. }
  200. return JavascriptFunction::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext);
  201. }
  202. PropertyQueryFlags JavascriptRegExpConstructor::GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  203. {
  204. BOOL result;
  205. PropertyRecord const* propertyRecord;
  206. this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
  207. if (propertyRecord != nullptr && GetPropertyBuiltIns(propertyRecord->GetPropertyId(), value, &result))
  208. {
  209. return JavascriptConversion::BooleanToPropertyQueryFlags(result);
  210. }
  211. return JavascriptFunction::GetPropertyQuery(originalInstance, propertyNameString, value, info, requestContext);
  212. }
  213. bool JavascriptRegExpConstructor::GetPropertyBuiltIns(PropertyId propertyId, Var* value, BOOL* result)
  214. {
  215. switch (propertyId)
  216. {
  217. case PropertyIds::input:
  218. case PropertyIds::$_:
  219. this->EnsureValues();
  220. *value = this->lastInput;
  221. *result = true;
  222. return true;
  223. case PropertyIds::lastMatch:
  224. case PropertyIds::$Ampersand:
  225. this->EnsureValues();
  226. *value = this->captures[0];
  227. *result = true;
  228. return true;
  229. case PropertyIds::lastParen:
  230. case PropertyIds::$Plus:
  231. this->EnsureValues();
  232. *value = this->lastParen;
  233. *result = true;
  234. return true;
  235. case PropertyIds::leftContext:
  236. case PropertyIds::$BackTick:
  237. this->EnsureValues();
  238. *value = this->leftContext;
  239. *result = true;
  240. return true;
  241. case PropertyIds::rightContext:
  242. case PropertyIds::$Tick:
  243. this->EnsureValues();
  244. *value = this->rightContext;
  245. *result = true;
  246. return true;
  247. case PropertyIds::$1:
  248. this->EnsureValues();
  249. *value = this->captures[1];
  250. *result = true;
  251. return true;
  252. case PropertyIds::$2:
  253. this->EnsureValues();
  254. *value = this->captures[2];
  255. *result = true;
  256. return true;
  257. case PropertyIds::$3:
  258. this->EnsureValues();
  259. *value = this->captures[3];
  260. *result = true;
  261. return true;
  262. case PropertyIds::$4:
  263. this->EnsureValues();
  264. *value = this->captures[4];
  265. *result = true;
  266. return true;
  267. case PropertyIds::$5:
  268. this->EnsureValues();
  269. *value = this->captures[5];
  270. *result = true;
  271. return true;
  272. case PropertyIds::$6:
  273. this->EnsureValues();
  274. *value = this->captures[6];
  275. *result = true;
  276. return true;
  277. case PropertyIds::$7:
  278. this->EnsureValues();
  279. *value = this->captures[7];
  280. *result = true;
  281. return true;
  282. case PropertyIds::$8:
  283. this->EnsureValues();
  284. *value = this->captures[8];
  285. *result = true;
  286. return true;
  287. case PropertyIds::$9:
  288. this->EnsureValues();
  289. *value = this->captures[9];
  290. *result = true;
  291. return true;
  292. case PropertyIds::index:
  293. this->EnsureValues();
  294. *value = this->index;
  295. *result = true;
  296. return true;
  297. default:
  298. return false;
  299. }
  300. }
  301. BOOL JavascriptRegExpConstructor::SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  302. {
  303. BOOL result;
  304. if (SetPropertyBuiltIns(propertyId, value, &result))
  305. {
  306. return result;
  307. }
  308. return JavascriptFunction::SetProperty(propertyId, value, flags, info);
  309. }
  310. BOOL JavascriptRegExpConstructor::SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  311. {
  312. BOOL result;
  313. PropertyRecord const * propertyRecord;
  314. this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
  315. if (propertyRecord != nullptr && SetPropertyBuiltIns(propertyRecord->GetPropertyId(), value, &result))
  316. {
  317. return result;
  318. }
  319. return JavascriptFunction::SetProperty(propertyNameString, value, flags, info);
  320. }
  321. bool JavascriptRegExpConstructor::SetPropertyBuiltIns(PropertyId propertyId, Var value, BOOL* result)
  322. {
  323. switch (propertyId)
  324. {
  325. case PropertyIds::input:
  326. case PropertyIds::$_:
  327. //TODO: review: although the 'input' property is marked as readonly, it has a set on V5.8. There is no spec on this.
  328. {
  329. auto tempInput = JavascriptConversion::ToString(value, this->GetScriptContext());
  330. // Above toString call can cause user code to be called, which may call .match to invalidate our state, ensure that we have proper values in case that happens.
  331. EnsureValues(); // The last match info relies on the last input. Use it before it is changed.
  332. this->lastInput = tempInput;
  333. }
  334. // Set implicit call flags since we are not necessarily making the original stored value available on re-load
  335. // and are killing the store that backs two exposed properties.
  336. this->GetScriptContext()->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_Accessor);
  337. *result = true;
  338. return true;
  339. case PropertyIds::lastMatch:
  340. case PropertyIds::$Ampersand:
  341. case PropertyIds::lastParen:
  342. case PropertyIds::$Plus:
  343. case PropertyIds::leftContext:
  344. case PropertyIds::$BackTick:
  345. case PropertyIds::rightContext:
  346. case PropertyIds::$Tick:
  347. case PropertyIds::$1:
  348. case PropertyIds::$2:
  349. case PropertyIds::$3:
  350. case PropertyIds::$4:
  351. case PropertyIds::$5:
  352. case PropertyIds::$6:
  353. case PropertyIds::$7:
  354. case PropertyIds::$8:
  355. case PropertyIds::$9:
  356. case PropertyIds::index:
  357. *result = false;
  358. return true;
  359. default:
  360. return false;
  361. }
  362. }
  363. BOOL JavascriptRegExpConstructor::InitProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  364. {
  365. return SetProperty(propertyId, value, flags, info);
  366. }
  367. BOOL JavascriptRegExpConstructor::DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags)
  368. {
  369. switch (propertyId)
  370. {
  371. // all globals are 'fNoDelete' in V5.8
  372. case PropertyIds::input:
  373. case PropertyIds::$_:
  374. case PropertyIds::lastMatch:
  375. case PropertyIds::$Ampersand:
  376. case PropertyIds::lastParen:
  377. case PropertyIds::$Plus:
  378. case PropertyIds::leftContext:
  379. case PropertyIds::$BackTick:
  380. case PropertyIds::rightContext:
  381. case PropertyIds::$Tick:
  382. case PropertyIds::$1:
  383. case PropertyIds::$2:
  384. case PropertyIds::$3:
  385. case PropertyIds::$4:
  386. case PropertyIds::$5:
  387. case PropertyIds::$6:
  388. case PropertyIds::$7:
  389. case PropertyIds::$8:
  390. case PropertyIds::$9:
  391. case PropertyIds::index:
  392. JavascriptError::ThrowCantDeleteIfStrictMode(flags, GetScriptContext(), GetScriptContext()->GetPropertyName(propertyId)->GetBuffer());
  393. return false;
  394. default:
  395. return JavascriptFunction::DeleteProperty(propertyId, flags);
  396. }
  397. }
  398. BOOL JavascriptRegExpConstructor::DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags)
  399. {
  400. PropertyRecord const * propertyRecord = nullptr;
  401. propertyNameString->GetScriptContext()->GetOrAddPropertyRecord(propertyNameString, &propertyRecord);
  402. PropertyId propertyId = propertyRecord->GetPropertyId();
  403. if (BuiltInPropertyRecords::input.Equals(propertyId)
  404. || BuiltInPropertyRecords::$_.Equals(propertyId)
  405. || BuiltInPropertyRecords::lastMatch.Equals(propertyId)
  406. || BuiltInPropertyRecords::$Ampersand.Equals(propertyId)
  407. || BuiltInPropertyRecords::lastParen.Equals(propertyId)
  408. || BuiltInPropertyRecords::$Plus.Equals(propertyId)
  409. || BuiltInPropertyRecords::leftContext.Equals(propertyId)
  410. || BuiltInPropertyRecords::$BackTick.Equals(propertyId)
  411. || BuiltInPropertyRecords::rightContext.Equals(propertyId)
  412. || BuiltInPropertyRecords::$Tick.Equals(propertyId)
  413. || BuiltInPropertyRecords::$1.Equals(propertyId)
  414. || BuiltInPropertyRecords::$2.Equals(propertyId)
  415. || BuiltInPropertyRecords::$3.Equals(propertyId)
  416. || BuiltInPropertyRecords::$4.Equals(propertyId)
  417. || BuiltInPropertyRecords::$5.Equals(propertyId)
  418. || BuiltInPropertyRecords::$6.Equals(propertyId)
  419. || BuiltInPropertyRecords::$7.Equals(propertyId)
  420. || BuiltInPropertyRecords::$8.Equals(propertyId)
  421. || BuiltInPropertyRecords::$9.Equals(propertyId)
  422. || BuiltInPropertyRecords::index.Equals(propertyId))
  423. {
  424. JavascriptError::ThrowCantDeleteIfStrictMode(flags, GetScriptContext(), propertyNameString->GetString());
  425. return false;
  426. }
  427. return JavascriptFunction::DeleteProperty(propertyNameString, flags);
  428. }
  429. BOOL JavascriptRegExpConstructor::GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  430. {
  431. stringBuilder->AppendCppLiteral(JS_DIAG_VALUE_JavascriptRegExpConstructor);
  432. return TRUE;
  433. }
  434. BOOL JavascriptRegExpConstructor::GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  435. {
  436. stringBuilder->AppendCppLiteral(JS_DIAG_TYPE_JavascriptRegExpConstructor);
  437. return TRUE;
  438. }
  439. BOOL JavascriptRegExpConstructor::IsEnumerable(PropertyId propertyId)
  440. {
  441. switch (propertyId)
  442. {
  443. case PropertyIds::input:
  444. case PropertyIds::$1:
  445. case PropertyIds::$2:
  446. case PropertyIds::$3:
  447. case PropertyIds::$4:
  448. case PropertyIds::$5:
  449. case PropertyIds::$6:
  450. case PropertyIds::$7:
  451. case PropertyIds::$8:
  452. case PropertyIds::$9:
  453. case PropertyIds::leftContext:
  454. case PropertyIds::rightContext:
  455. case PropertyIds::lastMatch:
  456. case PropertyIds::lastParen:
  457. return true;
  458. case PropertyIds::$_:
  459. case PropertyIds::$Ampersand:
  460. case PropertyIds::$Plus:
  461. case PropertyIds::$BackTick:
  462. case PropertyIds::$Tick:
  463. case PropertyIds::index:
  464. return false;
  465. default:
  466. return JavascriptFunction::IsEnumerable(propertyId);
  467. }
  468. }
  469. BOOL JavascriptRegExpConstructor::IsConfigurable(PropertyId propertyId)
  470. {
  471. switch (propertyId)
  472. {
  473. case PropertyIds::input:
  474. case PropertyIds::$_:
  475. case PropertyIds::lastMatch:
  476. case PropertyIds::$Ampersand:
  477. case PropertyIds::lastParen:
  478. case PropertyIds::$Plus:
  479. case PropertyIds::leftContext:
  480. case PropertyIds::$BackTick:
  481. case PropertyIds::rightContext:
  482. case PropertyIds::$Tick:
  483. case PropertyIds::$1:
  484. case PropertyIds::$2:
  485. case PropertyIds::$3:
  486. case PropertyIds::$4:
  487. case PropertyIds::$5:
  488. case PropertyIds::$6:
  489. case PropertyIds::$7:
  490. case PropertyIds::$8:
  491. case PropertyIds::$9:
  492. case PropertyIds::index:
  493. return false;
  494. default:
  495. return JavascriptFunction::IsConfigurable(propertyId);
  496. }
  497. }
  498. BOOL JavascriptRegExpConstructor::GetSpecialNonEnumerablePropertyName(uint32 index, Var *propertyName, ScriptContext * requestContext)
  499. {
  500. uint length = GetSpecialNonEnumerablePropertyCount();
  501. if (index < length)
  502. {
  503. *propertyName = requestContext->GetPropertyString(specialnonEnumPropertyIds[index]);
  504. return true;
  505. }
  506. return false;
  507. }
  508. // Returns the number of special non-enumerable properties this type has.
  509. uint JavascriptRegExpConstructor::GetSpecialNonEnumerablePropertyCount() const
  510. {
  511. return _countof(specialnonEnumPropertyIds);
  512. }
  513. // Returns the list of special properties for the type.
  514. PropertyId const * JavascriptRegExpConstructor::GetSpecialNonEnumerablePropertyIds() const
  515. {
  516. return specialnonEnumPropertyIds;
  517. }
  518. BOOL JavascriptRegExpConstructor::GetSpecialEnumerablePropertyName(uint32 index, JavascriptString ** propertyName, ScriptContext * requestContext)
  519. {
  520. uint length = GetSpecialEnumerablePropertyCount();
  521. if (index < length)
  522. {
  523. *propertyName = requestContext->GetPropertyString(specialEnumPropertyIds[index]);
  524. return true;
  525. }
  526. return false;
  527. }
  528. PropertyId const * JavascriptRegExpConstructor::GetSpecialEnumerablePropertyIds() const
  529. {
  530. return specialEnumPropertyIds;
  531. }
  532. // Returns the number of special non-enumerable properties this type has.
  533. uint JavascriptRegExpConstructor::GetSpecialEnumerablePropertyCount() const
  534. {
  535. return _countof(specialEnumPropertyIds);
  536. }
  537. // Returns the list of special properties for the type.
  538. PropertyId const * JavascriptRegExpConstructor::GetSpecialPropertyIds() const
  539. {
  540. return specialPropertyIds;
  541. }
  542. uint JavascriptRegExpConstructor::GetSpecialPropertyCount() const
  543. {
  544. return _countof(specialPropertyIds);
  545. }
  546. BOOL JavascriptRegExpConstructor::GetSpecialPropertyName(uint32 index, JavascriptString ** propertyName, ScriptContext * requestContext)
  547. {
  548. uint length = GetSpecialPropertyCount();
  549. if (index < length)
  550. {
  551. *propertyName = requestContext->GetPropertyString(specialPropertyIds[index]);
  552. return true;
  553. }
  554. return false;
  555. }
  556. } // namespace Js