API: expose RegExp.
authorvitalyr@chromium.org <vitalyr@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 4 Oct 2010 15:04:16 +0000 (15:04 +0000)
committervitalyr@chromium.org <vitalyr@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 4 Oct 2010 15:04:16 +0000 (15:04 +0000)
Review URL: http://codereview.chromium.org/3585010

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5584 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

include/v8.h
src/api.cc
src/api.h
test/cctest/test-api.cc

index 0613d5861ca2246a1d187ff2331d05ce9930902b..9ee1687d69e080689bcd66f69ca39d7c5de59678 100644 (file)
@@ -1359,6 +1359,36 @@ class Date : public Value {
 };
 
 
+/**
+ * An instance of the built-in RegExp constructor (ECMA-262, 15.10).
+ */
+class RegExp : public Value {
+ public:
+  enum Flags {
+    kNone = 0,
+    kGlobal = 1,
+    kIgnoreCase = 2,
+    kMultiline = 4
+  };
+
+  V8EXPORT static Local<RegExp> New(Handle<String> pattern,
+                                    Flags flags);
+
+  /**
+   * Returns the value of the source property: a string representing
+   * the regular expression.
+   */
+  V8EXPORT Local<String> GetSource() const;
+
+  V8EXPORT Flags GetFlags() const;
+
+  static inline RegExp* Cast(v8::Value* obj);
+
+ private:
+  V8EXPORT static void CheckCast(v8::Value* obj);
+};
+
+
 enum PropertyAttribute {
   None       = 0,
   ReadOnly   = 1 << 0,
@@ -3617,6 +3647,14 @@ Date* Date::Cast(v8::Value* value) {
 }
 
 
+RegExp* RegExp::Cast(v8::Value* value) {
+#ifdef V8_ENABLE_CHECKS
+  CheckCast(value);
+#endif
+  return static_cast<RegExp*>(value);
+}
+
+
 Object* Object::Cast(v8::Value* value) {
 #ifdef V8_ENABLE_CHECKS
   CheckCast(value);
index 350410a3cc6d0998fcc0f259a73985c2a9f25bde..7ca9e8fad94f9034b909a9e9a18e077a857e8992 100644 (file)
@@ -1991,6 +1991,15 @@ void v8::Date::CheckCast(v8::Value* that) {
 }
 
 
+void v8::RegExp::CheckCast(v8::Value* that) {
+  if (IsDeadCheck("v8::RegExp::Cast()")) return;
+  i::Handle<i::Object> obj = Utils::OpenHandle(that);
+  ApiCheck(obj->IsJSRegExp(),
+           "v8::RegExp::Cast()",
+           "Could not convert to regular expression");
+}
+
+
 bool Value::BooleanValue() const {
   if (IsDeadCheck("v8::Value::BooleanValue()")) return false;
   LOG_API("BooleanValue");
@@ -3712,6 +3721,62 @@ double v8::Date::NumberValue() const {
 }
 
 
+static i::Handle<i::String> RegExpFlagsToString(RegExp::Flags flags) {
+  char flags_buf[3];
+  int num_flags = 0;
+  if ((flags & RegExp::kGlobal) != 0) flags_buf[num_flags++] = 'g';
+  if ((flags & RegExp::kMultiline) != 0) flags_buf[num_flags++] = 'm';
+  if ((flags & RegExp::kIgnoreCase) != 0) flags_buf[num_flags++] = 'i';
+  ASSERT(num_flags <= static_cast<int>(ARRAY_SIZE(flags_buf)));
+  return i::Factory::LookupSymbol(
+      i::Vector<const char>(flags_buf, num_flags));
+}
+
+
+Local<v8::RegExp> v8::RegExp::New(Handle<String> pattern,
+                                  Flags flags) {
+  EnsureInitialized("v8::RegExp::New()");
+  LOG_API("RegExp::New");
+  ENTER_V8;
+  EXCEPTION_PREAMBLE();
+  i::Handle<i::String> flags_string = RegExpFlagsToString(flags);
+  i::Object** argv[2] = {
+    i::Handle<i::Object>::cast(Utils::OpenHandle(*pattern)).location(),
+    i::Handle<i::Object>::cast(flags_string).location()
+  };
+  i::Handle<i::Object> obj = i::Execution::New(
+      i::Handle<i::JSFunction>(i::Top::global_context()->regexp_function()),
+      2, argv,
+      &has_pending_exception);
+  EXCEPTION_BAILOUT_CHECK(Local<v8::RegExp>());
+  return Utils::ToLocal(i::Handle<i::JSRegExp>::cast(obj));
+}
+
+
+Local<v8::String> v8::RegExp::GetSource() const {
+  if (IsDeadCheck("v8::RegExp::GetSource()")) return Local<v8::String>();
+  i::Handle<i::JSRegExp> obj = Utils::OpenHandle(this);
+  return Utils::ToLocal(i::Handle<i::String>(obj->Pattern()));
+}
+
+
+// Assert that the static flags cast in GetFlags is valid.
+#define REGEXP_FLAG_ASSERT_EQ(api_flag, internal_flag)        \
+  STATIC_ASSERT(static_cast<int>(v8::RegExp::api_flag) ==     \
+                static_cast<int>(i::JSRegExp::internal_flag))
+REGEXP_FLAG_ASSERT_EQ(kNone, NONE);
+REGEXP_FLAG_ASSERT_EQ(kGlobal, GLOBAL);
+REGEXP_FLAG_ASSERT_EQ(kIgnoreCase, IGNORE_CASE);
+REGEXP_FLAG_ASSERT_EQ(kMultiline, MULTILINE);
+#undef REGEXP_FLAG_ASSERT_EQ
+
+v8::RegExp::Flags v8::RegExp::GetFlags() const {
+  if (IsDeadCheck("v8::RegExp::GetFlags()")) return v8::RegExp::kNone;
+  i::Handle<i::JSRegExp> obj = Utils::OpenHandle(this);
+  return static_cast<RegExp::Flags>(obj->GetFlags().value());
+}
+
+
 Local<v8::Array> v8::Array::New(int length) {
   EnsureInitialized("v8::Array::New()");
   LOG_API("Array::New");
index 5c671369de6cff539d166d983011e68de13be6b0..e179e35672ff69bfcb84333c33f0c11a3e557b96 100644 (file)
--- a/src/api.h
+++ b/src/api.h
@@ -174,6 +174,8 @@ class Utils {
       v8::internal::Handle<v8::internal::JSFunction> obj);
   static inline Local<String> ToLocal(
       v8::internal::Handle<v8::internal::String> obj);
+  static inline Local<RegExp> ToLocal(
+      v8::internal::Handle<v8::internal::JSRegExp> obj);
   static inline Local<Object> ToLocal(
       v8::internal::Handle<v8::internal::JSObject> obj);
   static inline Local<Array> ToLocal(
@@ -209,6 +211,8 @@ class Utils {
       OpenHandle(const ObjectTemplate* that);
   static inline v8::internal::Handle<v8::internal::Object>
       OpenHandle(const Data* data);
+  static inline v8::internal::Handle<v8::internal::JSRegExp>
+      OpenHandle(const RegExp* data);
   static inline v8::internal::Handle<v8::internal::JSObject>
       OpenHandle(const v8::Object* data);
   static inline v8::internal::Handle<v8::internal::JSArray>
@@ -265,6 +269,7 @@ MAKE_TO_LOCAL(ToLocal, Context, Context)
 MAKE_TO_LOCAL(ToLocal, Object, Value)
 MAKE_TO_LOCAL(ToLocal, JSFunction, Function)
 MAKE_TO_LOCAL(ToLocal, String, String)
+MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp)
 MAKE_TO_LOCAL(ToLocal, JSObject, Object)
 MAKE_TO_LOCAL(ToLocal, JSArray, Array)
 MAKE_TO_LOCAL(ToLocal, Proxy, External)
@@ -297,6 +302,7 @@ MAKE_OPEN_HANDLE(ObjectTemplate, ObjectTemplateInfo)
 MAKE_OPEN_HANDLE(Signature, SignatureInfo)
 MAKE_OPEN_HANDLE(TypeSwitch, TypeSwitchInfo)
 MAKE_OPEN_HANDLE(Data, Object)
+MAKE_OPEN_HANDLE(RegExp, JSRegExp)
 MAKE_OPEN_HANDLE(Object, JSObject)
 MAKE_OPEN_HANDLE(Array, JSArray)
 MAKE_OPEN_HANDLE(String, String)
index f1a6eada40e8619d92bdb255ce5f8f9f261fc62a..0631351c1826c6fe1d88dee3a38d664b523b399e 100644 (file)
@@ -11619,3 +11619,61 @@ TEST(GlobalLoadICGC) {
     CheckSurvivingGlobalObjectsCount(1);
   }
 }
+
+
+TEST(RegExp) {
+  v8::HandleScope scope;
+  LocalContext context;
+
+  v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
+  CHECK(re->IsRegExp());
+  CHECK(re->GetSource()->Equals(v8_str("foo")));
+  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
+
+  re = v8::RegExp::New(v8_str("bar"),
+                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
+                                                      v8::RegExp::kGlobal));
+  CHECK(re->IsRegExp());
+  CHECK(re->GetSource()->Equals(v8_str("bar")));
+  CHECK_EQ(static_cast<int>(re->GetFlags()),
+           v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal);
+
+  re = v8::RegExp::New(v8_str("baz"),
+                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
+                                                      v8::RegExp::kMultiline));
+  CHECK(re->IsRegExp());
+  CHECK(re->GetSource()->Equals(v8_str("baz")));
+  CHECK_EQ(static_cast<int>(re->GetFlags()),
+           v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
+
+  re = CompileRun("/quux/").As<v8::RegExp>();
+  CHECK(re->IsRegExp());
+  CHECK(re->GetSource()->Equals(v8_str("quux")));
+  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
+
+  re = CompileRun("/quux/gm").As<v8::RegExp>();
+  CHECK(re->IsRegExp());
+  CHECK(re->GetSource()->Equals(v8_str("quux")));
+  CHECK_EQ(static_cast<int>(re->GetFlags()),
+           v8::RegExp::kGlobal | v8::RegExp::kMultiline);
+
+  // Override the RegExp constructor and check the API constructor
+  // still works.
+  CompileRun("RegExp = function() {}");
+
+  re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
+  CHECK(re->IsRegExp());
+  CHECK(re->GetSource()->Equals(v8_str("foobar")));
+  CHECK_EQ(re->GetFlags(), v8::RegExp::kNone);
+
+  re = v8::RegExp::New(v8_str("foobarbaz"),
+                       static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
+                                                      v8::RegExp::kMultiline));
+  CHECK(re->IsRegExp());
+  CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
+  CHECK_EQ(static_cast<int>(re->GetFlags()),
+           v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline);
+
+  context->Global()->Set(v8_str("re"), re);
+  ExpectTrue("re.test('FoobarbaZ')");
+}