RegExpPrototype.cs 4.7 KB

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