RegExpPrototype.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. using System.Text.RegularExpressions;
  2. using Jint.Collections;
  3. using Jint.Native.Array;
  4. using Jint.Native.Object;
  5. using Jint.Runtime;
  6. using Jint.Runtime.Descriptors;
  7. using Jint.Runtime.Interop;
  8. namespace Jint.Native.RegExp
  9. {
  10. public sealed class RegExpPrototype : RegExpInstance
  11. {
  12. private RegExpConstructor _regExpConstructor;
  13. private RegExpPrototype(Engine engine)
  14. : base(engine)
  15. {
  16. }
  17. public static RegExpPrototype CreatePrototypeObject(Engine engine, RegExpConstructor regExpConstructor)
  18. {
  19. var obj = new RegExpPrototype(engine)
  20. {
  21. Prototype = engine.Object.PrototypeObject,
  22. Extensible = true,
  23. _regExpConstructor = regExpConstructor
  24. };
  25. return obj;
  26. }
  27. protected override void Initialize()
  28. {
  29. _properties = new StringDictionarySlim<PropertyDescriptor>(10)
  30. {
  31. ["constructor"] = new PropertyDescriptor(_regExpConstructor, true, false, true),
  32. ["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToRegExpString), true, false, true),
  33. ["exec"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "exec", Exec, 1), true, false, true),
  34. ["test"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "test", Test, 1), true, false, true),
  35. ["global"] = new PropertyDescriptor(false, false, false, false),
  36. ["ignoreCase"] = new PropertyDescriptor(false, false, false, false),
  37. ["multiline"] = new PropertyDescriptor(false, false, false, false),
  38. ["source"] = new PropertyDescriptor("(?:)", false, false, false),
  39. ["flags"] = new PropertyDescriptor("", false, false, false),
  40. ["lastIndex"] = new PropertyDescriptor(0, true, false, false)
  41. };
  42. }
  43. private static JsValue ToRegExpString(JsValue thisObj, JsValue[] arguments)
  44. {
  45. var regexObj = thisObj.TryCast<ObjectInstance>();
  46. if (regexObj.TryGetValue("source", out var source) == false)
  47. source = Undefined.ToString();
  48. if (regexObj.TryGetValue("flags", out var flags) == false)
  49. flags = Undefined.ToString();
  50. return $"/{source.AsString()}/{flags.AsString()}";
  51. }
  52. private JsValue Test(JsValue thisObj, JsValue[] arguments)
  53. {
  54. var r = TypeConverter.ToObject(Engine, thisObj);
  55. if (r.Class != "RegExp")
  56. {
  57. ExceptionHelper.ThrowTypeError(Engine);
  58. }
  59. var match = Exec(r, arguments);
  60. return !match.IsNull();
  61. }
  62. internal JsValue Exec(JsValue thisObj, JsValue[] arguments)
  63. {
  64. var R = TypeConverter.ToObject(Engine, thisObj) as RegExpInstance;
  65. if (ReferenceEquals(R, null))
  66. {
  67. ExceptionHelper.ThrowTypeError(Engine);
  68. }
  69. var s = TypeConverter.ToString(arguments.At(0));
  70. var length = s.Length;
  71. var lastIndex = TypeConverter.ToNumber(R.Get("lastIndex"));
  72. var i = TypeConverter.ToInteger(lastIndex);
  73. var global = R.Global;
  74. if (!global)
  75. {
  76. i = 0;
  77. }
  78. if (R.Source == "(?:)") // Reg Exp is really ""
  79. {
  80. // "aaa".match() => [ '', index: 0, input: 'aaa' ]
  81. var aa = InitReturnValueArray((ArrayInstance) Engine.Array.Construct(Arguments.Empty), s, 1, 0);
  82. aa.DefineOwnProperty("0", new PropertyDescriptor("", PropertyFlag.ConfigurableEnumerableWritable), true);
  83. return aa;
  84. }
  85. Match r = null;
  86. if (i < 0 || i > length)
  87. {
  88. R.Put("lastIndex", (double) 0, true);
  89. return Null;
  90. }
  91. r = R.Match(s, i);
  92. if (!r.Success)
  93. {
  94. R.Put("lastIndex", (double) 0, true);
  95. return Null;
  96. }
  97. var e = r.Index + r.Length;
  98. if (global)
  99. {
  100. R.Put("lastIndex", (double) e, true);
  101. }
  102. var n = r.Groups.Count;
  103. var matchIndex = r.Index;
  104. var a = InitReturnValueArray((ArrayInstance) Engine.Array.Construct(Arguments.Empty), s, n, matchIndex);
  105. for (uint k = 0; k < n; k++)
  106. {
  107. var group = r.Groups[(int) k];
  108. var value = group.Success ? group.Value : Undefined;
  109. a.SetIndexValue(k, value, updateLength: false);
  110. }
  111. a.SetLength((uint) n);
  112. return a;
  113. }
  114. private static ArrayInstance InitReturnValueArray(ArrayInstance array, string inputValue, int lengthValue, int indexValue)
  115. {
  116. array.SetOwnProperty("index", new PropertyDescriptor(indexValue, PropertyFlag.ConfigurableEnumerableWritable));
  117. array.SetOwnProperty("input", new PropertyDescriptor(inputValue, PropertyFlag.ConfigurableEnumerableWritable));
  118. array.SetOwnProperty(KnownKeys.Length, new PropertyDescriptor(lengthValue, PropertyFlag.OnlyWritable));
  119. return array;
  120. }
  121. }
  122. }