RegexPattern.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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 "ParserPch.h"
  6. namespace UnifiedRegex
  7. {
  8. RegexPattern::RegexPattern(Js::JavascriptLibrary *const library, Program* program, bool isLiteral)
  9. : library(library), isLiteral(isLiteral), isShallowClone(false)
  10. {
  11. rep.unified.program = program;
  12. rep.unified.matcher = 0;
  13. rep.unified.trigramInfo = 0;
  14. }
  15. RegexPattern *RegexPattern::New(Js::ScriptContext *scriptContext, Program* program, bool isLiteral)
  16. {
  17. return
  18. RecyclerNewFinalized(
  19. scriptContext->GetRecycler(),
  20. RegexPattern,
  21. scriptContext->GetLibrary(),
  22. program,
  23. isLiteral);
  24. }
  25. void RegexPattern::Finalize(bool isShutdown)
  26. {
  27. if(isShutdown)
  28. return;
  29. const auto scriptContext = GetScriptContext();
  30. if(!scriptContext)
  31. return;
  32. #if DBG
  33. // In JSRT, we might not have a chance to close at finalize time.
  34. if(!isLiteral && !scriptContext->IsClosed() && !scriptContext->GetThreadContext()->IsJSRT())
  35. {
  36. const auto source = GetSource();
  37. RegexPattern *p;
  38. Assert(
  39. !GetScriptContext()->GetDynamicRegexMap()->TryGetValue(
  40. RegexKey(source.GetBuffer(), source.GetLength(), GetFlags()),
  41. &p) || ( source.GetLength() == 0 ) ||
  42. p != this);
  43. }
  44. #endif
  45. if(isShallowClone)
  46. return;
  47. rep.unified.program->FreeBody(scriptContext->RegexAllocator());
  48. }
  49. void RegexPattern::Dispose(bool isShutdown)
  50. {
  51. }
  52. Js::ScriptContext *RegexPattern::GetScriptContext() const
  53. {
  54. return library->GetScriptContext();
  55. }
  56. Js::InternalString RegexPattern::GetSource() const
  57. {
  58. return Js::InternalString(rep.unified.program->source, rep.unified.program->sourceLen);
  59. }
  60. RegexFlags RegexPattern::GetFlags() const
  61. {
  62. return rep.unified.program->flags;
  63. }
  64. int RegexPattern::NumGroups() const
  65. {
  66. return rep.unified.program->numGroups;
  67. }
  68. bool RegexPattern::IsIgnoreCase() const
  69. {
  70. return (rep.unified.program->flags & IgnoreCaseRegexFlag) != 0;
  71. }
  72. bool RegexPattern::IsGlobal() const
  73. {
  74. return (rep.unified.program->flags & GlobalRegexFlag) != 0;
  75. }
  76. bool RegexPattern::IsMultiline() const
  77. {
  78. return (rep.unified.program->flags & MultilineRegexFlag) != 0;
  79. }
  80. bool RegexPattern::IsUnicode() const
  81. {
  82. return GetScriptContext()->GetConfig()->IsES6UnicodeExtensionsEnabled() && (rep.unified.program->flags & UnicodeRegexFlag) != 0;
  83. }
  84. bool RegexPattern::IsSticky() const
  85. {
  86. return GetScriptContext()->GetConfig()->IsES6RegExStickyEnabled() && (rep.unified.program->flags & StickyRegexFlag) != 0;
  87. }
  88. bool RegexPattern::WasLastMatchSuccessful() const
  89. {
  90. return rep.unified.matcher != 0 && rep.unified.matcher->WasLastMatchSuccessful();
  91. }
  92. GroupInfo RegexPattern::GetGroup(int groupId) const
  93. {
  94. Assert(groupId == 0 || WasLastMatchSuccessful());
  95. Assert(groupId >= 0 && groupId < NumGroups());
  96. return rep.unified.matcher->GetGroup(groupId);
  97. }
  98. RegexPattern *RegexPattern::CopyToScriptContext(Js::ScriptContext *scriptContext)
  99. {
  100. // This routine assumes that this instance will outlive the copy, which is the case for copy-on-write,
  101. // and therefore doesn't copy the immutable parts of the pattern. This should not be confused with a
  102. // would be CloneToScriptContext which will would clone the immutable parts as well because the lifetime
  103. // of a clone might be longer than the original.
  104. RegexPattern *result = UnifiedRegex::RegexPattern::New(scriptContext, rep.unified.program, isLiteral);
  105. Matcher *matcherClone = rep.unified.matcher ? rep.unified.matcher->CloneToScriptContext(scriptContext, result) : nullptr;
  106. result->rep.unified.matcher = matcherClone;
  107. result->isShallowClone = true;
  108. return result;
  109. }
  110. #if ENABLE_REGEX_CONFIG_OPTIONS
  111. void RegexPattern::Print(DebugWriter* w)
  112. {
  113. w->Print(_u("/"));
  114. Js::InternalString str = GetSource();
  115. if (str.GetLength() == 0)
  116. w->Print(_u("(?:)"));
  117. else
  118. {
  119. for (charcount_t i = 0; i < str.GetLength(); ++i)
  120. {
  121. const char16 c = str.GetBuffer()[i];
  122. switch(c)
  123. {
  124. case _u('/'):
  125. w->Print(_u("\\%lc"), c);
  126. break;
  127. case _u('\n'):
  128. case _u('\r'):
  129. case _u('\x2028'):
  130. case _u('\x2029'):
  131. w->PrintEscapedChar(c);
  132. break;
  133. case _u('\\'):
  134. Assert(i + 1 < str.GetLength()); // cannot end in a '\'
  135. w->Print(_u("\\%lc"), str.GetBuffer()[++i]);
  136. break;
  137. default:
  138. w->PrintEscapedChar(c);
  139. break;
  140. }
  141. }
  142. }
  143. w->Print(_u("/"));
  144. if (IsIgnoreCase())
  145. w->Print(_u("i"));
  146. if (IsGlobal())
  147. w->Print(_u("g"));
  148. if (IsMultiline())
  149. w->Print(_u("m"));
  150. if (IsUnicode())
  151. w->Print(_u("u"));
  152. if (IsSticky())
  153. w->Print(_u("y"));
  154. w->Print(_u(" /* "));
  155. w->Print(_u(", "));
  156. w->Print(isLiteral ? _u("literal") : _u("dynamic"));
  157. w->Print(_u(" */"));
  158. }
  159. #endif
  160. }