JavascriptRegularExpression.cpp 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596
  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. // Parser Includes
  7. #include "DebugWriter.h"
  8. #include "RegexPattern.h"
  9. namespace Js
  10. {
  11. JavascriptRegExp::JavascriptRegExp(UnifiedRegex::RegexPattern* pattern, DynamicType* type) :
  12. DynamicObject(type),
  13. pattern(pattern),
  14. splitPattern(nullptr),
  15. lastIndexVar(nullptr),
  16. lastIndexOrFlag(0)
  17. {
  18. Assert(type->GetTypeId() == TypeIds_RegEx);
  19. Assert(!this->GetType()->AreThisAndPrototypesEnsuredToHaveOnlyWritableDataProperties());
  20. #if ENABLE_REGEX_CONFIG_OPTIONS
  21. if (REGEX_CONFIG_FLAG(RegexTracing))
  22. {
  23. UnifiedRegex::DebugWriter* w = type->GetScriptContext()->GetRegexDebugWriter();
  24. if (pattern == 0)
  25. w->PrintEOL(_u("// REGEX CREATE"));
  26. else
  27. {
  28. w->Print(_u("// REGEX CREATE "));
  29. pattern->Print(w);
  30. w->EOL();
  31. }
  32. }
  33. #endif
  34. }
  35. JavascriptRegExp::JavascriptRegExp(DynamicType * type) :
  36. DynamicObject(type),
  37. pattern(nullptr),
  38. splitPattern(nullptr),
  39. lastIndexVar(nullptr),
  40. lastIndexOrFlag(0)
  41. {
  42. Assert(type->GetTypeId() == TypeIds_RegEx);
  43. #if DBG
  44. if (REGEX_CONFIG_FLAG(RegexTracing))
  45. {
  46. UnifiedRegex::DebugWriter* w = type->GetScriptContext()->GetRegexDebugWriter();
  47. w->PrintEOL(_u("REGEX CREATE"));
  48. }
  49. #endif
  50. }
  51. JavascriptRegExp::JavascriptRegExp(JavascriptRegExp * instance) :
  52. DynamicObject(instance),
  53. pattern(instance->GetPattern()),
  54. splitPattern(instance->GetSplitPattern()),
  55. lastIndexVar(instance->lastIndexVar),
  56. lastIndexOrFlag(instance->lastIndexOrFlag)
  57. {
  58. // For boxing stack instance
  59. Assert(ThreadContext::IsOnStack(instance));
  60. }
  61. bool JavascriptRegExp::Is(Var aValue)
  62. {
  63. return JavascriptOperators::GetTypeId(aValue) == TypeIds_RegEx;
  64. }
  65. // IsRegExp in the spec.
  66. bool JavascriptRegExp::IsRegExpLike(Var aValue, ScriptContext* scriptContext)
  67. {
  68. if (scriptContext->GetConfig()->IsES6RegExSymbolsEnabled())
  69. {
  70. if (!JavascriptOperators::IsObject(aValue))
  71. {
  72. return false;
  73. }
  74. Var symbolMatchProperty = JavascriptOperators::GetProperty(
  75. RecyclableObject::FromVar(aValue),
  76. PropertyIds::_symbolMatch,
  77. scriptContext);
  78. if (!JavascriptOperators::IsUndefined(symbolMatchProperty))
  79. {
  80. return JavascriptConversion::ToBool(symbolMatchProperty, scriptContext);
  81. }
  82. }
  83. return JavascriptRegExp::Is(aValue);
  84. }
  85. JavascriptRegExp* JavascriptRegExp::FromVar(Var aValue)
  86. {
  87. AssertOrFailFastMsg(Is(aValue), "Ensure var is actually a 'JavascriptRegExp'");
  88. return static_cast<JavascriptRegExp *>(aValue);
  89. }
  90. JavascriptRegExp* JavascriptRegExp::UnsafeFromVar(Var aValue)
  91. {
  92. AssertMsg(Is(aValue), "Ensure var is actually a 'JavascriptRegExp'");
  93. return static_cast<JavascriptRegExp *>(aValue);
  94. }
  95. CharCount JavascriptRegExp::GetLastIndexProperty(RecyclableObject* instance, ScriptContext* scriptContext)
  96. {
  97. int64 lastIndex = JavascriptConversion::ToLength(
  98. JavascriptOperators::GetProperty(instance, PropertyIds::lastIndex, scriptContext),
  99. scriptContext);
  100. return GetIndexOrMax(lastIndex);
  101. }
  102. void JavascriptRegExp::SetLastIndexProperty(Var instance, CharCount lastIndex, ScriptContext* scriptContext)
  103. {
  104. SetLastIndexProperty(
  105. instance,
  106. JavascriptNumber::ToVar(lastIndex, scriptContext),
  107. scriptContext);
  108. }
  109. void JavascriptRegExp::SetLastIndexProperty(Var instance, Var lastIndex, ScriptContext* scriptContext)
  110. {
  111. JavascriptOperators::SetProperty(
  112. instance,
  113. RecyclableObject::FromVar(instance),
  114. PropertyIds::lastIndex,
  115. lastIndex,
  116. scriptContext,
  117. static_cast<PropertyOperationFlags>(PropertyOperation_ThrowIfNotExtensible | PropertyOperation_ThrowIfNonWritable));
  118. }
  119. bool JavascriptRegExp::GetGlobalProperty(RecyclableObject* instance, ScriptContext* scriptContext)
  120. {
  121. return JavascriptConversion::ToBool(
  122. JavascriptOperators::GetProperty(instance, PropertyIds::global, scriptContext),
  123. scriptContext);
  124. }
  125. bool JavascriptRegExp::GetUnicodeProperty(RecyclableObject* instance, ScriptContext* scriptContext)
  126. {
  127. return JavascriptConversion::ToBool(
  128. JavascriptOperators::GetProperty(instance, PropertyIds::unicode, scriptContext),
  129. scriptContext);
  130. }
  131. CharCount JavascriptRegExp::AddIndex(CharCount base, CharCount offset)
  132. {
  133. return (base + offset < base) // Overflow?
  134. ? MaxCharCount
  135. : base + offset;
  136. }
  137. CharCount JavascriptRegExp::GetIndexOrMax(int64 index)
  138. {
  139. return (index > SIZE_MAX || IsValidCharCount((size_t) index))
  140. ? (CharCount) index
  141. : MaxCharCount;
  142. }
  143. InternalString JavascriptRegExp::GetSource() const
  144. {
  145. return GetPattern()->GetSource();
  146. }
  147. UnifiedRegex::RegexFlags JavascriptRegExp::GetFlags() const
  148. {
  149. return GetPattern()->GetFlags();
  150. }
  151. JavascriptRegExp* JavascriptRegExp::GetJavascriptRegExp(Arguments& args, PCWSTR propertyName, ScriptContext* scriptContext)
  152. {
  153. if (args.Info.Count == 0)
  154. {
  155. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedRegExp, propertyName);
  156. }
  157. return ToRegExp(args[0], propertyName, scriptContext);
  158. }
  159. JavascriptRegExp* JavascriptRegExp::ToRegExp(Var var, PCWSTR varName, ScriptContext* scriptContext)
  160. {
  161. JavascriptRegExp * regExp = JavascriptOperators::TryFromVar<JavascriptRegExp>(var);
  162. if (regExp)
  163. {
  164. return regExp;
  165. }
  166. if (JavascriptOperators::GetTypeId(var) == TypeIds_HostDispatch)
  167. {
  168. TypeId remoteTypeId = TypeIds_Limit;
  169. RecyclableObject* reclObj = RecyclableObject::UnsafeFromVar(var);
  170. if (reclObj->GetRemoteTypeId(&remoteTypeId) && remoteTypeId == TypeIds_RegEx)
  171. {
  172. return static_cast<JavascriptRegExp *>(reclObj->GetRemoteObject());
  173. }
  174. }
  175. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedRegExp, varName);
  176. }
  177. RecyclableObject* JavascriptRegExp::GetThisObject(Arguments& args, PCWSTR varName, ScriptContext* scriptContext)
  178. {
  179. if (args.Info.Count == 0 || !JavascriptOperators::IsObject(args[0]))
  180. {
  181. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedObject, varName);
  182. }
  183. return RecyclableObject::FromVar(args[0]);
  184. }
  185. JavascriptString* JavascriptRegExp::GetFirstStringArg(Arguments& args, ScriptContext* scriptContext)
  186. {
  187. if (args.Info.Count == 1)
  188. {
  189. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  190. }
  191. else
  192. {
  193. JavascriptString *jsString = JavascriptOperators::TryFromVar<JavascriptString>(args[1]);
  194. if (jsString)
  195. {
  196. return jsString;
  197. }
  198. else
  199. {
  200. return JavascriptConversion::ToString(args[1], scriptContext);
  201. }
  202. }
  203. }
  204. bool JavascriptRegExp::ShouldApplyPrototypeWebWorkaround(Arguments& args, ScriptContext* scriptContext)
  205. {
  206. return scriptContext->GetConfig()->IsES6PrototypeChain() && \
  207. args.Info.Count >= 1 && args[0] == scriptContext->GetLibrary()->GetRegExpPrototype();
  208. }
  209. Var JavascriptRegExp::NewInstance(RecyclableObject* function, CallInfo callInfo, ...)
  210. {
  211. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  212. ARGUMENTS(args, callInfo);
  213. ScriptContext* scriptContext = function->GetScriptContext();
  214. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  215. // SkipDefaultNewObject function flag should have prevented the default object from
  216. // being created, except when call true a host dispatch.
  217. Var newTarget = args.HasNewTarget() ? args.Values[args.Info.Count] : function;
  218. bool isCtorSuperCall = JavascriptOperators::GetAndAssertIsConstructorSuperCall(args);
  219. UnifiedRegex::RegexPattern* pattern = nullptr;
  220. UnifiedRegex::RegexPattern* splitPattern = nullptr;
  221. JavascriptRegExp* regex = nullptr;
  222. if (callInfo.Count < 2)
  223. {
  224. pattern = scriptContext->GetLibrary()->GetEmptyRegexPattern();
  225. }
  226. else if (JavascriptRegExp::IsRegExpLike(args[1], scriptContext))
  227. {
  228. // JavascriptRegExp::IsRegExpLike() makes sure that args[1] is an Object.
  229. RecyclableObject* regexLikeObj = RecyclableObject::FromVar(args[1]);
  230. if (!(callInfo.Flags & CallFlags_New) &&
  231. (callInfo.Count == 2 || JavascriptOperators::IsUndefinedObject(args[2])) &&
  232. newTarget == JavascriptOperators::GetProperty(regexLikeObj, PropertyIds::constructor, scriptContext))
  233. {
  234. // ES5 15.10.3.1 Called as a function: If pattern R is a regexp object and flags is undefined, then return R unchanged.
  235. // As per ES6 21.2.3.1: We should only return pattern when the this argument is not an uninitialized RegExp object.
  236. // If regex is null, we can be sure the this argument is not initialized.
  237. return regexLikeObj;
  238. }
  239. if (JavascriptRegExp::Is(regexLikeObj))
  240. {
  241. JavascriptRegExp* source = JavascriptRegExp::FromVar(regexLikeObj);
  242. if (callInfo.Count > 2)
  243. {
  244. // As per ES 2015 21.2.3.1: If 1st argument is RegExp and 2nd argument is flag then return regexp with same pattern as 1st
  245. // argument and flags supplied by the 2nd argument.
  246. if (!JavascriptOperators::IsUndefinedObject(args[2]))
  247. {
  248. InternalString str = source->GetSource();
  249. pattern = CreatePattern(JavascriptString::NewCopyBuffer(str.GetBuffer(), str.GetLength(), scriptContext),
  250. args[2], scriptContext);
  251. // "splitPattern" is a version of "pattern" without the sticky flag. If other flags are the same, we can safely
  252. // reuse "splitPattern".
  253. UnifiedRegex::RegexFlags currentSplitFlags =
  254. static_cast<UnifiedRegex::RegexFlags>(source->GetPattern()->GetFlags() & ~UnifiedRegex::StickyRegexFlag);
  255. UnifiedRegex::RegexFlags newSplitFlags =
  256. static_cast<UnifiedRegex::RegexFlags>(pattern->GetFlags() & ~UnifiedRegex::StickyRegexFlag);
  257. if (newSplitFlags == currentSplitFlags)
  258. {
  259. splitPattern = source->GetSplitPattern();
  260. }
  261. }
  262. }
  263. if (!pattern)
  264. {
  265. pattern = source->GetPattern();
  266. splitPattern = source->GetSplitPattern();
  267. }
  268. }
  269. else // RegExp-like
  270. {
  271. Var source = JavascriptOperators::GetProperty(regexLikeObj, PropertyIds::source, scriptContext);
  272. Var flags = args.Info.Count < 3 || JavascriptOperators::IsUndefinedObject(args[2])
  273. ? JavascriptOperators::GetProperty(regexLikeObj, PropertyIds::flags, scriptContext)
  274. : args[2];
  275. pattern = CreatePattern(source, flags, scriptContext);
  276. }
  277. }
  278. else
  279. {
  280. pattern = CreatePattern(args[1], (callInfo.Count > 2) ? args[2] : nullptr, scriptContext);
  281. }
  282. if (regex == nullptr)
  283. {
  284. regex = scriptContext->GetLibrary()->CreateRegExp(nullptr);
  285. }
  286. regex->SetPattern(pattern);
  287. regex->SetSplitPattern(splitPattern);
  288. return isCtorSuperCall ?
  289. JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), regex, nullptr, scriptContext) :
  290. regex;
  291. }
  292. UnifiedRegex::RegexPattern* JavascriptRegExp::CreatePattern(Var aValue, Var options, ScriptContext *scriptContext)
  293. {
  294. JavascriptString * strBody;
  295. if (JavascriptString::Is(aValue))
  296. {
  297. strBody = JavascriptString::FromVar(aValue);
  298. }
  299. else if (JavascriptOperators::GetTypeId(aValue) == TypeIds_Undefined)
  300. {
  301. strBody = scriptContext->GetLibrary()->GetEmptyString();
  302. }
  303. else
  304. {
  305. strBody = JavascriptConversion::ToString(aValue, scriptContext); // must be null terminated!
  306. }
  307. int cBody = strBody->GetLength();
  308. const char16 *szRegex = strBody->GetSz();
  309. int cOpts = 0;
  310. const char16 *szOptions = nullptr;
  311. JavascriptString * strOptions = nullptr;
  312. if (options != nullptr && !JavascriptOperators::IsUndefinedObject(options))
  313. {
  314. if (JavascriptString::Is(options))
  315. {
  316. strOptions = JavascriptString::FromVar(options);
  317. }
  318. else
  319. {
  320. strOptions = JavascriptConversion::ToString(options, scriptContext);
  321. }
  322. szOptions = strOptions->GetSz(); // must be null terminated!
  323. cOpts = strOptions->GetLength();
  324. }
  325. UnifiedRegex::RegexPattern* pattern = RegexHelper::CompileDynamic(scriptContext, szRegex, cBody, szOptions, cOpts, false);
  326. return pattern;
  327. }
  328. JavascriptRegExp* JavascriptRegExp::CreateRegEx(const char16* pSource, CharCount sourceLen, UnifiedRegex::RegexFlags flags, ScriptContext *scriptContext)
  329. {
  330. UnifiedRegex::RegexPattern* pattern = RegexHelper::CompileDynamic(scriptContext, pSource, sourceLen, flags, false);
  331. return scriptContext->GetLibrary()->CreateRegExp(pattern);
  332. }
  333. JavascriptRegExp* JavascriptRegExp::CreateRegEx(Var aValue, Var options, ScriptContext *scriptContext)
  334. {
  335. // This is called as helper from OpCode::CoerseRegEx. If aValue is regex pattern /a/, CreatePattern converts
  336. // it to pattern "/a/" instead of "a". So if we know that aValue is regex, then just return the same object
  337. if (JavascriptRegExp::Is(aValue))
  338. {
  339. return JavascriptRegExp::FromVar(aValue);
  340. }
  341. else
  342. {
  343. return CreateRegExNoCoerce(aValue, options, scriptContext);
  344. }
  345. }
  346. JavascriptRegExp* JavascriptRegExp::CreateRegExNoCoerce(Var aValue, Var options, ScriptContext *scriptContext)
  347. {
  348. UnifiedRegex::RegexPattern* pattern = CreatePattern(aValue, options, scriptContext);
  349. return scriptContext->GetLibrary()->CreateRegExp(pattern);
  350. }
  351. void JavascriptRegExp::CacheLastIndex()
  352. {
  353. if (lastIndexVar == nullptr)
  354. lastIndexOrFlag = 0;
  355. else
  356. {
  357. // Does ToInteger(lastIndex) yield an integer in [0, MaxCharCount]?
  358. double v = JavascriptConversion::ToInteger(lastIndexVar, GetScriptContext());
  359. if (JavascriptNumber::IsNan(v))
  360. lastIndexOrFlag = 0;
  361. else if (JavascriptNumber::IsPosInf(v) ||
  362. JavascriptNumber::IsNegInf(v) ||
  363. v < 0.0 ||
  364. v > (double)MaxCharCount)
  365. lastIndexOrFlag = InvalidValue;
  366. else
  367. lastIndexOrFlag = (CharCount)v;
  368. }
  369. }
  370. JavascriptString *JavascriptRegExp::ToString(bool sourceOnly)
  371. {
  372. Js::InternalString str = pattern->GetSource();
  373. CompoundString *const builder = CompoundString::NewWithCharCapacity(str.GetLength() + 5, GetLibrary());
  374. if (!sourceOnly)
  375. {
  376. builder->AppendChars(_u('/'));
  377. }
  378. if (pattern->IsLiteral())
  379. {
  380. builder->AppendChars(str.GetBuffer(), str.GetLength());
  381. }
  382. else
  383. {
  384. // Need to ensure that the resulting static regex is functionally equivalent (as written) to 'this' regex. This
  385. // involves the following:
  386. // - Empty regex should result in /(?:)/ rather than //, which is a comment
  387. // - Unescaped '/' needs to be escaped so that it doesn't end the static regex prematurely
  388. // - Line terminators need to be escaped since they're not allowed in a static regex
  389. if (str.GetLength() == 0)
  390. {
  391. builder->AppendChars(_u("(?:)"));
  392. }
  393. else
  394. {
  395. bool escape = false;
  396. for (charcount_t i = 0; i < str.GetLength(); ++i)
  397. {
  398. const char16 c = str.GetBuffer()[i];
  399. if(!escape)
  400. {
  401. switch(c)
  402. {
  403. case _u('/'):
  404. case _u('\n'):
  405. case _u('\r'):
  406. case _u('\x2028'):
  407. case _u('\x2029'):
  408. // Unescaped '/' or line terminator needs to be escaped
  409. break;
  410. case _u('\\'):
  411. // Escape sequence; the next character is escaped and shouldn't be escaped further
  412. escape = true;
  413. Assert(i + 1 < str.GetLength()); // cannot end in a '\'
  414. // '\' is appended on the next iteration as 'escape' is true. This handles the case where we
  415. // have an escaped line terminator (\<lineTerminator>), where \\n has a different meaning and we
  416. // need to use \n instead.
  417. continue;
  418. default:
  419. builder->AppendChars(c);
  420. continue;
  421. }
  422. }
  423. else
  424. {
  425. escape = false;
  426. }
  427. builder->AppendChars(_u('\\'));
  428. switch(c)
  429. {
  430. // Line terminators need to be escaped. \<lineTerminator> is a special case, where \\n doesn't work
  431. // since that means a '\' followed by an 'n'. We need to use \n instead.
  432. case _u('\n'):
  433. builder->AppendChars(_u('n'));
  434. break;
  435. case _u('\r'):
  436. builder->AppendChars(_u('r'));
  437. break;
  438. case _u('\x2028'):
  439. builder->AppendChars(_u("u2028"));
  440. break;
  441. case _u('\x2029'):
  442. builder->AppendChars(_u("u2029"));
  443. break;
  444. default:
  445. builder->AppendChars(c);
  446. }
  447. }
  448. }
  449. }
  450. if (!sourceOnly)
  451. {
  452. builder->AppendChars(_u('/'));
  453. // Cross-browser compatibility - flags are listed in alphabetical order in the spec and by other browsers
  454. // If you change the order of the flags, don't forget to change it in EntryGetterFlags() and GetOptions() too.
  455. if (pattern->IsGlobal())
  456. {
  457. builder->AppendChars(_u('g'));
  458. }
  459. if (pattern->IsIgnoreCase())
  460. {
  461. builder->AppendChars(_u('i'));
  462. }
  463. if (pattern->IsMultiline())
  464. {
  465. builder->AppendChars(_u('m'));
  466. }
  467. if (pattern->IsUnicode())
  468. {
  469. builder->AppendChars(_u('u'));
  470. }
  471. if (pattern->IsSticky())
  472. {
  473. builder->AppendChars(_u('y'));
  474. }
  475. }
  476. return builder;
  477. }
  478. Var JavascriptRegExp::EntryCompile(RecyclableObject* function, CallInfo callInfo, ...)
  479. {
  480. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  481. ARGUMENTS(args, callInfo);
  482. ScriptContext* scriptContext = function->GetScriptContext();
  483. JavascriptRegExp* thisRegularExpression = GetJavascriptRegExp(args, _u("RegExp.prototype.compile"), scriptContext);
  484. UnifiedRegex::RegexPattern* pattern;
  485. UnifiedRegex::RegexPattern* splitPattern = nullptr;
  486. if (callInfo.Count == 1 )
  487. {
  488. pattern = scriptContext->GetLibrary()->GetEmptyRegexPattern();
  489. }
  490. else if (JavascriptRegExp::Is(args[1]))
  491. {
  492. JavascriptRegExp* source = JavascriptRegExp::FromVar(args[1]);
  493. //compile with a regular expression
  494. pattern = source->GetPattern();
  495. splitPattern = source->GetSplitPattern();
  496. // second arg must be undefined if a reg expression is passed
  497. if(callInfo.Count > 2 && JavascriptOperators::GetTypeId(args[2]) != TypeIds_Undefined)
  498. {
  499. JavascriptError::ThrowSyntaxError(scriptContext, JSERR_RegExpSyntax);
  500. }
  501. }
  502. else
  503. {
  504. //compile with a string
  505. JavascriptString * strBody;
  506. if (JavascriptString::Is(args[1]))
  507. {
  508. strBody = JavascriptString::FromVar(args[1]);
  509. }
  510. else if(JavascriptOperators::GetTypeId(args[1]) == TypeIds_Undefined)
  511. {
  512. strBody = scriptContext->GetLibrary()->GetEmptyString();
  513. }
  514. else
  515. {
  516. strBody = JavascriptConversion::ToString(args[1], scriptContext);
  517. }
  518. int cBody = strBody->GetLength();
  519. const char16 *szRegex = strBody->GetSz(); // must be null terminated!
  520. int cOpts = 0;
  521. const char16 *szOptions = nullptr;
  522. JavascriptString * strOptions = nullptr;
  523. if (callInfo.Count > 2 && !JavascriptOperators::IsUndefinedObject(args[2]))
  524. {
  525. if (JavascriptString::Is(args[2]))
  526. {
  527. strOptions = JavascriptString::FromVar(args[2]);
  528. }
  529. else
  530. {
  531. strOptions = JavascriptConversion::ToString(args[2], scriptContext);
  532. }
  533. szOptions = strOptions->GetSz(); // must be null terminated!
  534. cOpts = strOptions->GetLength();
  535. }
  536. pattern = RegexHelper::CompileDynamic(scriptContext, szRegex, cBody, szOptions, cOpts, false);
  537. }
  538. thisRegularExpression->SetPattern(pattern);
  539. thisRegularExpression->SetSplitPattern(splitPattern);
  540. thisRegularExpression->SetLastIndex(0);
  541. return thisRegularExpression;
  542. }
  543. Var JavascriptRegExp::OP_NewRegEx(Var aCompiledRegex, ScriptContext* scriptContext)
  544. {
  545. JavascriptRegExp * pNewInstance =
  546. RecyclerNew(scriptContext->GetRecycler(),JavascriptRegExp,((UnifiedRegex::RegexPattern*)aCompiledRegex),
  547. scriptContext->GetLibrary()->GetRegexType());
  548. return pNewInstance;
  549. }
  550. Var JavascriptRegExp::EntryExec(RecyclableObject* function, CallInfo callInfo, ...)
  551. {
  552. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  553. ARGUMENTS(args, callInfo);
  554. ScriptContext* scriptContext = function->GetScriptContext();
  555. Assert(!(callInfo.Flags & CallFlags_New));
  556. JavascriptRegExp * pRegEx = GetJavascriptRegExp(args, _u("RegExp.prototype.exec"), scriptContext);
  557. JavascriptString * pStr = GetFirstStringArg(args, scriptContext);
  558. return RegexHelper::RegexExec(scriptContext, pRegEx, pStr, RegexHelper::IsResultNotUsed(callInfo.Flags));
  559. }
  560. Var JavascriptRegExp::EntryTest(RecyclableObject* function, CallInfo callInfo, ...)
  561. {
  562. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  563. ARGUMENTS(args, callInfo);
  564. ScriptContext* scriptContext = function->GetScriptContext();
  565. Assert(!(callInfo.Flags & CallFlags_New));
  566. RecyclableObject *thisObj = GetThisObject(args, _u("RegExp.prototype.test"), scriptContext);
  567. JavascriptString* string = GetFirstStringArg(args, scriptContext);
  568. return RegexHelper::RegexTest(scriptContext, thisObj, string);
  569. }
  570. Var JavascriptRegExp::EntryToString(RecyclableObject* function, CallInfo callInfo, ...)
  571. {
  572. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  573. ARGUMENTS(args, callInfo);
  574. ScriptContext* scriptContext = function->GetScriptContext();
  575. Assert(!(callInfo.Flags & CallFlags_New));
  576. Assert(args.Info.Count > 0);
  577. PCWSTR const varName = _u("RegExp.prototype.toString");
  578. const ScriptConfiguration* scriptConfig = scriptContext->GetConfig();
  579. if (scriptConfig->IsES6RegExPrototypePropertiesEnabled())
  580. {
  581. RecyclableObject *thisObj = GetThisObject(args, varName, scriptContext);
  582. JavascriptString* source = JavascriptConversion::ToString(
  583. JavascriptOperators::GetProperty(thisObj, PropertyIds::source, scriptContext),
  584. scriptContext);
  585. JavascriptString* flags = JavascriptConversion::ToString(
  586. JavascriptOperators::GetProperty(thisObj, PropertyIds::flags, scriptContext),
  587. scriptContext);
  588. CharCount length = source->GetLength() + flags->GetLength() + 2; // 2 for the two '/'s
  589. CompoundString *const builder =
  590. CompoundString::NewWithCharCapacity(length, scriptContext->GetLibrary());
  591. builder->Append(_u('/'));
  592. builder->Append(source);
  593. builder->Append(_u('/'));
  594. builder->Append(flags);
  595. return builder;
  596. }
  597. else
  598. {
  599. JavascriptRegExp* obj = GetJavascriptRegExp(args, varName, scriptContext);
  600. bool sourceOnly = false;
  601. return obj->ToString(sourceOnly);
  602. }
  603. }
  604. Var JavascriptRegExp::EntrySymbolMatch(RecyclableObject* function, CallInfo callInfo, ...)
  605. {
  606. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  607. ARGUMENTS(args, callInfo);
  608. Assert(!(callInfo.Flags & CallFlags_New));
  609. ScriptContext* scriptContext = function->GetScriptContext();
  610. CHAKRATEL_LANGSTATS_INC_LANGFEATURECOUNT(ES6, RegexSymbolMatch, scriptContext);
  611. PCWSTR const varName = _u("RegExp.prototype[Symbol.match]");
  612. RecyclableObject *thisObj = GetThisObject(args, varName, scriptContext);
  613. JavascriptString* string = GetFirstStringArg(args, scriptContext);
  614. return RegexHelper::RegexMatch(
  615. scriptContext,
  616. thisObj,
  617. string,
  618. RegexHelper::IsResultNotUsed(callInfo.Flags));
  619. }
  620. bool JavascriptRegExp::HasOriginalRegExType(RecyclableObject* instance)
  621. {
  622. JavascriptLibrary* library = instance->GetLibrary();
  623. if (instance->GetType() != library->GetRegexType())
  624. {
  625. return false;
  626. }
  627. DynamicObject* regexPrototype = library->GetRegExpPrototype();
  628. return JavascriptOperators::GetPrototype(instance) == regexPrototype
  629. && regexPrototype->GetType() == library->GetRegexPrototypeType();
  630. }
  631. bool JavascriptRegExp::HasObservableConstructor(DynamicObject* regexPrototype)
  632. {
  633. JavascriptLibrary* library = regexPrototype->GetLibrary();
  634. return regexPrototype->GetSlot(library->GetRegexConstructorSlotIndex()) != library->GetRegExpConstructor();
  635. }
  636. bool JavascriptRegExp::HasObservableExec(DynamicObject* regexPrototype)
  637. {
  638. JavascriptLibrary* library = regexPrototype->GetLibrary();
  639. return regexPrototype->GetSlot(library->GetRegexExecSlotIndex()) != library->GetRegexExecFunction();
  640. }
  641. bool JavascriptRegExp::HasObservableFlags(DynamicObject* regexPrototype)
  642. {
  643. JavascriptLibrary* library = regexPrototype->GetLibrary();
  644. return regexPrototype->GetScriptContext()->GetConfig()->IsES6RegExPrototypePropertiesEnabled()
  645. && regexPrototype->GetSlot(library->GetRegexFlagsGetterSlotIndex()) != library->GetRegexFlagsGetterFunction();
  646. }
  647. bool JavascriptRegExp::HasObservableGlobalFlag(DynamicObject* regexPrototype)
  648. {
  649. JavascriptLibrary* library = regexPrototype->GetLibrary();
  650. return regexPrototype->GetScriptContext()->GetConfig()->IsES6RegExPrototypePropertiesEnabled()
  651. && regexPrototype->GetSlot(library->GetRegexGlobalGetterSlotIndex()) != library->GetRegexGlobalGetterFunction();
  652. }
  653. bool JavascriptRegExp::HasObservableUnicodeFlag(DynamicObject* regexPrototype)
  654. {
  655. const ScriptConfiguration* scriptConfig = regexPrototype->GetScriptContext()->GetConfig();
  656. JavascriptLibrary* library = regexPrototype->GetLibrary();
  657. return scriptConfig->IsES6UnicodeExtensionsEnabled()
  658. && scriptConfig->IsES6RegExPrototypePropertiesEnabled()
  659. && regexPrototype->GetSlot(library->GetRegexUnicodeGetterSlotIndex()) != library->GetRegexUnicodeGetterFunction();
  660. }
  661. Var JavascriptRegExp::EntrySymbolReplace(RecyclableObject* function, CallInfo callInfo, ...)
  662. {
  663. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  664. ARGUMENTS(args, callInfo);
  665. Assert(!(callInfo.Flags & CallFlags_New));
  666. ScriptContext* scriptContext = function->GetScriptContext();
  667. CHAKRATEL_LANGSTATS_INC_LANGFEATURECOUNT(ES6, RegexSymbolReplace, scriptContext);
  668. PCWSTR varName = _u("RegExp.prototype[Symbol.replace]");
  669. RecyclableObject* thisObj = GetThisObject(args, varName, scriptContext);
  670. JavascriptString* string = GetFirstStringArg(args, scriptContext);
  671. Var replaceValue = (args.Info.Count > 2) ? args[2] : scriptContext->GetLibrary()->GetUndefined();
  672. if (JavascriptFunction::Is(replaceValue))
  673. {
  674. JavascriptFunction* replaceFunction = JavascriptFunction::FromVar(replaceValue);
  675. return RegexHelper::RegexReplaceFunction(scriptContext, thisObj, string, replaceFunction);
  676. }
  677. else
  678. {
  679. JavascriptString* replaceString = JavascriptConversion::ToString(replaceValue, scriptContext);
  680. return RegexHelper::RegexReplace(
  681. scriptContext,
  682. thisObj,
  683. string,
  684. replaceString,
  685. RegexHelper::IsResultNotUsed(callInfo.Flags));
  686. }
  687. }
  688. Var JavascriptRegExp::EntrySymbolSearch(RecyclableObject* function, CallInfo callInfo, ...)
  689. {
  690. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  691. ARGUMENTS(args, callInfo);
  692. Assert(!(callInfo.Flags & CallFlags_New));
  693. ScriptContext* scriptContext = function->GetScriptContext();
  694. CHAKRATEL_LANGSTATS_INC_LANGFEATURECOUNT(ES6, RegexSymbolSearch, scriptContext);
  695. PCWSTR const varName = _u("RegExp.prototype[Symbol.search]");
  696. RecyclableObject *thisObj = GetThisObject(args, varName, scriptContext);
  697. Var regEx = args[0];
  698. JavascriptString* string = GetFirstStringArg(args, scriptContext);
  699. Var previousLastIndex = JavascriptOperators::GetProperty(thisObj, PropertyIds::lastIndex, scriptContext);
  700. SetLastIndexProperty(regEx, TaggedInt::ToVarUnchecked(0), scriptContext);
  701. Var result = CallExec(thisObj, string, varName, scriptContext);
  702. SetLastIndexProperty(regEx, previousLastIndex, scriptContext);
  703. return JavascriptOperators::IsNull(result)
  704. ? TaggedInt::ToVarUnchecked(-1)
  705. : JavascriptOperators::GetProperty(RecyclableObject::FromVar(result), PropertyIds::index, scriptContext);
  706. }
  707. Var JavascriptRegExp::EntrySymbolSplit(RecyclableObject* function, CallInfo callInfo, ...)
  708. {
  709. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  710. ARGUMENTS(args, callInfo);
  711. Assert(!(callInfo.Flags & CallFlags_New));
  712. ScriptContext* scriptContext = function->GetScriptContext();
  713. CHAKRATEL_LANGSTATS_INC_LANGFEATURECOUNT(ES6, RegexSymbolSplit, scriptContext);
  714. RecyclableObject *thisObj = GetThisObject(args, _u("RegExp.prototype[Symbol.match]"), scriptContext);
  715. JavascriptString* string = GetFirstStringArg(args, scriptContext);
  716. // TODO: SPEC DEVIATION
  717. //
  718. // In RegexHelper::RegexSplit, we check if RegExp properties are overridden in order to determine
  719. // if the algorithm is observable. If it is, we go through the new ES6 algorithm, but otherwise, we
  720. // run the faster ES5 version.
  721. //
  722. // According to the spec, we're supposed to process "limit" after we use some of the RegExp properties.
  723. // However, there doesn't seem to be any reason why "limit" processing can't be pulled above the rest
  724. // in the spec. Therefore, we should see if such a spec update is OK. If not, this would have to be
  725. // moved to its correct place in the code.
  726. uint32 limit = (args.Info.Count < 3 || JavascriptOperators::IsUndefinedObject(args[2]))
  727. ? UINT_MAX
  728. : JavascriptConversion::ToUInt32(args[2], scriptContext);
  729. return RegexHelper::RegexSplit(
  730. scriptContext,
  731. thisObj,
  732. string,
  733. limit,
  734. RegexHelper::IsResultNotUsed(callInfo.Flags));
  735. }
  736. Var JavascriptRegExp::CallExec(RecyclableObject* thisObj, JavascriptString* string, PCWSTR varName, ScriptContext* scriptContext)
  737. {
  738. Var exec = JavascriptOperators::GetProperty(thisObj, PropertyIds::exec, scriptContext);
  739. if (JavascriptConversion::IsCallable(exec))
  740. {
  741. RecyclableObject* execFn = RecyclableObject::UnsafeFromVar(exec);
  742. ThreadContext * threadContext = scriptContext->GetThreadContext();
  743. Var result = threadContext->ExecuteImplicitCall(execFn, ImplicitCall_Accessor, [=]()->Js::Var
  744. {
  745. return CALL_FUNCTION(scriptContext->GetThreadContext(), execFn, CallInfo(CallFlags_Value, 2), thisObj, string);
  746. });
  747. if (!JavascriptOperators::IsObjectOrNull(result))
  748. {
  749. JavascriptError::ThrowTypeError(scriptContext, JSERR_RegExpExecInvalidReturnType, varName);
  750. }
  751. return result;
  752. }
  753. JavascriptRegExp* regExObj = ToRegExp(thisObj, varName, scriptContext);
  754. return RegexHelper::RegexExec(scriptContext, regExObj, string, false);
  755. }
  756. UnifiedRegex::RegexFlags JavascriptRegExp::SetRegexFlag(
  757. PropertyId propertyId,
  758. UnifiedRegex::RegexFlags flags,
  759. UnifiedRegex::RegexFlags flag,
  760. ScriptContext* scriptContext)
  761. {
  762. bool isEnabled = JavascriptConversion::ToBool(
  763. JavascriptOperators::GetProperty(this, propertyId, scriptContext),
  764. scriptContext);
  765. return isEnabled
  766. ? static_cast<UnifiedRegex::RegexFlags>(flags | flag)
  767. : static_cast<UnifiedRegex::RegexFlags>(flags & ~flag);
  768. }
  769. Var JavascriptRegExp::EntryGetterSymbolSpecies(RecyclableObject* function, CallInfo callInfo, ...)
  770. {
  771. ARGUMENTS(args, callInfo);
  772. Assert(args.Info.Count > 0);
  773. return args[0];
  774. }
  775. Var JavascriptRegExp::EntryGetterFlags(RecyclableObject* function, CallInfo callInfo, ...)
  776. {
  777. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  778. ARGUMENTS(args, callInfo);
  779. Assert(!(callInfo.Flags & CallFlags_New));
  780. ScriptContext* scriptContext = function->GetScriptContext();
  781. RecyclableObject *thisObj = GetThisObject(args, _u("RegExp.prototype.flags"), scriptContext);
  782. Var flags;
  783. BEGIN_TEMP_ALLOCATOR(tempAlloc, scriptContext, _u("JavascriptRegExp"))
  784. {
  785. StringBuilder<ArenaAllocator> bs(tempAlloc, 5);
  786. #define APPEND_FLAG(propertyId, flag) AppendFlagForFlagsProperty(&bs, thisObj, propertyId, flag, scriptContext)
  787. // If you change the order of the flags, don't forget to change it in GetOptions() and ToString() too.
  788. APPEND_FLAG(PropertyIds::global, _u('g'));
  789. APPEND_FLAG(PropertyIds::ignoreCase, _u('i'));
  790. APPEND_FLAG(PropertyIds::multiline, _u('m'));
  791. ScriptConfiguration const * scriptConfig = scriptContext->GetConfig();
  792. if (scriptConfig->IsES6UnicodeExtensionsEnabled())
  793. {
  794. APPEND_FLAG(PropertyIds::unicode, _u('u'));
  795. }
  796. if (scriptConfig->IsES6RegExStickyEnabled())
  797. {
  798. APPEND_FLAG(PropertyIds::sticky, _u('y'));
  799. }
  800. #undef APPEND_FLAG
  801. flags = Js::JavascriptString::NewCopyBuffer(bs.Detach(), bs.Count(), scriptContext);
  802. }
  803. END_TEMP_ALLOCATOR(tempAlloc, scriptContext);
  804. return flags;
  805. }
  806. void JavascriptRegExp::AppendFlagForFlagsProperty(
  807. StringBuilder<ArenaAllocator>* builder,
  808. RecyclableObject* thisObj,
  809. PropertyId propertyId,
  810. char16 flag,
  811. ScriptContext* scriptContext)
  812. {
  813. Var propertyValue = JavascriptOperators::GetProperty(thisObj, propertyId, scriptContext);
  814. if (JavascriptConversion::ToBoolean(propertyValue, scriptContext))
  815. {
  816. builder->Append(flag);
  817. }
  818. }
  819. Var JavascriptRegExp::EntryGetterOptions(RecyclableObject* function, CallInfo callInfo, ...)
  820. {
  821. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  822. ARGUMENTS(args, callInfo);
  823. Assert(!(callInfo.Flags & CallFlags_New));
  824. ScriptContext* scriptContext = function->GetScriptContext();
  825. if (ShouldApplyPrototypeWebWorkaround(args, scriptContext))
  826. {
  827. return scriptContext->GetLibrary()->GetUndefined();
  828. }
  829. return GetJavascriptRegExp(args, _u("RegExp.prototype.options"), scriptContext)->GetOptions();
  830. }
  831. Var JavascriptRegExp::GetOptions()
  832. {
  833. Var options;
  834. ScriptContext* scriptContext = this->GetLibrary()->GetScriptContext();
  835. BEGIN_TEMP_ALLOCATOR(tempAlloc, scriptContext, _u("JavascriptRegExp"))
  836. {
  837. StringBuilder<ArenaAllocator> bs(tempAlloc, 4);
  838. // If you change the order of the flags, don't forget to change it in EntryGetterFlags() and ToString() too.
  839. if(GetPattern()->IsGlobal())
  840. {
  841. bs.Append(_u('g'));
  842. }
  843. if(GetPattern()->IsIgnoreCase())
  844. {
  845. bs.Append(_u('i'));
  846. }
  847. if(GetPattern()->IsMultiline())
  848. {
  849. bs.Append(_u('m'));
  850. }
  851. if (GetPattern()->IsUnicode())
  852. {
  853. bs.Append(_u('u'));
  854. }
  855. if (GetPattern()->IsSticky())
  856. {
  857. bs.Append(_u('y'));
  858. }
  859. options = Js::JavascriptString::NewCopyBuffer(bs.Detach(), bs.Count(), scriptContext);
  860. }
  861. END_TEMP_ALLOCATOR(tempAlloc, scriptContext);
  862. return options;
  863. }
  864. Var JavascriptRegExp::EntryGetterSource(RecyclableObject* function, CallInfo callInfo, ...)
  865. {
  866. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  867. ARGUMENTS(args, callInfo);
  868. Assert(!(callInfo.Flags & CallFlags_New));
  869. ScriptContext* scriptContext = function->GetScriptContext();
  870. if (ShouldApplyPrototypeWebWorkaround(args, scriptContext))
  871. {
  872. return JavascriptString::NewCopyBuffer(_u("(?:)"), 4, scriptContext);
  873. }
  874. return GetJavascriptRegExp(args, _u("RegExp.prototype.source"), scriptContext)->ToString(true);
  875. }
  876. #define DEFINE_FLAG_GETTER(methodName, propertyName, patternMethodName) \
  877. Var JavascriptRegExp::##methodName##(RecyclableObject* function, CallInfo callInfo, ...) \
  878. { \
  879. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); \
  880. ARGUMENTS(args, callInfo); \
  881. Assert(!(callInfo.Flags & CallFlags_New)); \
  882. \
  883. ScriptContext* scriptContext = function->GetScriptContext(); \
  884. if (ShouldApplyPrototypeWebWorkaround(args, scriptContext)) \
  885. {\
  886. return scriptContext->GetLibrary()->GetUndefined(); \
  887. }\
  888. \
  889. JavascriptRegExp* pRegEx = GetJavascriptRegExp(args, _u("RegExp.prototype.") _u(#propertyName), scriptContext); \
  890. return pRegEx->GetLibrary()->CreateBoolean(pRegEx->GetPattern()->##patternMethodName##()); \
  891. }
  892. DEFINE_FLAG_GETTER(EntryGetterGlobal, global, IsGlobal)
  893. DEFINE_FLAG_GETTER(EntryGetterIgnoreCase, ignoreCase, IsIgnoreCase)
  894. DEFINE_FLAG_GETTER(EntryGetterMultiline, multiline, IsMultiline)
  895. DEFINE_FLAG_GETTER(EntryGetterSticky, sticky, IsSticky)
  896. DEFINE_FLAG_GETTER(EntryGetterUnicode, unicode, IsUnicode)
  897. JavascriptRegExp * JavascriptRegExp::BoxStackInstance(JavascriptRegExp * instance)
  898. {
  899. Assert(ThreadContext::IsOnStack(instance));
  900. // On the stack, the we reserved a pointer before the object as to store the boxed value
  901. JavascriptRegExp ** boxedInstanceRef = ((JavascriptRegExp **)instance) - 1;
  902. JavascriptRegExp * boxedInstance = *boxedInstanceRef;
  903. if (boxedInstance)
  904. {
  905. return boxedInstance;
  906. }
  907. Assert(instance->GetTypeHandler()->GetInlineSlotsSize() == 0);
  908. boxedInstance = RecyclerNew(instance->GetRecycler(), JavascriptRegExp, instance);
  909. *boxedInstanceRef = boxedInstance;
  910. return boxedInstance;
  911. }
  912. // Both 'unicode' and 'sticky' special properties could be controlled via config
  913. // flags. Below, 'sticky' is listed after 'unicode' (for no special reason).
  914. // When the 'unicode' config flag is disabled, we want 'unicode' to be excluded
  915. // from the list, but we still want 'sticky' to be included depending on its
  916. // config flag. That's the reason why we have two lists for the special property
  917. // IDs.
  918. #define DEFAULT_SPECIAL_PROPERTY_IDS \
  919. PropertyIds::lastIndex, \
  920. PropertyIds::global, \
  921. PropertyIds::multiline, \
  922. PropertyIds::ignoreCase, \
  923. PropertyIds::source, \
  924. PropertyIds::options
  925. PropertyId const JavascriptRegExp::specialPropertyIdsAll[] =
  926. {
  927. DEFAULT_SPECIAL_PROPERTY_IDS,
  928. PropertyIds::unicode,
  929. PropertyIds::sticky
  930. };
  931. PropertyId const JavascriptRegExp::specialPropertyIdsWithoutUnicode[] =
  932. {
  933. DEFAULT_SPECIAL_PROPERTY_IDS,
  934. PropertyIds::sticky
  935. };
  936. PropertyQueryFlags JavascriptRegExp::HasPropertyQuery(PropertyId propertyId)
  937. {
  938. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  939. #define HAS_PROPERTY(ownProperty) \
  940. return (ownProperty ? PropertyQueryFlags::Property_Found : DynamicObject::HasPropertyQuery(propertyId));
  941. switch (propertyId)
  942. {
  943. case PropertyIds::lastIndex:
  944. return PropertyQueryFlags::Property_Found;
  945. case PropertyIds::global:
  946. case PropertyIds::multiline:
  947. case PropertyIds::ignoreCase:
  948. case PropertyIds::source:
  949. case PropertyIds::options:
  950. HAS_PROPERTY(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  951. case PropertyIds::unicode:
  952. HAS_PROPERTY(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled())
  953. case PropertyIds::sticky:
  954. HAS_PROPERTY(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled())
  955. default:
  956. return DynamicObject::HasPropertyQuery(propertyId);
  957. }
  958. #undef HAS_PROPERTY
  959. }
  960. PropertyQueryFlags JavascriptRegExp::GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  961. {
  962. return JavascriptRegExp::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext);
  963. }
  964. PropertyQueryFlags JavascriptRegExp::GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  965. {
  966. BOOL result;
  967. if (GetPropertyBuiltIns(propertyId, value, &result))
  968. {
  969. return JavascriptConversion::BooleanToPropertyQueryFlags(result);
  970. }
  971. return DynamicObject::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext);
  972. }
  973. PropertyQueryFlags JavascriptRegExp::GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  974. {
  975. BOOL result;
  976. PropertyRecord const* propertyRecord;
  977. this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
  978. if (propertyRecord != nullptr && GetPropertyBuiltIns(propertyRecord->GetPropertyId(), value, &result))
  979. {
  980. return JavascriptConversion::BooleanToPropertyQueryFlags(result);
  981. }
  982. return DynamicObject::GetPropertyQuery(originalInstance, propertyNameString, value, info, requestContext);
  983. }
  984. bool JavascriptRegExp::GetPropertyBuiltIns(PropertyId propertyId, Var* value, BOOL* result)
  985. {
  986. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  987. #define GET_FLAG(patternMethod) \
  988. if (!scriptConfig->IsES6RegExPrototypePropertiesEnabled()) \
  989. { \
  990. *value = this->GetLibrary()->CreateBoolean(this->GetPattern()->##patternMethod##()); \
  991. *result = true; \
  992. return true; \
  993. } \
  994. else \
  995. { \
  996. return false; \
  997. }
  998. switch (propertyId)
  999. {
  1000. case PropertyIds::lastIndex:
  1001. if (this->lastIndexVar == nullptr)
  1002. {
  1003. Assert(lastIndexOrFlag <= MaxCharCount);
  1004. this->lastIndexVar = JavascriptNumber::ToVar(lastIndexOrFlag, GetScriptContext());
  1005. }
  1006. *value = this->lastIndexVar;
  1007. *result = true;
  1008. return true;
  1009. case PropertyIds::global:
  1010. GET_FLAG(IsGlobal)
  1011. case PropertyIds::multiline:
  1012. GET_FLAG(IsMultiline)
  1013. case PropertyIds::ignoreCase:
  1014. GET_FLAG(IsIgnoreCase)
  1015. case PropertyIds::unicode:
  1016. GET_FLAG(IsUnicode)
  1017. case PropertyIds::sticky:
  1018. GET_FLAG(IsSticky)
  1019. case PropertyIds::source:
  1020. if (!scriptConfig->IsES6RegExPrototypePropertiesEnabled())
  1021. {
  1022. *value = this->ToString(true);
  1023. *result = true;
  1024. return true;
  1025. }
  1026. else
  1027. {
  1028. return false;
  1029. }
  1030. case PropertyIds::options:
  1031. if (!scriptConfig->IsES6RegExPrototypePropertiesEnabled())
  1032. {
  1033. *value = GetOptions();
  1034. *result = true;
  1035. return true;
  1036. }
  1037. else
  1038. {
  1039. return false;
  1040. }
  1041. default:
  1042. return false;
  1043. }
  1044. #undef GET_FLAG
  1045. }
  1046. BOOL JavascriptRegExp::SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1047. {
  1048. BOOL result;
  1049. if (SetPropertyBuiltIns(propertyId, value, flags, &result))
  1050. {
  1051. return result;
  1052. }
  1053. return DynamicObject::SetProperty(propertyId, value, flags, info);
  1054. }
  1055. BOOL JavascriptRegExp::SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1056. {
  1057. BOOL result;
  1058. PropertyRecord const * propertyRecord;
  1059. this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
  1060. if (propertyRecord != nullptr && SetPropertyBuiltIns(propertyRecord->GetPropertyId(), value, flags, &result))
  1061. {
  1062. return result;
  1063. }
  1064. return DynamicObject::SetProperty(propertyNameString, value, flags, info);
  1065. }
  1066. bool JavascriptRegExp::SetPropertyBuiltIns(PropertyId propertyId, Var value, PropertyOperationFlags flags, BOOL* result)
  1067. {
  1068. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1069. #define SET_PROPERTY(ownProperty) \
  1070. if (ownProperty) \
  1071. { \
  1072. JavascriptError::ThrowCantAssignIfStrictMode(flags, this->GetScriptContext()); \
  1073. *result = false; \
  1074. return true; \
  1075. } \
  1076. return false;
  1077. switch (propertyId)
  1078. {
  1079. case PropertyIds::lastIndex:
  1080. this->lastIndexVar = value;
  1081. lastIndexOrFlag = NotCachedValue;
  1082. *result = true;
  1083. return true;
  1084. case PropertyIds::global:
  1085. case PropertyIds::multiline:
  1086. case PropertyIds::ignoreCase:
  1087. case PropertyIds::source:
  1088. case PropertyIds::options:
  1089. SET_PROPERTY(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1090. case PropertyIds::unicode:
  1091. SET_PROPERTY(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1092. case PropertyIds::sticky:
  1093. SET_PROPERTY(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1094. default:
  1095. return false;
  1096. }
  1097. #undef SET_PROPERTY
  1098. }
  1099. BOOL JavascriptRegExp::InitProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1100. {
  1101. return SetProperty(propertyId, value, flags, info);
  1102. }
  1103. BOOL JavascriptRegExp::DeleteProperty(PropertyId propertyId, PropertyOperationFlags propertyOperationFlags)
  1104. {
  1105. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1106. #define DELETE_PROPERTY(ownProperty) \
  1107. if (ownProperty) \
  1108. { \
  1109. JavascriptError::ThrowCantDeleteIfStrictMode(propertyOperationFlags, this->GetScriptContext(), this->GetScriptContext()->GetPropertyName(propertyId)->GetBuffer()); \
  1110. return false; \
  1111. } \
  1112. return DynamicObject::DeleteProperty(propertyId, propertyOperationFlags);
  1113. switch (propertyId)
  1114. {
  1115. case PropertyIds::lastIndex:
  1116. DELETE_PROPERTY(true);
  1117. case PropertyIds::global:
  1118. case PropertyIds::multiline:
  1119. case PropertyIds::ignoreCase:
  1120. case PropertyIds::source:
  1121. case PropertyIds::options:
  1122. DELETE_PROPERTY(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1123. case PropertyIds::unicode:
  1124. DELETE_PROPERTY(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1125. case PropertyIds::sticky:
  1126. DELETE_PROPERTY(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1127. default:
  1128. return DynamicObject::DeleteProperty(propertyId, propertyOperationFlags);
  1129. }
  1130. #undef DELETE_PROPERTY
  1131. }
  1132. BOOL JavascriptRegExp::DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags)
  1133. {
  1134. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1135. #define DELETE_PROPERTY(ownProperty) \
  1136. if (ownProperty) \
  1137. { \
  1138. JavascriptError::ThrowCantDeleteIfStrictMode(flags, this->GetScriptContext(), propertyNameString->GetString()); \
  1139. return false; \
  1140. } \
  1141. return DynamicObject::DeleteProperty(propertyNameString, flags);
  1142. if (BuiltInPropertyRecords::lastIndex.Equals(propertyNameString))
  1143. {
  1144. DELETE_PROPERTY(true);
  1145. }
  1146. else if (BuiltInPropertyRecords::global.Equals(propertyNameString)
  1147. || BuiltInPropertyRecords::multiline.Equals(propertyNameString)
  1148. || BuiltInPropertyRecords::ignoreCase.Equals(propertyNameString)
  1149. || BuiltInPropertyRecords::source.Equals(propertyNameString)
  1150. || BuiltInPropertyRecords::options.Equals(propertyNameString))
  1151. {
  1152. DELETE_PROPERTY(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1153. }
  1154. else if (BuiltInPropertyRecords::unicode.Equals(propertyNameString))
  1155. {
  1156. DELETE_PROPERTY(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1157. }
  1158. else if (BuiltInPropertyRecords::sticky.Equals(propertyNameString))
  1159. {
  1160. DELETE_PROPERTY(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1161. }
  1162. else
  1163. {
  1164. return DynamicObject::DeleteProperty(propertyNameString, flags);
  1165. }
  1166. #undef DELETE_PROPERTY
  1167. }
  1168. DescriptorFlags JavascriptRegExp::GetSetter(PropertyId propertyId, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  1169. {
  1170. DescriptorFlags result;
  1171. if (GetSetterBuiltIns(propertyId, info, &result))
  1172. {
  1173. return result;
  1174. }
  1175. return DynamicObject::GetSetter(propertyId, setterValue, info, requestContext);
  1176. }
  1177. DescriptorFlags JavascriptRegExp::GetSetter(JavascriptString* propertyNameString, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  1178. {
  1179. DescriptorFlags result;
  1180. PropertyRecord const * propertyRecord;
  1181. this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
  1182. if (propertyRecord != nullptr && GetSetterBuiltIns(propertyRecord->GetPropertyId(), info, &result))
  1183. {
  1184. return result;
  1185. }
  1186. return DynamicObject::GetSetter(propertyNameString, setterValue, info, requestContext);
  1187. }
  1188. bool JavascriptRegExp::GetSetterBuiltIns(PropertyId propertyId, PropertyValueInfo* info, DescriptorFlags* result)
  1189. {
  1190. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1191. #define GET_SETTER(ownProperty) \
  1192. if (ownProperty) \
  1193. { \
  1194. PropertyValueInfo::SetNoCache(info, this); \
  1195. *result = JavascriptRegExp::IsWritable(propertyId) ? WritableData : Data; \
  1196. return true; \
  1197. } \
  1198. return false;
  1199. switch (propertyId)
  1200. {
  1201. case PropertyIds::lastIndex:
  1202. GET_SETTER(true);
  1203. case PropertyIds::global:
  1204. case PropertyIds::multiline:
  1205. case PropertyIds::ignoreCase:
  1206. case PropertyIds::source:
  1207. case PropertyIds::options:
  1208. GET_SETTER(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1209. case PropertyIds::unicode:
  1210. GET_SETTER(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1211. case PropertyIds::sticky:
  1212. GET_SETTER(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1213. default:
  1214. return false;
  1215. }
  1216. #undef GET_SETTER
  1217. }
  1218. BOOL JavascriptRegExp::GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  1219. {
  1220. Js::InternalString str = pattern->GetSource();
  1221. stringBuilder->Append(str.GetBuffer(), str.GetLength());
  1222. return TRUE;
  1223. }
  1224. BOOL JavascriptRegExp::GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  1225. {
  1226. stringBuilder->AppendCppLiteral(JS_DIAG_TYPE_JavascriptRegExp);
  1227. return TRUE;
  1228. }
  1229. BOOL JavascriptRegExp::IsEnumerable(PropertyId propertyId)
  1230. {
  1231. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1232. #define IS_ENUMERABLE(ownProperty) \
  1233. return (ownProperty ? false : DynamicObject::IsEnumerable(propertyId));
  1234. switch (propertyId)
  1235. {
  1236. case PropertyIds::lastIndex:
  1237. return false;
  1238. case PropertyIds::global:
  1239. case PropertyIds::multiline:
  1240. case PropertyIds::ignoreCase:
  1241. case PropertyIds::source:
  1242. case PropertyIds::options:
  1243. IS_ENUMERABLE(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1244. case PropertyIds::unicode:
  1245. IS_ENUMERABLE(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1246. case PropertyIds::sticky:
  1247. IS_ENUMERABLE(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1248. default:
  1249. return DynamicObject::IsEnumerable(propertyId);
  1250. }
  1251. #undef IS_ENUMERABLE
  1252. }
  1253. BOOL JavascriptRegExp::IsConfigurable(PropertyId propertyId)
  1254. {
  1255. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1256. #define IS_CONFIGURABLE(ownProperty) \
  1257. return (ownProperty ? false : DynamicObject::IsConfigurable(propertyId));
  1258. switch (propertyId)
  1259. {
  1260. case PropertyIds::lastIndex:
  1261. return false;
  1262. case PropertyIds::global:
  1263. case PropertyIds::multiline:
  1264. case PropertyIds::ignoreCase:
  1265. case PropertyIds::source:
  1266. case PropertyIds::options:
  1267. IS_CONFIGURABLE(!scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1268. case PropertyIds::unicode:
  1269. IS_CONFIGURABLE(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1270. case PropertyIds::sticky:
  1271. IS_CONFIGURABLE(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1272. default:
  1273. return DynamicObject::IsConfigurable(propertyId);
  1274. }
  1275. #undef IS_CONFIGURABLE
  1276. }
  1277. BOOL JavascriptRegExp::IsWritable(PropertyId propertyId)
  1278. {
  1279. const ScriptConfiguration* scriptConfig = this->GetScriptContext()->GetConfig();
  1280. #define IS_WRITABLE(ownProperty) \
  1281. return (ownProperty ? false : DynamicObject::IsWritable(propertyId));
  1282. switch (propertyId)
  1283. {
  1284. case PropertyIds::lastIndex:
  1285. return true;
  1286. case PropertyIds::global:
  1287. case PropertyIds::multiline:
  1288. case PropertyIds::ignoreCase:
  1289. case PropertyIds::source:
  1290. case PropertyIds::options:
  1291. IS_WRITABLE(!scriptConfig->IsES6RegExPrototypePropertiesEnabled())
  1292. case PropertyIds::unicode:
  1293. IS_WRITABLE(scriptConfig->IsES6UnicodeExtensionsEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1294. case PropertyIds::sticky:
  1295. IS_WRITABLE(scriptConfig->IsES6RegExStickyEnabled() && !scriptConfig->IsES6RegExPrototypePropertiesEnabled());
  1296. default:
  1297. return DynamicObject::IsWritable(propertyId);
  1298. }
  1299. #undef IS_WRITABLE
  1300. }
  1301. BOOL JavascriptRegExp::GetSpecialPropertyName(uint32 index, JavascriptString ** propertyName, ScriptContext * requestContext)
  1302. {
  1303. uint length = GetSpecialPropertyCount();
  1304. if (index < length)
  1305. {
  1306. *propertyName = requestContext->GetPropertyString(GetSpecialPropertyIdsInlined()[index]);
  1307. return true;
  1308. }
  1309. return false;
  1310. }
  1311. // Returns the number of special non-enumerable properties this type has.
  1312. uint JavascriptRegExp::GetSpecialPropertyCount() const
  1313. {
  1314. if (GetScriptContext()->GetConfig()->IsES6RegExPrototypePropertiesEnabled())
  1315. {
  1316. return 1; // lastIndex
  1317. }
  1318. uint specialPropertyCount = defaultSpecialPropertyIdsCount;
  1319. if (GetScriptContext()->GetConfig()->IsES6UnicodeExtensionsEnabled())
  1320. {
  1321. specialPropertyCount += 1;
  1322. }
  1323. if (GetScriptContext()->GetConfig()->IsES6RegExStickyEnabled())
  1324. {
  1325. specialPropertyCount += 1;
  1326. }
  1327. return specialPropertyCount;
  1328. }
  1329. // Returns the list of special non-enumerable properties for the type.
  1330. PropertyId const * JavascriptRegExp::GetSpecialPropertyIds() const
  1331. {
  1332. return GetSpecialPropertyIdsInlined();
  1333. }
  1334. inline PropertyId const * JavascriptRegExp::GetSpecialPropertyIdsInlined() const
  1335. {
  1336. return GetScriptContext()->GetConfig()->IsES6UnicodeExtensionsEnabled()
  1337. ? specialPropertyIdsAll
  1338. : specialPropertyIdsWithoutUnicode;
  1339. }
  1340. #if ENABLE_TTD
  1341. TTD::NSSnapObjects::SnapObjectType JavascriptRegExp::GetSnapTag_TTD() const
  1342. {
  1343. return TTD::NSSnapObjects::SnapObjectType::SnapRegexObject;
  1344. }
  1345. void JavascriptRegExp::ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc)
  1346. {
  1347. TTD::NSSnapObjects::SnapRegexInfo* sri = alloc.SlabAllocateStruct<TTD::NSSnapObjects::SnapRegexInfo>();
  1348. UnifiedRegex::RegexPattern* pattern = this->pattern;
  1349. alloc.CopyStringIntoWLength(pattern->GetSource().GetBuffer(), pattern->GetSource().GetLength(), sri->RegexStr);
  1350. //split regex should be automatically generated from regex string and flags so no need to exttract it as well
  1351. sri->Flags = this->GetFlags();
  1352. sri->LastIndexVar = TTD_CONVERT_JSVAR_TO_TTDVAR(this->lastIndexVar);
  1353. sri->LastIndexOrFlag = this->lastIndexOrFlag;
  1354. TTD::NSSnapObjects::StdExtractSetKindSpecificInfo<TTD::NSSnapObjects::SnapRegexInfo*, TTD::NSSnapObjects::SnapObjectType::SnapRegexObject>(objData, sri);
  1355. }
  1356. void JavascriptRegExp::SetLastIndexInfo_TTD(CharCount lastIndex, Js::Var lastVar)
  1357. {
  1358. this->lastIndexOrFlag = lastIndex;
  1359. this->lastIndexVar = lastVar;
  1360. }
  1361. #endif
  1362. } // namespace Js