RegExpPrototype.cs 4.7 KB

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