RegexPattern.cpp 5.6 KB

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