Browse Source

Merge pull request #13379 from electron/native-mate-in-electron

Merge native_mate into electron/electron
Samuel Attard 6 years ago
parent
commit
a96fc9170c

+ 0 - 3
.gitmodules

@@ -7,9 +7,6 @@
 [submodule "vendor/breakpad"]
 	path = vendor/breakpad
 	url = https://github.com/electron/chromium-breakpad.git
-[submodule "vendor/native_mate"]
-	path = vendor/native_mate
-	url = https://github.com/electron/native-mate.git
 [submodule "vendor/crashpad"]
 	path = vendor/crashpad
 	url = https://github.com/electron/crashpad.git

+ 1 - 1
docs/README.md

@@ -129,7 +129,7 @@ These individual tutorials expand on topics discussed in the guide above.
 * [Menu](api/menu.md)
 * [MenuItem](api/menu-item.md)
 * [net](api/net.md)
-* [netLog](api/netLog.md)
+* [netLog](api/net-log.md)
 * [powerMonitor](api/power-monitor.md)
 * [powerSaveBlocker](api/power-save-blocker.md)
 * [protocol](api/protocol.md)

+ 1 - 1
docs/api/breaking-changes.md

@@ -1,6 +1,6 @@
 # API Contract
 
-Breaking changes will be documented here, and deprecation warnings added to JS code where possible, at least [one major version](electron-versioning.md#semver) before the change is made.
+Breaking changes will be documented here, and deprecation warnings added to JS code where possible, at least [one major version](../tutorial/electron-versioning.md#semver) before the change is made.
 
 # `FIXME` comments
 

+ 2 - 2
electron.gyp

@@ -10,7 +10,7 @@
   'includes': [
     'features.gypi',
     'filenames.gypi',
-    'vendor/native_mate/native_mate_files.gypi',
+    'native_mate/native_mate_files.gypi',
   ],
   'target_defaults': {
     'defines': [
@@ -300,7 +300,7 @@
       'include_dirs': [
         '.',
         'chromium_src',
-        'vendor/native_mate',
+        'native_mate',
         # Include atom_natives.h.
         '<(SHARED_INTERMEDIATE_DIR)',
         # Include directories for uv and node.

+ 27 - 0
native_mate/LICENSE.chromium

@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 56 - 0
native_mate/README.md

@@ -0,0 +1,56 @@
+> A fork of Chromium's [gin library][chromium-gin-lib] that makes it easier to
+> marshal types between C++ and JavaScript.
+
+# Overview
+
+`native-mate` was forked from `gin` so that it could be used in
+[Electron][electron] without conflicting with Node's Environment. It has also
+been extended to allow Electron to create classes in JavaScript.
+
+With the help of Chromium's `base` library, `native-mate` makes writing JS
+bindings very easy, and most of the intricate details of converting V8 types
+to C++ types and back are taken care of auto-magically. In most cases there's
+no need to use the raw V8 API to implement an API binding.
+
+For example, here's an API binding that doesn't use `native-mate`:
+
+```c++
+// static
+void Shell::OpenItem(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  base::FilePath file_path;
+  if (!FromV8Arguments(args, &file_path))
+    return node::ThrowTypeError("Bad argument");
+
+  platform_util::OpenItem(file_path);
+}
+
+// static
+void Shell::Initialize(v8::Handle<v8::Object> target) {
+  NODE_SET_METHOD(target, "openItem", OpenItem);
+}
+```
+
+And here's the same API binding using `native-mate`:
+
+```c++
+void Initialize(v8::Handle<v8::Object> exports) {
+  mate::Dictionary dict(v8::Isolate::GetCurrent(), exports);
+  dict.SetMethod("openItem", &platform_util::OpenItem);
+}
+```
+
+# Code Structure
+
+* `converter.h` - Templatized JS<->C++ conversion routines for many common C++
+  types. You can define your own by specializing `Converter`.
+* `function_template.h` - Create JavaScript functions that dispatch to any C++
+  function, member function pointer, or `base::Callback`.
+* `object_template_builder.h` - A handy utility for creation of `v8::ObjectTemplate`.
+* `wrappable.h` - Base class for C++ classes that want to be owned by the V8 GC.
+  Wrappable objects are automatically deleted when GC discovers that nothing in
+  the V8 heap refers to them. This is also an easy way to expose C++ objects to
+  JavaScript.
+
+
+[chromium-gin-lib]: https://code.google.com/p/chromium/codesearch#chromium/src/gin/README.md&sq=package:chromium
+[electron]: http://electron.atom.io/

+ 72 - 0
native_mate/native_mate/arguments.cc

@@ -0,0 +1,72 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#include "native_mate/arguments.h"
+
+#include "base/strings/stringprintf.h"
+#include "native_mate/converter.h"
+
+namespace mate {
+
+namespace {
+
+std::string V8TypeAsString(v8::Isolate* isolate, v8::Local<v8::Value> value) {
+  if (value.IsEmpty())
+    return "<empty handle>";
+  v8::MaybeLocal<v8::String> details =
+      value->ToDetailString(isolate->GetCurrentContext());
+  std::string result;
+  if (!details.IsEmpty())
+    ConvertFromV8(isolate, details.ToLocalChecked(), &result);
+  return result;
+}
+
+}  // namespace
+
+Arguments::Arguments()
+    : isolate_(NULL),
+      info_(NULL),
+      next_(0),
+      insufficient_arguments_(false) {
+}
+
+Arguments::Arguments(const v8::FunctionCallbackInfo<v8::Value>& info)
+    : isolate_(info.GetIsolate()),
+      info_(&info),
+      next_(0),
+      insufficient_arguments_(false) {
+}
+
+Arguments::~Arguments() {
+}
+
+v8::Local<v8::Value> Arguments::PeekNext() const {
+  if (next_ >= info_->Length())
+    return v8::Local<v8::Value>();
+  return (*info_)[next_];
+}
+
+v8::Local<v8::Value> Arguments::ThrowError() const {
+  if (insufficient_arguments_)
+    return ThrowTypeError("Insufficient number of arguments.");
+
+  return ThrowTypeError(base::StringPrintf(
+      "Error processing argument at index %d, conversion failure from %s",
+      next_, V8TypeAsString(isolate_, (*info_)[next_]).c_str()));
+}
+
+v8::Local<v8::Value> Arguments::ThrowError(const std::string& message) const {
+  isolate_->ThrowException(v8::Exception::Error(
+      StringToV8(isolate_, message)));
+  return v8::Undefined(isolate_);
+}
+
+v8::Local<v8::Value> Arguments::ThrowTypeError(
+    const std::string& message) const {
+  isolate_->ThrowException(v8::Exception::TypeError(
+      StringToV8(isolate_, message)));
+  return v8::Undefined(isolate_);
+}
+
+}  // namespace mate

+ 99 - 0
native_mate/native_mate/arguments.h

@@ -0,0 +1,99 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#ifndef NATIVE_MATE_ARGUMENTS_H_
+#define NATIVE_MATE_ARGUMENTS_H_
+
+#include "base/macros.h"
+#include "native_mate/converter.h"
+
+namespace mate {
+
+// Arguments is a wrapper around v8::FunctionCallbackInfo that integrates
+// with Converter to make it easier to marshall arguments and return values
+// between V8 and C++.
+class Arguments {
+ public:
+  Arguments();
+  explicit Arguments(const v8::FunctionCallbackInfo<v8::Value>& info);
+  ~Arguments();
+
+  v8::Local<v8::Object> GetHolder() const {
+    return info_->Holder();
+  }
+
+  template<typename T>
+  bool GetHolder(T* out) {
+    return ConvertFromV8(isolate_, info_->Holder(), out);
+  }
+
+  template<typename T>
+  bool GetData(T* out) {
+    return ConvertFromV8(isolate_, info_->Data(), out);
+  }
+
+  template<typename T>
+  bool GetNext(T* out) {
+    if (next_ >= info_->Length()) {
+      insufficient_arguments_ = true;
+      return false;
+    }
+    v8::Local<v8::Value> val = (*info_)[next_];
+    bool success = ConvertFromV8(isolate_, val, out);
+    if (success)
+      next_++;
+    return success;
+  }
+
+  template<typename T>
+  bool GetRemaining(std::vector<T>* out) {
+    if (next_ >= info_->Length()) {
+      insufficient_arguments_ = true;
+      return false;
+    }
+    int remaining = info_->Length() - next_;
+    out->resize(remaining);
+    for (int i = 0; i < remaining; ++i) {
+      v8::Local<v8::Value> val = (*info_)[next_++];
+      if (!ConvertFromV8(isolate_, val, &out->at(i)))
+        return false;
+    }
+    return true;
+  }
+
+  v8::Local<v8::Object> GetThis() {
+    return info_->This();
+  }
+
+  bool IsConstructCall() const {
+    return info_->IsConstructCall();
+  }
+
+  int Length() const {
+    return info_->Length();
+  }
+
+  template<typename T>
+  void Return(T val) {
+    info_->GetReturnValue().Set(ConvertToV8(isolate_, val));
+  }
+
+  v8::Local<v8::Value> PeekNext() const;
+
+  v8::Local<v8::Value> ThrowError() const;
+  v8::Local<v8::Value> ThrowError(const std::string& message) const;
+  v8::Local<v8::Value> ThrowTypeError(const std::string& message) const;
+
+  v8::Isolate* isolate() const { return isolate_; }
+
+ private:
+  v8::Isolate* isolate_;
+  const v8::FunctionCallbackInfo<v8::Value>* info_;
+  int next_;
+  bool insufficient_arguments_;
+};
+
+}  // namespace mate
+
+#endif  // NATIVE_MATE_ARGUMENTS_H_

+ 148 - 0
native_mate/native_mate/constructor.h

@@ -0,0 +1,148 @@
+// This file was GENERATED by command:
+//     pump.py constructor.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#ifndef NATIVE_MATE_WRAPPABLE_CLASS_H_
+#define NATIVE_MATE_WRAPPABLE_CLASS_H_
+
+#include "base/bind.h"
+#include "native_mate/function_template.h"
+
+namespace mate {
+
+namespace internal {
+
+// This set of templates invokes a base::Callback by converting the Arguments
+// into native types. It relies on the function_template.h to provide helper
+// templates.
+inline WrappableBase* InvokeFactory(
+    Arguments* args,
+    const base::Callback<WrappableBase*()>& callback) {
+  return callback.Run();
+};
+
+template<typename P1>
+inline WrappableBase* InvokeFactory(
+    Arguments* args,
+    const base::Callback<WrappableBase*(P1)>& callback) {
+  typename CallbackParamTraits<P1>::LocalType a1;
+  if (!GetNextArgument(args, 0, true, &a1))
+    return nullptr;
+  return callback.Run(a1);
+};
+
+template<typename P1, typename P2>
+inline WrappableBase* InvokeFactory(
+    Arguments* args,
+    const base::Callback<WrappableBase*(P1, P2)>& callback) {
+  typename CallbackParamTraits<P1>::LocalType a1;
+  typename CallbackParamTraits<P2>::LocalType a2;
+  if (!GetNextArgument(args, 0, true, &a1) ||
+      !GetNextArgument(args, 0, false, &a2))
+    return nullptr;
+  return callback.Run(a1, a2);
+};
+
+template<typename P1, typename P2, typename P3>
+inline WrappableBase* InvokeFactory(
+    Arguments* args,
+    const base::Callback<WrappableBase*(P1, P2, P3)>& callback) {
+  typename CallbackParamTraits<P1>::LocalType a1;
+  typename CallbackParamTraits<P2>::LocalType a2;
+  typename CallbackParamTraits<P3>::LocalType a3;
+  if (!GetNextArgument(args, 0, true, &a1) ||
+      !GetNextArgument(args, 0, false, &a2) ||
+      !GetNextArgument(args, 0, false, &a3))
+    return nullptr;
+  return callback.Run(a1, a2, a3);
+};
+
+template<typename P1, typename P2, typename P3, typename P4>
+inline WrappableBase* InvokeFactory(
+    Arguments* args,
+    const base::Callback<WrappableBase*(P1, P2, P3, P4)>& callback) {
+  typename CallbackParamTraits<P1>::LocalType a1;
+  typename CallbackParamTraits<P2>::LocalType a2;
+  typename CallbackParamTraits<P3>::LocalType a3;
+  typename CallbackParamTraits<P4>::LocalType a4;
+  if (!GetNextArgument(args, 0, true, &a1) ||
+      !GetNextArgument(args, 0, false, &a2) ||
+      !GetNextArgument(args, 0, false, &a3) ||
+      !GetNextArgument(args, 0, false, &a4))
+    return nullptr;
+  return callback.Run(a1, a2, a3, a4);
+};
+
+template<typename P1, typename P2, typename P3, typename P4, typename P5>
+inline WrappableBase* InvokeFactory(
+    Arguments* args,
+    const base::Callback<WrappableBase*(P1, P2, P3, P4, P5)>& callback) {
+  typename CallbackParamTraits<P1>::LocalType a1;
+  typename CallbackParamTraits<P2>::LocalType a2;
+  typename CallbackParamTraits<P3>::LocalType a3;
+  typename CallbackParamTraits<P4>::LocalType a4;
+  typename CallbackParamTraits<P5>::LocalType a5;
+  if (!GetNextArgument(args, 0, true, &a1) ||
+      !GetNextArgument(args, 0, false, &a2) ||
+      !GetNextArgument(args, 0, false, &a3) ||
+      !GetNextArgument(args, 0, false, &a4) ||
+      !GetNextArgument(args, 0, false, &a5))
+    return nullptr;
+  return callback.Run(a1, a2, a3, a4, a5);
+};
+
+template<typename P1, typename P2, typename P3, typename P4, typename P5,
+    typename P6>
+inline WrappableBase* InvokeFactory(
+    Arguments* args,
+    const base::Callback<WrappableBase*(P1, P2, P3, P4, P5, P6)>& callback) {
+  typename CallbackParamTraits<P1>::LocalType a1;
+  typename CallbackParamTraits<P2>::LocalType a2;
+  typename CallbackParamTraits<P3>::LocalType a3;
+  typename CallbackParamTraits<P4>::LocalType a4;
+  typename CallbackParamTraits<P5>::LocalType a5;
+  typename CallbackParamTraits<P6>::LocalType a6;
+  if (!GetNextArgument(args, 0, true, &a1) ||
+      !GetNextArgument(args, 0, false, &a2) ||
+      !GetNextArgument(args, 0, false, &a3) ||
+      !GetNextArgument(args, 0, false, &a4) ||
+      !GetNextArgument(args, 0, false, &a5) ||
+      !GetNextArgument(args, 0, false, &a6))
+    return nullptr;
+  return callback.Run(a1, a2, a3, a4, a5, a6);
+};
+
+template<typename Sig>
+void InvokeNew(const base::Callback<Sig>& factory,
+               v8::Isolate* isolate, Arguments* args) {
+  if (!args->IsConstructCall()) {
+    args->ThrowError("Requires constructor call");
+    return;
+  }
+
+  WrappableBase* object;
+  {
+    // Don't continue if the constructor throws an exception.
+    v8::TryCatch try_catch(isolate);
+    object = internal::InvokeFactory(args, factory);
+    if (try_catch.HasCaught()) {
+      try_catch.ReThrow();
+      return;
+    }
+  }
+
+  if (!object)
+    args->ThrowError();
+
+  return;
+}
+
+}  // namespace internal
+
+}  // namespace mate
+
+#endif  // NATIVE_MATE_WRAPPABLE_CLASS_H_

+ 247 - 0
native_mate/native_mate/converter.cc

@@ -0,0 +1,247 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#include "native_mate/converter.h"
+
+#include "v8/include/v8.h"
+
+using v8::Array;
+using v8::Boolean;
+using v8::External;
+using v8::Function;
+using v8::Integer;
+using v8::Isolate;
+using v8::Local;
+using v8::Number;
+using v8::Object;
+using v8::String;
+using v8::Value;
+
+namespace mate {
+
+Local<Value> Converter<bool>::ToV8(Isolate* isolate, bool val) {
+  return v8::Boolean::New(isolate, val);
+}
+
+bool Converter<bool>::FromV8(Isolate* isolate, Local<Value> val, bool* out) {
+  if (!val->IsBoolean())
+    return false;
+  *out = val->BooleanValue();
+  return true;
+}
+
+#if !defined(OS_LINUX) && !defined(OS_FREEBSD)
+Local<Value> Converter<unsigned long>::ToV8(Isolate* isolate,
+                                             unsigned long val) {
+  return v8::Integer::New(isolate, val);
+}
+
+bool Converter<unsigned long>::FromV8(Isolate* isolate, Local<Value> val,
+                                      unsigned long* out) {
+  if (!val->IsNumber())
+    return false;
+  *out = val->IntegerValue();
+  return true;
+}
+#endif
+
+Local<Value> Converter<int32_t>::ToV8(Isolate* isolate, int32_t val) {
+  return v8::Integer::New(isolate, val);
+}
+
+bool Converter<int32_t>::FromV8(Isolate* isolate, Local<Value> val,
+                                int32_t* out) {
+  if (!val->IsInt32())
+    return false;
+  *out = val->Int32Value();
+  return true;
+}
+
+Local<Value> Converter<uint32_t>::ToV8(Isolate* isolate, uint32_t val) {
+  return v8::Integer::NewFromUnsigned(isolate, val);
+}
+
+bool Converter<uint32_t>::FromV8(Isolate* isolate, Local<Value> val,
+                                 uint32_t* out) {
+  if (!val->IsUint32())
+    return false;
+  *out = val->Uint32Value();
+  return true;
+}
+
+Local<Value> Converter<int64_t>::ToV8(Isolate* isolate, int64_t val) {
+  return v8::Number::New(isolate, static_cast<double>(val));
+}
+
+bool Converter<int64_t>::FromV8(Isolate* isolate, Local<Value> val,
+                                int64_t* out) {
+  if (!val->IsNumber())
+    return false;
+  // Even though IntegerValue returns int64_t, JavaScript cannot represent
+  // the full precision of int64_t, which means some rounding might occur.
+  *out = val->IntegerValue();
+  return true;
+}
+
+Local<Value> Converter<uint64_t>::ToV8(Isolate* isolate, uint64_t val) {
+  return v8::Number::New(isolate, static_cast<double>(val));
+}
+
+bool Converter<uint64_t>::FromV8(Isolate* isolate, Local<Value> val,
+                                 uint64_t* out) {
+  if (!val->IsNumber())
+    return false;
+  *out = static_cast<uint64_t>(val->IntegerValue());
+  return true;
+}
+
+Local<Value> Converter<float>::ToV8(Isolate* isolate, float val) {
+  return v8::Number::New(isolate, val);
+}
+
+bool Converter<float>::FromV8(Isolate* isolate, Local<Value> val,
+                              float* out) {
+  if (!val->IsNumber())
+    return false;
+  *out = static_cast<float>(val->NumberValue());
+  return true;
+}
+
+Local<Value> Converter<double>::ToV8(Isolate* isolate, double val) {
+  return v8::Number::New(isolate, val);
+}
+
+bool Converter<double>::FromV8(Isolate* isolate, Local<Value> val,
+                               double* out) {
+  if (!val->IsNumber())
+    return false;
+  *out = val->NumberValue();
+  return true;
+}
+
+Local<Value> Converter<const char*>::ToV8(
+    Isolate* isolate, const char* val) {
+  return v8::String::NewFromUtf8(isolate, val);
+}
+
+Local<Value> Converter<base::StringPiece>::ToV8(
+    Isolate* isolate, const base::StringPiece& val) {
+  return v8::String::NewFromUtf8(isolate,
+                                 val.data(),
+                                 v8::String::kNormalString,
+                                 static_cast<uint32_t>(val.length()));
+}
+
+Local<Value> Converter<std::string>::ToV8(Isolate* isolate,
+                                           const std::string& val) {
+  return Converter<base::StringPiece>::ToV8(isolate, val);
+}
+
+bool Converter<std::string>::FromV8(Isolate* isolate, Local<Value> val,
+                                    std::string* out) {
+  if (!val->IsString())
+    return false;
+  Local<String> str = Local<String>::Cast(val);
+  int length = str->Utf8Length();
+  out->resize(length);
+  str->WriteUtf8(&(*out)[0], length, NULL, String::NO_NULL_TERMINATION);
+  return true;
+}
+
+Local<Value> Converter<Local<Function>>::ToV8(Isolate* isolate,
+                                              Local<Function> val) {
+  return val;
+}
+
+bool Converter<Local<Function> >::FromV8(Isolate* isolate, Local<Value> val,
+                                         Local<Function>* out) {
+  if (!val->IsFunction())
+    return false;
+  *out = Local<Function>::Cast(val);
+  return true;
+}
+
+Local<Value> Converter<Local<Object> >::ToV8(Isolate* isolate,
+                                             Local<Object> val) {
+  return val;
+}
+
+bool Converter<Local<Object> >::FromV8(Isolate* isolate, Local<Value> val,
+                                       Local<Object>* out) {
+  if (!val->IsObject())
+    return false;
+  *out = Local<Object>::Cast(val);
+  return true;
+}
+
+Local<Value> Converter<Local<String> >::ToV8(Isolate* isolate,
+                                             Local<String> val) {
+  return val;
+}
+
+bool Converter<Local<String> >::FromV8(Isolate* isolate, Local<Value> val,
+                                       Local<String>* out) {
+  if (!val->IsString())
+    return false;
+  *out = Local<String>::Cast(val);
+  return true;
+}
+
+Local<Value> Converter<Local<External> >::ToV8(Isolate* isolate,
+                                               Local<External> val) {
+  return val;
+}
+
+bool Converter<Local<External> >::FromV8(Isolate* isolate,
+                                          v8::Local<Value> val,
+                                          Local<External>* out) {
+  if (!val->IsExternal())
+    return false;
+  *out = Local<External>::Cast(val);
+  return true;
+}
+
+Local<Value> Converter<Local<Array> >::ToV8(Isolate* isolate,
+                                            Local<Array> val) {
+  return val;
+}
+
+bool Converter<Local<Array> >::FromV8(Isolate* isolate,
+                                      v8::Local<Value> val,
+                                      Local<Array>* out) {
+  if (!val->IsArray())
+    return false;
+  *out = Local<Array>::Cast(val);
+  return true;
+}
+
+Local<Value> Converter<Local<Value> >::ToV8(Isolate* isolate,
+                                            Local<Value> val) {
+  return val;
+}
+
+bool Converter<Local<Value> >::FromV8(Isolate* isolate, Local<Value> val,
+                                      Local<Value>* out) {
+  *out = val;
+  return true;
+}
+
+v8::Local<v8::String> StringToSymbol(v8::Isolate* isolate,
+                                      const base::StringPiece& val) {
+  return v8::String::NewFromUtf8(isolate,
+                                 val.data(),
+                                 v8::String::kInternalizedString,
+                                 static_cast<uint32_t>(val.length()));
+}
+
+std::string V8ToString(v8::Local<v8::Value> value) {
+  if (value.IsEmpty())
+    return std::string();
+  std::string result;
+  if (!ConvertFromV8(NULL, value, &result))
+    return std::string();
+  return result;
+}
+
+}  // namespace mate

+ 364 - 0
native_mate/native_mate/converter.h

@@ -0,0 +1,364 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#ifndef NATIVE_MATE_CONVERTER_H_
+#define NATIVE_MATE_CONVERTER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+#include <set>
+
+#include "base/strings/string_piece.h"
+#include "v8/include/v8.h"
+
+namespace mate {
+
+template<typename KeyType>
+bool SetProperty(v8::Isolate* isolate,
+                 v8::Local<v8::Object> object,
+                 KeyType key,
+                 v8::Local<v8::Value> value) {
+  auto maybe = object->Set(isolate->GetCurrentContext(), key, value);
+  return !maybe.IsNothing() && maybe.FromJust();
+}
+
+template<typename T>
+struct ToV8ReturnsMaybe {
+  static const bool value = false;
+};
+
+template<typename T, typename Enable = void>
+struct Converter {};
+
+template<>
+struct Converter<void*> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, void* val) {
+    return v8::Undefined(isolate);
+  }
+};
+
+template<>
+struct Converter<std::nullptr_t> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, std::nullptr_t val) {
+    return v8::Null(isolate);
+  }
+};
+
+template<>
+struct Converter<bool> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    bool val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     bool* out);
+};
+
+#if !defined(OS_LINUX) && !defined(OS_FREEBSD)
+template<>
+struct Converter<unsigned long> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    unsigned long val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     unsigned long* out);
+};
+#endif
+
+template<>
+struct Converter<int32_t> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    int32_t val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     int32_t* out);
+};
+
+template<>
+struct Converter<uint32_t> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    uint32_t val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     uint32_t* out);
+};
+
+template<>
+struct Converter<int64_t> {
+  // Warning: JavaScript cannot represent 64 integers precisely.
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    int64_t val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     int64_t* out);
+};
+
+template<>
+struct Converter<uint64_t> {
+  // Warning: JavaScript cannot represent 64 integers precisely.
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    uint64_t val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     uint64_t* out);
+};
+
+template<>
+struct Converter<float> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    float val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     float* out);
+};
+
+template<>
+struct Converter<double> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    double val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     double* out);
+};
+
+template<>
+struct Converter<const char*> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, const char* val);
+};
+
+template<>
+struct Converter<base::StringPiece> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    const base::StringPiece& val);
+  // No conversion out is possible because StringPiece does not contain storage.
+};
+
+template<>
+struct Converter<std::string> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    const std::string& val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     std::string* out);
+};
+
+v8::Local<v8::String> StringToSymbol(v8::Isolate* isolate,
+                                      const base::StringPiece& input);
+
+std::string V8ToString(v8::Local<v8::Value> value);
+
+template<>
+struct Converter<v8::Local<v8::Function> > {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    v8::Local<v8::Function> val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     v8::Local<v8::Function>* out);
+};
+
+template<>
+struct Converter<v8::Local<v8::Object> > {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    v8::Local<v8::Object> val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     v8::Local<v8::Object>* out);
+};
+
+template<>
+struct Converter<v8::Local<v8::String> > {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    v8::Local<v8::String> val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     v8::Local<v8::String>* out);
+};
+
+template<>
+struct Converter<v8::Local<v8::External> > {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    v8::Local<v8::External> val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     v8::Local<v8::External>* out);
+};
+
+template<>
+struct Converter<v8::Local<v8::Array> > {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    v8::Local<v8::Array> val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     v8::Local<v8::Array>* out);
+};
+
+template<>
+struct Converter<v8::Local<v8::Value> > {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    v8::Local<v8::Value> val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     v8::Local<v8::Value>* out);
+};
+
+template<typename T>
+struct Converter<std::vector<T> > {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    const std::vector<T>& val) {
+    v8::Local<v8::Array> result(
+        v8::Array::New(isolate, static_cast<int>(val.size())));
+    for (size_t i = 0; i < val.size(); ++i) {
+      result->Set(static_cast<int>(i), Converter<T>::ToV8(isolate, val[i]));
+    }
+    return result;
+  }
+
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     std::vector<T>* out) {
+    if (!val->IsArray())
+      return false;
+
+    std::vector<T> result;
+    v8::Local<v8::Array> array(v8::Local<v8::Array>::Cast(val));
+    uint32_t length = array->Length();
+    for (uint32_t i = 0; i < length; ++i) {
+      T item;
+      if (!Converter<T>::FromV8(isolate, array->Get(i), &item))
+        return false;
+      result.push_back(item);
+    }
+
+    out->swap(result);
+    return true;
+  }
+};
+
+template<typename T>
+struct Converter<std::set<T> > {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    const std::set<T>& val) {
+    v8::Local<v8::Array> result(
+        v8::Array::New(isolate, static_cast<int>(val.size())));
+    typename std::set<T>::const_iterator it;
+    int i;
+    for (i = 0, it = val.begin(); it != val.end(); ++it, ++i)
+      result->Set(i, Converter<T>::ToV8(isolate, *it));
+    return result;
+  }
+
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     std::set<T>* out) {
+    if (!val->IsArray())
+      return false;
+
+    std::set<T> result;
+    v8::Local<v8::Array> array(v8::Local<v8::Array>::Cast(val));
+    uint32_t length = array->Length();
+    for (uint32_t i = 0; i < length; ++i) {
+      T item;
+      if (!Converter<T>::FromV8(isolate, array->Get(i), &item))
+        return false;
+      result.insert(item);
+    }
+
+    out->swap(result);
+    return true;
+  }
+};
+
+template<typename T>
+struct Converter<std::map<std::string, T> > {
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     std::map<std::string, T> * out) {
+    if (!val->IsObject())
+      return false;
+
+    v8::Local<v8::Object> dict = val->ToObject();
+    v8::Local<v8::Array> keys = dict->GetOwnPropertyNames();
+    for (uint32_t i = 0; i < keys->Length(); ++i) {
+      v8::Local<v8::Value> key = keys->Get(i);
+      T value;
+      if (Converter<T>::FromV8(isolate, dict->Get(key), &value))
+        (*out)[V8ToString(key)] = std::move(value);
+    }
+    return true;
+  }
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                   const std::map<std::string, T>& val) {
+    v8::Local<v8::Object> result = v8::Object::New(isolate);
+    for (auto i = val.begin(); i != val.end(); i++) {
+      result->Set(Converter<T>::ToV8(isolate, i->first),
+                 Converter<T>::ToV8(isolate, i->second));
+    }
+    return result;
+  }
+};
+
+// Convenience functions that deduce T.
+template<typename T>
+v8::Local<v8::Value> ConvertToV8(v8::Isolate* isolate, const T& input) {
+  return Converter<T>::ToV8(isolate, input);
+}
+
+inline v8::Local<v8::Value> ConvertToV8(v8::Isolate* isolate,
+                                        const char* input) {
+  return Converter<const char*>::ToV8(isolate, input);
+}
+
+template<typename T>
+v8::MaybeLocal<v8::Value> ConvertToV8(v8::Local<v8::Context> context,
+                                      const T& input) {
+  return Converter<T>::ToV8(context, input);
+}
+
+template<typename T, bool = ToV8ReturnsMaybe<T>::value> struct ToV8Traits;
+
+template <typename T>
+struct ToV8Traits<T, true> {
+  static bool TryConvertToV8(v8::Isolate* isolate,
+                             const T& input,
+                             v8::Local<v8::Value>* output) {
+    auto maybe = ConvertToV8(isolate->GetCurrentContext(), input);
+    if (maybe.IsEmpty())
+      return false;
+    *output = maybe.ToLocalChecked();
+    return true;
+  }
+};
+
+template <typename T>
+struct ToV8Traits<T, false> {
+  static bool TryConvertToV8(v8::Isolate* isolate,
+                             const T& input,
+                             v8::Local<v8::Value>* output) {
+    *output = ConvertToV8(isolate, input);
+    return true;
+  }
+};
+
+template <typename T>
+bool TryConvertToV8(v8::Isolate* isolate,
+                    const T& input,
+                    v8::Local<v8::Value>* output) {
+  return ToV8Traits<T>::TryConvertToV8(isolate, input, output);
+}
+
+template<typename T>
+bool ConvertFromV8(v8::Isolate* isolate, v8::Local<v8::Value> input,
+                   T* result) {
+  return Converter<T>::FromV8(isolate, input, result);
+}
+
+inline v8::Local<v8::String> StringToV8(
+    v8::Isolate* isolate,
+    const base::StringPiece& input) {
+  return ConvertToV8(isolate, input).As<v8::String>();
+}
+
+}  // namespace mate
+
+#endif  // NATIVE_MATE_CONVERTER_H_

+ 44 - 0
native_mate/native_mate/dictionary.cc

@@ -0,0 +1,44 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#include "native_mate/dictionary.h"
+
+namespace mate {
+
+Dictionary::Dictionary()
+    : isolate_(NULL) {
+}
+
+Dictionary::Dictionary(v8::Isolate* isolate,
+                       v8::Local<v8::Object> object)
+    : isolate_(isolate),
+      object_(object) {
+}
+
+Dictionary::~Dictionary() {
+}
+
+Dictionary Dictionary::CreateEmpty(v8::Isolate* isolate) {
+  return Dictionary(isolate, v8::Object::New(isolate));
+}
+
+v8::Local<v8::Object> Dictionary::GetHandle() const {
+  return object_;
+}
+
+v8::Local<v8::Value> Converter<Dictionary>::ToV8(v8::Isolate* isolate,
+                                                  Dictionary val) {
+  return val.GetHandle();
+}
+
+bool Converter<Dictionary>::FromV8(v8::Isolate* isolate,
+                                   v8::Local<v8::Value> val,
+                                   Dictionary* out) {
+  if (!val->IsObject() || val->IsFunction())
+    return false;
+  *out = Dictionary(isolate, v8::Local<v8::Object>::Cast(val));
+  return true;
+}
+
+}  // namespace mate

+ 146 - 0
native_mate/native_mate/dictionary.h

@@ -0,0 +1,146 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#ifndef NATIVE_MATE_DICTIONARY_H_
+#define NATIVE_MATE_DICTIONARY_H_
+
+#include "native_mate/converter.h"
+#include "native_mate/object_template_builder.h"
+
+namespace mate {
+
+namespace internal {
+
+// Returns true if |maybe| is both a value, and that value is true.
+inline bool IsTrue(v8::Maybe<bool> maybe) {
+  return maybe.IsJust() && maybe.FromJust();
+}
+
+}  // namespace internal
+
+// Dictionary is useful when writing bindings for a function that either
+// receives an arbitrary JavaScript object as an argument or returns an
+// arbitrary JavaScript object as a result. For example, Dictionary is useful
+// when you might use the |dictionary| type in WebIDL:
+//
+//   http://heycam.github.io/webidl/#idl-dictionaries
+//
+// WARNING: You cannot retain a Dictionary object in the heap. The underlying
+//          storage for Dictionary is tied to the closest enclosing
+//          v8::HandleScope. Generally speaking, you should store a Dictionary
+//          on the stack.
+//
+class Dictionary {
+ public:
+  Dictionary();
+  Dictionary(v8::Isolate* isolate, v8::Local<v8::Object> object);
+  virtual ~Dictionary();
+
+  static Dictionary CreateEmpty(v8::Isolate* isolate);
+
+  template<typename T>
+  bool Get(const base::StringPiece& key, T* out) const {
+    // Check for existence before getting, otherwise this method will always
+    // returns true when T == v8::Local<v8::Value>.
+    v8::Local<v8::Context> context = isolate_->GetCurrentContext();
+    v8::Local<v8::String> v8_key = StringToV8(isolate_, key);
+    if (!internal::IsTrue(GetHandle()->Has(context, v8_key)))
+      return false;
+
+    v8::Local<v8::Value> val;
+    if (!GetHandle()->Get(context, v8_key).ToLocal(&val))
+      return false;
+    return ConvertFromV8(isolate_, val, out);
+  }
+
+  template<typename T>
+  bool GetHidden(const base::StringPiece& key, T* out) const {
+    v8::Local<v8::Context> context = isolate_->GetCurrentContext();
+    v8::Local<v8::Private> privateKey =
+        v8::Private::ForApi(isolate_, StringToV8(isolate_, key));
+    v8::Local<v8::Value> value;
+    v8::Maybe<bool> result =
+        GetHandle()->HasPrivate(context, privateKey);
+    if (internal::IsTrue(result) &&
+        GetHandle()->GetPrivate(context, privateKey).ToLocal(&value))
+      return ConvertFromV8(isolate_, value, out);
+    return false;
+  }
+
+  template<typename T>
+  bool Set(const base::StringPiece& key, const T& val) {
+    v8::Local<v8::Value> v8_value;
+    if (!TryConvertToV8(isolate_, val, &v8_value))
+      return false;
+    v8::Maybe<bool> result =
+        GetHandle()->Set(isolate_->GetCurrentContext(),
+                         StringToV8(isolate_, key),
+                         v8_value);
+    return !result.IsNothing() && result.FromJust();
+  }
+
+  template<typename T>
+  bool SetHidden(const base::StringPiece& key, T val) {
+    v8::Local<v8::Value> v8_value;
+    if (!TryConvertToV8(isolate_, val, &v8_value))
+      return false;
+    v8::Local<v8::Context> context = isolate_->GetCurrentContext();
+    v8::Local<v8::Private> privateKey =
+        v8::Private::ForApi(isolate_, StringToV8(isolate_, key));
+    v8::Maybe<bool> result =
+        GetHandle()->SetPrivate(context, privateKey, v8_value);
+    return !result.IsNothing() && result.FromJust();
+  }
+
+  template<typename T>
+  bool SetReadOnly(const base::StringPiece& key, T val) {
+    v8::Local<v8::Value> v8_value;
+    if (!TryConvertToV8(isolate_, val, &v8_value))
+      return false;
+    v8::Maybe<bool> result =
+        GetHandle()->DefineOwnProperty(isolate_->GetCurrentContext(),
+                                       StringToV8(isolate_, key),
+                                       v8_value,
+                                       v8::ReadOnly);
+    return !result.IsNothing() && result.FromJust();
+  }
+
+  template<typename T>
+  bool SetMethod(const base::StringPiece& key, const T& callback) {
+    return GetHandle()->Set(
+        StringToV8(isolate_, key),
+        CallbackTraits<T>::CreateTemplate(isolate_, callback)->GetFunction());
+  }
+
+  bool Delete(const base::StringPiece& key) {
+    v8::Maybe<bool> result = GetHandle()->Delete(isolate_->GetCurrentContext(),
+                                                 StringToV8(isolate_, key));
+    return !result.IsNothing() && result.FromJust();
+  }
+
+  bool IsEmpty() const { return isolate() == NULL; }
+
+  virtual v8::Local<v8::Object> GetHandle() const;
+
+  v8::Isolate* isolate() const { return isolate_; }
+
+ protected:
+  v8::Isolate* isolate_;
+
+ private:
+  v8::Local<v8::Object> object_;
+};
+
+template<>
+struct Converter<Dictionary> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    Dictionary val);
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     Dictionary* out);
+};
+
+}  // namespace mate
+
+#endif  // NATIVE_MATE_DICTIONARY_H_

+ 40 - 0
native_mate/native_mate/function_template.cc

@@ -0,0 +1,40 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#include "native_mate/function_template.h"
+
+namespace mate {
+
+namespace internal {
+
+CallbackHolderBase::CallbackHolderBase(v8::Isolate* isolate)
+    : v8_ref_(isolate, v8::External::New(isolate, this)) {
+  v8_ref_.SetWeak(this, &CallbackHolderBase::FirstWeakCallback,
+                  v8::WeakCallbackType::kParameter);
+}
+
+CallbackHolderBase::~CallbackHolderBase() {
+  DCHECK(v8_ref_.IsEmpty());
+}
+
+v8::Local<v8::External> CallbackHolderBase::GetHandle(v8::Isolate* isolate) {
+  return v8::Local<v8::External>::New(isolate, v8_ref_);
+}
+
+// static
+void CallbackHolderBase::FirstWeakCallback(
+    const v8::WeakCallbackInfo<CallbackHolderBase>& data) {
+  data.GetParameter()->v8_ref_.Reset();
+  data.SetSecondPassCallback(SecondWeakCallback);
+}
+
+// static
+void CallbackHolderBase::SecondWeakCallback(
+    const v8::WeakCallbackInfo<CallbackHolderBase>& data) {
+  delete data.GetParameter();
+}
+
+}  // namespace internal
+
+}  // namespace mate

+ 285 - 0
native_mate/native_mate/function_template.h

@@ -0,0 +1,285 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#ifndef NATIVE_MATE_FUNCTION_TEMPLATE_H_
+#define NATIVE_MATE_FUNCTION_TEMPLATE_H_
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "native_mate/arguments.h"
+#include "native_mate/wrappable_base.h"
+#include "v8/include/v8.h"
+
+namespace mate {
+
+enum CreateFunctionTemplateFlags {
+  HolderIsFirstArgument = 1 << 0,
+};
+
+namespace internal {
+
+struct Destroyable {
+  static void Destroy(Arguments* args) {
+    if (IsDestroyed(args))
+      return;
+
+    v8::Local<v8::Object> holder = args->GetHolder();
+    delete static_cast<WrappableBase*>(
+        holder->GetAlignedPointerFromInternalField(0));
+    holder->SetAlignedPointerInInternalField(0, nullptr);
+  }
+  static bool IsDestroyed(Arguments* args) {
+    v8::Local<v8::Object> holder = args->GetHolder();
+    return holder->InternalFieldCount() == 0 ||
+           holder->GetAlignedPointerFromInternalField(0) == nullptr;
+  }
+};
+
+template<typename T>
+struct CallbackParamTraits {
+  typedef T LocalType;
+};
+template<typename T>
+struct CallbackParamTraits<const T&> {
+  typedef T LocalType;
+};
+template<typename T>
+struct CallbackParamTraits<const T*> {
+  typedef T* LocalType;
+};
+
+
+// CallbackHolder and CallbackHolderBase are used to pass a base::Callback from
+// CreateFunctionTemplate through v8 (via v8::FunctionTemplate) to
+// DispatchToCallback, where it is invoked.
+
+// This simple base class is used so that we can share a single object template
+// among every CallbackHolder instance.
+class CallbackHolderBase {
+ public:
+  v8::Local<v8::External> GetHandle(v8::Isolate* isolate);
+
+ protected:
+  explicit CallbackHolderBase(v8::Isolate* isolate);
+  virtual ~CallbackHolderBase();
+
+ private:
+  static void FirstWeakCallback(
+      const v8::WeakCallbackInfo<CallbackHolderBase>& data);
+  static void SecondWeakCallback(
+      const v8::WeakCallbackInfo<CallbackHolderBase>& data);
+
+  v8::Global<v8::External> v8_ref_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallbackHolderBase);
+};
+
+template<typename Sig>
+class CallbackHolder : public CallbackHolderBase {
+ public:
+  CallbackHolder(v8::Isolate* isolate,
+                 const base::Callback<Sig>& callback,
+                 int flags)
+      : CallbackHolderBase(isolate), callback(callback), flags(flags) {}
+  base::Callback<Sig> callback;
+  int flags;
+ private:
+  virtual ~CallbackHolder() {}
+
+  DISALLOW_COPY_AND_ASSIGN(CallbackHolder);
+};
+
+template<typename T>
+bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
+                     T* result) {
+  if (is_first && (create_flags & HolderIsFirstArgument) != 0) {
+    return args->GetHolder(result);
+  } else {
+    return args->GetNext(result);
+  }
+}
+
+// For advanced use cases, we allow callers to request the unparsed Arguments
+// object and poke around in it directly.
+inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
+                            Arguments* result) {
+  *result = *args;
+  return true;
+}
+inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
+                            Arguments** result) {
+  *result = args;
+  return true;
+}
+
+// It's common for clients to just need the isolate, so we make that easy.
+inline bool GetNextArgument(Arguments* args, int create_flags,
+                            bool is_first, v8::Isolate** result) {
+  *result = args->isolate();
+  return true;
+}
+
+// Classes for generating and storing an argument pack of integer indices
+// (based on well-known "indices trick", see: http://goo.gl/bKKojn):
+template <size_t... indices>
+struct IndicesHolder {};
+
+template <size_t requested_index, size_t... indices>
+struct IndicesGenerator {
+  using type = typename IndicesGenerator<requested_index - 1,
+                                         requested_index - 1,
+                                         indices...>::type;
+};
+template <size_t... indices>
+struct IndicesGenerator<0, indices...> {
+  using type = IndicesHolder<indices...>;
+};
+
+// Class template for extracting and storing single argument for callback
+// at position |index|.
+template <size_t index, typename ArgType>
+struct ArgumentHolder {
+  using ArgLocalType = typename CallbackParamTraits<ArgType>::LocalType;
+
+  ArgLocalType value;
+  bool ok;
+
+  ArgumentHolder(Arguments* args, int create_flags)
+      : ok(false) {
+    if (index == 0 &&
+        (create_flags & HolderIsFirstArgument) &&
+        Destroyable::IsDestroyed(args)) {
+      args->ThrowError("Object has been destroyed");
+      return;
+    }
+    ok = GetNextArgument(args, create_flags, index == 0, &value);
+    if (!ok) {
+      // Ideally we would include the expected c++ type in the error
+      // message which we can access via typeid(ArgType).name()
+      // however we compile with no-rtti, which disables typeid.
+      args->ThrowError();
+    }
+  }
+};
+
+// Class template for converting arguments from JavaScript to C++ and running
+// the callback with them.
+template <typename IndicesType, typename... ArgTypes>
+class Invoker {};
+
+template <size_t... indices, typename... ArgTypes>
+class Invoker<IndicesHolder<indices...>, ArgTypes...>
+    : public ArgumentHolder<indices, ArgTypes>... {
+ public:
+  // Invoker<> inherits from ArgumentHolder<> for each argument.
+  // C++ has always been strict about the class initialization order,
+  // so it is guaranteed ArgumentHolders will be initialized (and thus, will
+  // extract arguments from Arguments) in the right order.
+  Invoker(Arguments* args, int create_flags)
+      : ArgumentHolder<indices, ArgTypes>(args, create_flags)..., args_(args) {
+    // GCC thinks that create_flags is going unused, even though the
+    // expansion above clearly makes use of it. Per jyasskin@, casting
+    // to void is the commonly accepted way to convince the compiler
+    // that you're actually using a parameter/varible.
+    (void)create_flags;
+  }
+
+  bool IsOK() {
+    return And(ArgumentHolder<indices, ArgTypes>::ok...);
+  }
+
+  template <typename ReturnType>
+  void DispatchToCallback(base::Callback<ReturnType(ArgTypes...)> callback) {
+    v8::MicrotasksScope script_scope(
+        args_->isolate(), v8::MicrotasksScope::kRunMicrotasks);
+    args_->Return(callback.Run(ArgumentHolder<indices, ArgTypes>::value...));
+  }
+
+  // In C++, you can declare the function foo(void), but you can't pass a void
+  // expression to foo. As a result, we must specialize the case of Callbacks
+  // that have the void return type.
+  void DispatchToCallback(base::Callback<void(ArgTypes...)> callback) {
+    v8::MicrotasksScope script_scope(
+        args_->isolate(), v8::MicrotasksScope::kRunMicrotasks);
+    callback.Run(ArgumentHolder<indices, ArgTypes>::value...);
+  }
+
+ private:
+  static bool And() { return true; }
+  template <typename... T>
+  static bool And(bool arg1, T... args) {
+    return arg1 && And(args...);
+  }
+
+  Arguments* args_;
+};
+
+// DispatchToCallback converts all the JavaScript arguments to C++ types and
+// invokes the base::Callback.
+template <typename Sig>
+struct Dispatcher {};
+
+template <typename ReturnType, typename... ArgTypes>
+struct Dispatcher<ReturnType(ArgTypes...)> {
+  static void DispatchToCallback(
+      const v8::FunctionCallbackInfo<v8::Value>& info) {
+    Arguments args(info);
+    v8::Local<v8::External> v8_holder;
+    args.GetData(&v8_holder);
+    CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
+        v8_holder->Value());
+
+    typedef CallbackHolder<ReturnType(ArgTypes...)> HolderT;
+    HolderT* holder = static_cast<HolderT*>(holder_base);
+
+    using Indices = typename IndicesGenerator<sizeof...(ArgTypes)>::type;
+    Invoker<Indices, ArgTypes...> invoker(&args, holder->flags);
+    if (invoker.IsOK())
+      invoker.DispatchToCallback(holder->callback);
+  }
+};
+
+}  // namespace internal
+
+
+// CreateFunctionTemplate creates a v8::FunctionTemplate that will create
+// JavaScript functions that execute a provided C++ function or base::Callback.
+// JavaScript arguments are automatically converted via gin::Converter, as is
+// the return value of the C++ function, if any.
+//
+// NOTE: V8 caches FunctionTemplates for a lifetime of a web page for its own
+// internal reasons, thus it is generally a good idea to cache the template
+// returned by this function.  Otherwise, repeated method invocations from JS
+// will create substantial memory leaks. See http://crbug.com/463487.
+template<typename Sig>
+v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(
+    v8::Isolate* isolate, const base::Callback<Sig> callback,
+    int callback_flags = 0) {
+  typedef internal::CallbackHolder<Sig> HolderT;
+  HolderT* holder = new HolderT(isolate, callback, callback_flags);
+
+  return v8::FunctionTemplate::New(
+      isolate,
+      &internal::Dispatcher<Sig>::DispatchToCallback,
+      ConvertToV8<v8::Local<v8::External> >(isolate,
+                                             holder->GetHandle(isolate)));
+}
+
+// CreateFunctionHandler installs a CallAsFunction handler on the given
+// object template that forwards to a provided C++ function or base::Callback.
+template<typename Sig>
+void CreateFunctionHandler(v8::Isolate* isolate,
+                           v8::Local<v8::ObjectTemplate> tmpl,
+                           const base::Callback<Sig> callback,
+                           int callback_flags = 0) {
+  typedef internal::CallbackHolder<Sig> HolderT;
+  HolderT* holder = new HolderT(isolate, callback, callback_flags);
+  tmpl->SetCallAsFunctionHandler(&internal::Dispatcher<Sig>::DispatchToCallback,
+                                 ConvertToV8<v8::Local<v8::External> >(
+                                     isolate, holder->GetHandle(isolate)));
+}
+
+}  // namespace mate
+
+#endif  // NATIVE_MATE_FUNCTION_TEMPLATE_H_

+ 72 - 0
native_mate/native_mate/handle.h

@@ -0,0 +1,72 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#ifndef NATIVE_MATE_HANDLE_H_
+#define NATIVE_MATE_HANDLE_H_
+
+#include "native_mate/converter.h"
+
+namespace mate {
+
+// You can use mate::Handle on the stack to retain a mate::Wrappable object.
+// Currently we don't have a mechanism for retaining a mate::Wrappable object
+// in the C++ heap because strong references from C++ to V8 can cause memory
+// leaks.
+template<typename T>
+class Handle {
+ public:
+  Handle() : object_(NULL) {}
+
+  Handle(v8::Local<v8::Object> wrapper, T* object)
+    : wrapper_(wrapper),
+      object_(object) {
+  }
+
+  bool IsEmpty() const { return !object_; }
+
+  void Clear() {
+    wrapper_.Clear();
+    object_ = NULL;
+  }
+
+  T* operator->() const { return object_; }
+  v8::Local<v8::Object> ToV8() const { return wrapper_; }
+  T* get() const { return object_; }
+
+ private:
+  v8::Local<v8::Object> wrapper_;
+  T* object_;
+};
+
+template<typename T>
+struct Converter<mate::Handle<T> > {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    const mate::Handle<T>& val) {
+    return val.ToV8();
+  }
+  static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val,
+                     mate::Handle<T>* out) {
+    T* object = NULL;
+    if (val->IsNull() || val->IsUndefined()) {
+      *out = mate::Handle<T>();
+      return true;
+    }
+    if (!Converter<T*>::FromV8(isolate, val, &object)) {
+      return false;
+    }
+    *out = mate::Handle<T>(val->ToObject(), object);
+    return true;
+  }
+};
+
+// This function is a convenient way to create a handle from a raw pointer
+// without having to write out the type of the object explicitly.
+template<typename T>
+mate::Handle<T> CreateHandle(v8::Isolate* isolate, T* object) {
+  return mate::Handle<T>(object->GetWrapper(), object);
+}
+
+}  // namespace mate
+
+#endif  // NATIVE_MATE_HANDLE_H_

+ 44 - 0
native_mate/native_mate/object_template_builder.cc

@@ -0,0 +1,44 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#include "native_mate/object_template_builder.h"
+
+namespace mate {
+
+ObjectTemplateBuilder::ObjectTemplateBuilder(
+    v8::Isolate* isolate,
+    v8::Local<v8::ObjectTemplate> templ)
+    : isolate_(isolate), template_(templ) {
+}
+
+ObjectTemplateBuilder::~ObjectTemplateBuilder() {
+}
+
+ObjectTemplateBuilder& ObjectTemplateBuilder::SetImpl(
+    const base::StringPiece& name, v8::Local<v8::Data> val) {
+  template_->Set(StringToSymbol(isolate_, name), val);
+  return *this;
+}
+
+ObjectTemplateBuilder& ObjectTemplateBuilder::SetPropertyImpl(
+    const base::StringPiece& name, v8::Local<v8::FunctionTemplate> getter,
+    v8::Local<v8::FunctionTemplate> setter) {
+  template_->SetAccessorProperty(StringToSymbol(isolate_, name), getter,
+                                 setter);
+  return *this;
+}
+
+ObjectTemplateBuilder& ObjectTemplateBuilder::MakeDestroyable() {
+  SetMethod("destroy", base::Bind(internal::Destroyable::Destroy));
+  SetMethod("isDestroyed", base::Bind(internal::Destroyable::IsDestroyed));
+  return *this;
+}
+
+v8::Local<v8::ObjectTemplate> ObjectTemplateBuilder::Build() {
+  v8::Local<v8::ObjectTemplate> result = template_;
+  template_.Clear();
+  return result;
+}
+
+}  // namespace mate

+ 131 - 0
native_mate/native_mate/object_template_builder.h

@@ -0,0 +1,131 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#ifndef NATIVE_MATE_OBJECT_TEMPLATE_BUILDER_H_
+#define NATIVE_MATE_OBJECT_TEMPLATE_BUILDER_H_
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/strings/string_piece.h"
+#include "native_mate/converter.h"
+#include "native_mate/function_template.h"
+#include "v8/include/v8.h"
+
+namespace mate {
+
+namespace {
+
+// Base template - used only for non-member function pointers. Other types
+// either go to one of the below specializations, or go here and fail to compile
+// because of base::Bind().
+template<typename T, typename Enable = void>
+struct CallbackTraits {
+  static v8::Local<v8::FunctionTemplate> CreateTemplate(
+      v8::Isolate* isolate, T callback) {
+    return CreateFunctionTemplate(isolate, base::Bind(callback));
+  }
+};
+
+// Specialization for base::Callback.
+template<typename T>
+struct CallbackTraits<base::Callback<T> > {
+  static v8::Local<v8::FunctionTemplate> CreateTemplate(
+      v8::Isolate* isolate, const base::Callback<T>& callback) {
+    return CreateFunctionTemplate(isolate, callback);
+  }
+};
+
+// Specialization for member function pointers. We need to handle this case
+// specially because the first parameter for callbacks to MFP should typically
+// come from the the JavaScript "this" object the function was called on, not
+// from the first normal parameter.
+template<typename T>
+struct CallbackTraits<T, typename std::enable_if<
+                           std::is_member_function_pointer<T>::value>::type> {
+  static v8::Local<v8::FunctionTemplate> CreateTemplate(
+      v8::Isolate* isolate, T callback) {
+    int flags = HolderIsFirstArgument;
+    return CreateFunctionTemplate(isolate, base::Bind(callback), flags);
+  }
+};
+
+// This specialization allows people to construct function templates directly if
+// they need to do fancier stuff.
+template<>
+struct CallbackTraits<v8::Local<v8::FunctionTemplate> > {
+  static v8::Local<v8::FunctionTemplate> CreateTemplate(
+      v8::Local<v8::FunctionTemplate> templ) {
+    return templ;
+  }
+};
+
+}  // namespace
+
+
+// ObjectTemplateBuilder provides a handy interface to creating
+// v8::ObjectTemplate instances with various sorts of properties.
+class ObjectTemplateBuilder {
+ public:
+  explicit ObjectTemplateBuilder(
+      v8::Isolate* isolate,
+      v8::Local<v8::ObjectTemplate> templ);
+  ~ObjectTemplateBuilder();
+
+  // It's against Google C++ style to return a non-const ref, but we take some
+  // poetic license here in order that all calls to Set() can be via the '.'
+  // operator and line up nicely.
+  template<typename T>
+  ObjectTemplateBuilder& SetValue(const base::StringPiece& name, T val) {
+    return SetImpl(name, ConvertToV8(isolate_, val));
+  }
+
+  // In the following methods, T and U can be function pointer, member function
+  // pointer, base::Callback, or v8::FunctionTemplate. Most clients will want to
+  // use one of the first two options. Also see mate::CreateFunctionTemplate()
+  // for creating raw function templates.
+  template<typename T>
+  ObjectTemplateBuilder& SetMethod(const base::StringPiece& name,
+                                   T callback) {
+    return SetImpl(name,
+                   CallbackTraits<T>::CreateTemplate(isolate_, callback));
+  }
+  template<typename T>
+  ObjectTemplateBuilder& SetProperty(const base::StringPiece& name,
+                                     T getter) {
+    return SetPropertyImpl(
+        name,
+        CallbackTraits<T>::CreateTemplate(isolate_, getter),
+        v8::Local<v8::FunctionTemplate>());
+  }
+  template<typename T, typename U>
+  ObjectTemplateBuilder& SetProperty(const base::StringPiece& name,
+                                     T getter,
+                                     U setter) {
+    return SetPropertyImpl(
+        name,
+        CallbackTraits<T>::CreateTemplate(isolate_, getter),
+        CallbackTraits<U>::CreateTemplate(isolate_, setter));
+  }
+
+  // Add "destroy" and "isDestroyed" methods.
+  ObjectTemplateBuilder& MakeDestroyable();
+
+  v8::Local<v8::ObjectTemplate> Build();
+
+ private:
+  ObjectTemplateBuilder& SetImpl(const base::StringPiece& name,
+                                 v8::Local<v8::Data> val);
+  ObjectTemplateBuilder& SetPropertyImpl(
+      const base::StringPiece& name, v8::Local<v8::FunctionTemplate> getter,
+      v8::Local<v8::FunctionTemplate> setter);
+
+  v8::Isolate* isolate_;
+
+  // ObjectTemplateBuilder should only be used on the stack.
+  v8::Local<v8::ObjectTemplate> template_;
+};
+
+}  // namespace mate
+
+#endif  // NATIVE_MATE_OBJECT_TEMPLATE_BUILDER_H_

+ 34 - 0
native_mate/native_mate/persistent_dictionary.cc

@@ -0,0 +1,34 @@
+// Copyright 2014 Cheng Zhao. All rights reserved.
+// Use of this source code is governed by MIT license that can be found in the
+// LICENSE file.
+
+#include "native_mate/persistent_dictionary.h"
+
+namespace mate {
+
+PersistentDictionary::PersistentDictionary() {
+}
+
+PersistentDictionary::PersistentDictionary(v8::Isolate* isolate,
+                                           v8::Local<v8::Object> object)
+    : handle_(new RefCountedPersistent<v8::Object>(isolate, object)) {
+  isolate_ = isolate;
+}
+
+PersistentDictionary::~PersistentDictionary() {
+}
+
+v8::Local<v8::Object> PersistentDictionary::GetHandle() const {
+  return handle_->NewHandle();
+}
+
+bool Converter<PersistentDictionary>::FromV8(v8::Isolate* isolate,
+                                             v8::Local<v8::Value> val,
+                                             PersistentDictionary* out) {
+  if (!val->IsObject())
+    return false;
+  *out = PersistentDictionary(isolate, v8::Local<v8::Object>::Cast(val));
+  return true;
+}
+
+}  // namespace mate

+ 36 - 0
native_mate/native_mate/persistent_dictionary.h

@@ -0,0 +1,36 @@
+// Copyright 2014 Cheng Zhao. All rights reserved.
+// Use of this source code is governed by MIT license that can be found in the
+// LICENSE file.
+
+#ifndef NATIVE_MATE_PERSISTENT_DICTIONARY_H_
+#define NATIVE_MATE_PERSISTENT_DICTIONARY_H_
+
+#include "native_mate/dictionary.h"
+#include "native_mate/scoped_persistent.h"
+
+namespace mate {
+
+// Like Dictionary, but stores object in persistent handle so you can keep it
+// safely on heap.
+class PersistentDictionary : public Dictionary {
+ public:
+  PersistentDictionary();
+  PersistentDictionary(v8::Isolate* isolate, v8::Local<v8::Object> object);
+  virtual ~PersistentDictionary();
+
+  v8::Local<v8::Object> GetHandle() const override;
+
+ private:
+  scoped_refptr<RefCountedPersistent<v8::Object> > handle_;
+};
+
+template<>
+struct Converter<PersistentDictionary> {
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     PersistentDictionary* out);
+};
+
+}  // namespace mate
+
+#endif  // NATIVE_MATE_PERSISTENT_DICTIONARY_H_

+ 45 - 0
native_mate/native_mate/promise.cc

@@ -0,0 +1,45 @@
+// Copyright (c) 2018 GitHub, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#include "native_mate/promise.h"
+
+namespace mate {
+
+Promise::Promise()
+    : isolate_(NULL) {
+}
+
+Promise::Promise(v8::Isolate* isolate)
+    : isolate_(isolate) {
+  resolver_ = v8::Promise::Resolver::New(isolate);
+}
+
+Promise::~Promise() {
+}
+
+Promise Promise::Create(v8::Isolate* isolate) {
+  return Promise(isolate);
+}
+
+Promise Promise::Create() {
+  return Promise::Create(v8::Isolate::GetCurrent());
+}
+
+void Promise::RejectWithErrorMessage(const std::string& string) {
+  v8::Local<v8::String> error_message =
+      v8::String::NewFromUtf8(isolate(), string.c_str());
+  v8::Local<v8::Value> error = v8::Exception::Error(error_message);
+  resolver_->Reject(mate::ConvertToV8(isolate(), error));
+}
+
+v8::Local<v8::Object> Promise::GetHandle() const {
+  return resolver_->GetPromise();
+}
+
+v8::Local<v8::Value> Converter<Promise>::ToV8(v8::Isolate* isolate,
+                                                  Promise val) {
+  return val.GetHandle();
+}
+
+}  // namespace mate

+ 57 - 0
native_mate/native_mate/promise.h

@@ -0,0 +1,57 @@
+// Copyright (c) 2018 GitHub, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#ifndef NATIVE_MATE_PROMISE_H_
+#define NATIVE_MATE_PROMISE_H_
+
+#include "native_mate/converter.h"
+
+namespace mate {
+
+class Promise {
+ public:
+  Promise();
+  Promise(v8::Isolate* isolate);
+  virtual ~Promise();
+
+  static Promise Create(v8::Isolate* isolate);
+  static Promise Create();
+
+  v8::Isolate* isolate() const { return isolate_; }
+
+  virtual v8::Local<v8::Object> GetHandle() const;
+
+  template<typename T>
+  void Resolve(T* value) {
+    resolver_->Resolve(mate::ConvertToV8(isolate(), value));
+  }
+
+  template<typename T>
+  void Reject(T* value) {
+    resolver_->Reject(mate::ConvertToV8(isolate(), value));
+  }
+
+  void RejectWithErrorMessage(const std::string& error);
+
+ protected:
+  v8::Isolate* isolate_;
+
+ private:
+  v8::Local<v8::Promise::Resolver> resolver_;
+};
+
+template<>
+struct Converter<Promise> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    Promise val);
+  // TODO(MarshallOfSound): Implement FromV8 to allow promise chaining
+  //                        in native land
+  // static bool FromV8(v8::Isolate* isolate,
+  //                    v8::Local<v8::Value> val,
+  //                    Promise* out);
+};
+
+}  // namespace mate
+
+#endif  // NATIVE_MATE_PROMISE_H_

+ 111 - 0
native_mate/native_mate/scoped_persistent.h

@@ -0,0 +1,111 @@
+// Copyright 2014 Cheng Zhao. All rights reserved.
+// Use of this source code is governed by MIT license that can be found in the
+// LICENSE file.
+
+#ifndef NATIVE_MATE_SCOPED_PERSISTENT_H_
+#define NATIVE_MATE_SCOPED_PERSISTENT_H_
+
+#include "base/memory/ref_counted.h"
+#include "native_mate/converter.h"
+#include "v8/include/v8.h"
+
+namespace mate {
+
+// A v8::Persistent handle to a V8 value which destroys and clears the
+// underlying handle on destruction.
+template <typename T>
+class ScopedPersistent {
+ public:
+  ScopedPersistent() : isolate_(v8::Isolate::GetCurrent()) {}
+
+  ScopedPersistent(v8::Isolate* isolate, v8::Local<v8::Value> handle)
+      : isolate_(isolate) {
+    reset(isolate, v8::Local<T>::Cast(handle));
+  }
+
+  ~ScopedPersistent() {
+    reset();
+  }
+
+  void reset(v8::Isolate* isolate, v8::Local<T> handle) {
+    if (!handle.IsEmpty()) {
+      isolate_ = isolate;
+      handle_.Reset(isolate, handle);
+    } else {
+      reset();
+    }
+  }
+
+  void reset() {
+    handle_.Reset();
+  }
+
+  bool IsEmpty() const {
+    return handle_.IsEmpty();
+  }
+
+  v8::Local<T> NewHandle() const {
+    return NewHandle(isolate_);
+  }
+
+  v8::Local<T> NewHandle(v8::Isolate* isolate) const {
+    if (handle_.IsEmpty())
+      return v8::Local<T>();
+    return v8::Local<T>::New(isolate, handle_);
+  }
+
+  template<typename P, typename C>
+  void SetWeak(P* parameter, C callback) {
+    handle_.SetWeak(parameter, callback);
+  }
+
+  v8::Isolate* isolate() const { return isolate_; }
+
+ private:
+  v8::Isolate* isolate_;
+  v8::Persistent<T> handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPersistent);
+};
+
+template <typename T>
+class RefCountedPersistent : public ScopedPersistent<T>,
+                             public base::RefCounted<RefCountedPersistent<T>> {
+ public:
+  RefCountedPersistent() {}
+
+  RefCountedPersistent(v8::Isolate* isolate, v8::Local<v8::Value> handle)
+    : ScopedPersistent<T>(isolate, handle) {
+  }
+
+ protected:
+  friend class base::RefCounted<RefCountedPersistent<T>>;
+
+  ~RefCountedPersistent() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RefCountedPersistent);
+};
+
+template<typename T>
+struct Converter<ScopedPersistent<T> > {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                    const ScopedPersistent<T>& val) {
+    return val.NewHandle(isolate);
+  }
+
+  static bool FromV8(v8::Isolate* isolate,
+                     v8::Local<v8::Value> val,
+                     ScopedPersistent<T>* out) {
+    v8::Local<T> converted;
+    if (!Converter<v8::Local<T> >::FromV8(isolate, val, &converted))
+      return false;
+
+    out->reset(isolate, converted);
+    return true;
+  }
+};
+
+}  // namespace mate
+
+#endif  // NATIVE_MATE_SCOPED_PERSISTENT_H_

+ 75 - 0
native_mate/native_mate/wrappable.cc

@@ -0,0 +1,75 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#include "native_mate/wrappable.h"
+
+#include "base/logging.h"
+#include "native_mate/dictionary.h"
+#include "native_mate/object_template_builder.h"
+
+namespace mate {
+
+WrappableBase::WrappableBase() : isolate_(nullptr) {}
+
+WrappableBase::~WrappableBase() {
+  if (wrapper_.IsEmpty())
+    return;
+
+  GetWrapper()->SetAlignedPointerInInternalField(0, nullptr);
+  wrapper_.ClearWeak();
+  wrapper_.Reset();
+}
+
+v8::Local<v8::Object> WrappableBase::GetWrapper() const {
+  if (!wrapper_.IsEmpty())
+    return v8::Local<v8::Object>::New(isolate_, wrapper_);
+  else
+    return v8::Local<v8::Object>();
+}
+
+void WrappableBase::InitWith(v8::Isolate* isolate,
+                             v8::Local<v8::Object> wrapper) {
+  CHECK(wrapper_.IsEmpty());
+  isolate_ = isolate;
+  wrapper->SetAlignedPointerInInternalField(0, this);
+  wrapper_.Reset(isolate, wrapper);
+  wrapper_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
+
+  // Call object._init if we have one.
+  v8::Local<v8::Function> init;
+  if (Dictionary(isolate, wrapper).Get("_init", &init))
+    init->Call(wrapper, 0, nullptr);
+
+  AfterInit(isolate);
+}
+
+// static
+void WrappableBase::FirstWeakCallback(
+    const v8::WeakCallbackInfo<WrappableBase>& data) {
+  WrappableBase* wrappable = data.GetParameter();
+  wrappable->wrapper_.Reset();
+  data.SetSecondPassCallback(SecondWeakCallback);
+}
+
+// static
+void WrappableBase::SecondWeakCallback(
+    const v8::WeakCallbackInfo<WrappableBase>& data) {
+  WrappableBase* wrappable = data.GetParameter();
+  delete wrappable;
+}
+
+namespace internal {
+
+void* FromV8Impl(v8::Isolate* isolate, v8::Local<v8::Value> val) {
+  if (!val->IsObject())
+    return nullptr;
+  v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(val);
+  if (obj->InternalFieldCount() != 1)
+    return nullptr;
+  return obj->GetAlignedPointerFromInternalField(0);
+}
+
+}  // namespace internal
+
+}  // namespace mate

+ 99 - 0
native_mate/native_mate/wrappable.h

@@ -0,0 +1,99 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.chromium file.
+
+#ifndef NATIVE_MATE_WRAPPABLE_H_
+#define NATIVE_MATE_WRAPPABLE_H_
+
+#include "base/bind.h"
+#include "native_mate/converter.h"
+#include "native_mate/constructor.h"
+#include "gin/per_isolate_data.h"
+
+namespace mate {
+
+namespace internal {
+
+void* FromV8Impl(v8::Isolate* isolate, v8::Local<v8::Value> val);
+
+}  // namespace internal
+
+template<typename T>
+class Wrappable : public WrappableBase {
+ public:
+  Wrappable() {}
+
+  template<typename Sig>
+  static void SetConstructor(v8::Isolate* isolate,
+                             const base::Callback<Sig>& constructor) {
+    v8::Local<v8::FunctionTemplate> templ = CreateFunctionTemplate(
+        isolate, base::Bind(&internal::InvokeNew<Sig>, constructor));
+    templ->InstanceTemplate()->SetInternalFieldCount(1);
+    T::BuildPrototype(isolate, templ);
+    gin::PerIsolateData::From(isolate)->SetFunctionTemplate(
+        &kWrapperInfo, templ);
+  }
+
+  static v8::Local<v8::FunctionTemplate> GetConstructor(v8::Isolate* isolate) {
+    // Fill the object template.
+    auto data = gin::PerIsolateData::From(isolate);
+    auto templ = data->GetFunctionTemplate(&kWrapperInfo);
+    if (templ.IsEmpty()) {
+      templ = v8::FunctionTemplate::New(isolate);
+      templ->InstanceTemplate()->SetInternalFieldCount(1);
+      T::BuildPrototype(isolate, templ);
+      data->SetFunctionTemplate(&kWrapperInfo, templ);
+    }
+    return templ;
+  }
+
+ protected:
+  // Init the class with T::BuildPrototype.
+  void Init(v8::Isolate* isolate) {
+    v8::Local<v8::FunctionTemplate> templ = GetConstructor(isolate);
+
+    // |wrapper| may be empty in some extreme cases, e.g., when
+    // Object.prototype.constructor is overwritten.
+    v8::Local<v8::Object> wrapper;
+    if (!templ->InstanceTemplate()->NewInstance(
+            isolate->GetCurrentContext()).ToLocal(&wrapper)) {
+      // The current wrappable object will be no longer managed by V8. Delete
+      // this now.
+      delete this;
+      return;
+    }
+    InitWith(isolate, wrapper);
+  }
+
+ private:
+  static gin::WrapperInfo kWrapperInfo;
+
+  DISALLOW_COPY_AND_ASSIGN(Wrappable);
+};
+
+// static
+template<typename T>
+gin::WrapperInfo Wrappable<T>::kWrapperInfo = { gin::kEmbedderNativeGin };
+
+// This converter handles any subclass of Wrappable.
+template <typename T>
+struct Converter<T*,
+                 typename std::enable_if<
+                     std::is_convertible<T*, WrappableBase*>::value>::type> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, T* val) {
+    if (val)
+      return val->GetWrapper();
+    else
+      return v8::Null(isolate);
+  }
+
+  static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val, T** out) {
+    *out = static_cast<T*>(static_cast<WrappableBase*>(
+        internal::FromV8Impl(isolate, val)));
+    return *out != nullptr;
+  }
+};
+
+}  // namespace mate
+
+#endif  // NATIVE_MATE_WRAPPABLE_H_

+ 61 - 0
native_mate/native_mate/wrappable_base.h

@@ -0,0 +1,61 @@
+#ifndef NATIVE_MATE_WRAPPABLE_BASE_H_
+#define NATIVE_MATE_WRAPPABLE_BASE_H_
+
+namespace mate {
+
+namespace internal {
+struct Destroyable;
+}
+
+// Wrappable is a base class for C++ objects that have corresponding v8 wrapper
+// objects. To retain a Wrappable object on the stack, use a gin::Handle.
+//
+// USAGE:
+// // my_class.h
+// class MyClass : Wrappable<MyClass> {
+//  public:
+//   ...
+// };
+//
+// Subclasses should also typically have private constructors and expose a
+// static Create function that returns a mate::Handle. Forcing creators through
+// this static Create function will enforce that clients actually create a
+// wrapper for the object. If clients fail to create a wrapper for a wrappable
+// object, the object will leak because we use the weak callback from the
+// wrapper as the signal to delete the wrapped object.
+class WrappableBase {
+ public:
+  WrappableBase();
+  virtual ~WrappableBase();
+
+  // Retrieve the v8 wrapper object cooresponding to this object.
+  v8::Local<v8::Object> GetWrapper() const;
+
+  // Returns the Isolate this object is created in.
+  v8::Isolate* isolate() const { return isolate_; }
+
+ protected:
+  // Called after the "_init" method gets called in JavaScript.
+  virtual void AfterInit(v8::Isolate* isolate) {}
+
+  // Bind the C++ class to the JS wrapper.
+  // This method should only be called by classes using Constructor.
+  virtual void InitWith(v8::Isolate* isolate, v8::Local<v8::Object> wrapper);
+
+ private:
+  friend struct internal::Destroyable;
+
+  static void FirstWeakCallback(
+      const v8::WeakCallbackInfo<WrappableBase>& data);
+  static void SecondWeakCallback(
+      const v8::WeakCallbackInfo<WrappableBase>& data);
+
+  v8::Isolate* isolate_;
+  v8::Global<v8::Object> wrapper_;  // Weak
+
+  DISALLOW_COPY_AND_ASSIGN(WrappableBase);
+};
+
+}  // namespace mate
+
+#endif  // NATIVE_MATE_WRAPPABLE_BASE_H_

+ 26 - 0
native_mate/native_mate_files.gypi

@@ -0,0 +1,26 @@
+{
+  'variables': {
+    'native_mate_files': [
+      'native_mate/arguments.cc',
+      'native_mate/arguments.h',
+      'native_mate/constructor.h',
+      'native_mate/converter.cc',
+      'native_mate/converter.h',
+      'native_mate/dictionary.cc',
+      'native_mate/dictionary.h',
+      'native_mate/function_template.cc',
+      'native_mate/function_template.h',
+      'native_mate/handle.h',
+      'native_mate/object_template_builder.cc',
+      'native_mate/object_template_builder.h',
+      'native_mate/persistent_dictionary.cc',
+      'native_mate/persistent_dictionary.h',
+      'native_mate/scoped_persistent.h',
+      'native_mate/wrappable.cc',
+      'native_mate/wrappable.h',
+      'native_mate/wrappable_base.h',
+      'native_mate/promise.h',
+      'native_mate/promise.cc',
+    ],
+  },
+}

+ 855 - 0
script/pump.py

@@ -0,0 +1,855 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""pump v0.2.0 - Pretty Useful for Meta Programming.
+
+A tool for preprocessor meta programming.  Useful for generating
+repetitive boilerplate code.  Especially useful for writing C++
+classes, functions, macros, and templates that need to work with
+various number of arguments.
+
+USAGE:
+       pump.py SOURCE_FILE
+
+EXAMPLES:
+       pump.py foo.cc.pump
+         Converts foo.cc.pump to foo.cc.
+
+GRAMMAR:
+       CODE ::= ATOMIC_CODE*
+       ATOMIC_CODE ::= $var ID = EXPRESSION
+           | $var ID = [[ CODE ]]
+           | $range ID EXPRESSION..EXPRESSION
+           | $for ID SEPARATOR [[ CODE ]]
+           | $($)
+           | $ID
+           | $(EXPRESSION)
+           | $if EXPRESSION [[ CODE ]] ELSE_BRANCH
+           | [[ CODE ]]
+           | RAW_CODE
+       SEPARATOR ::= RAW_CODE | EMPTY
+       ELSE_BRANCH ::= $else [[ CODE ]]
+           | $elif EXPRESSION [[ CODE ]] ELSE_BRANCH
+           | EMPTY
+       EXPRESSION has Python syntax.
+"""
+
+__author__ = '[email protected] (Zhanyong Wan)'
+
+import os
+import re
+import sys
+
+
+TOKEN_TABLE = [
+    (re.compile(r'\$var\s+'), '$var'),
+    (re.compile(r'\$elif\s+'), '$elif'),
+    (re.compile(r'\$else\s+'), '$else'),
+    (re.compile(r'\$for\s+'), '$for'),
+    (re.compile(r'\$if\s+'), '$if'),
+    (re.compile(r'\$range\s+'), '$range'),
+    (re.compile(r'\$[_A-Za-z]\w*'), '$id'),
+    (re.compile(r'\$\(\$\)'), '$($)'),
+    (re.compile(r'\$'), '$'),
+    (re.compile(r'\[\[\n?'), '[['),
+    (re.compile(r'\]\]\n?'), ']]'),
+    ]
+
+
+class Cursor:
+  """Represents a position (line and column) in a text file."""
+
+  def __init__(self, line=-1, column=-1):
+    self.line = line
+    self.column = column
+
+  def __eq__(self, rhs):
+    return self.line == rhs.line and self.column == rhs.column
+
+  def __ne__(self, rhs):
+    return not self == rhs
+
+  def __lt__(self, rhs):
+    return self.line < rhs.line or (
+        self.line == rhs.line and self.column < rhs.column)
+
+  def __le__(self, rhs):
+    return self < rhs or self == rhs
+
+  def __gt__(self, rhs):
+    return rhs < self
+
+  def __ge__(self, rhs):
+    return rhs <= self
+
+  def __str__(self):
+    if self == Eof():
+      return 'EOF'
+    else:
+      return '%s(%s)' % (self.line + 1, self.column)
+
+  def __add__(self, offset):
+    return Cursor(self.line, self.column + offset)
+
+  def __sub__(self, offset):
+    return Cursor(self.line, self.column - offset)
+
+  def Clone(self):
+    """Returns a copy of self."""
+
+    return Cursor(self.line, self.column)
+
+
+# Special cursor to indicate the end-of-file.
+def Eof():
+  """Returns the special cursor to denote the end-of-file."""
+  return Cursor(-1, -1)
+
+
+class Token:
+  """Represents a token in a Pump source file."""
+
+  def __init__(self, start=None, end=None, value=None, token_type=None):
+    if start is None:
+      self.start = Eof()
+    else:
+      self.start = start
+    if end is None:
+      self.end = Eof()
+    else:
+      self.end = end
+    self.value = value
+    self.token_type = token_type
+
+  def __str__(self):
+    return 'Token @%s: \'%s\' type=%s' % (
+        self.start, self.value, self.token_type)
+
+  def Clone(self):
+    """Returns a copy of self."""
+
+    return Token(self.start.Clone(), self.end.Clone(), self.value,
+                 self.token_type)
+
+
+def StartsWith(lines, pos, string):
+  """Returns True iff the given position in lines starts with 'string'."""
+
+  return lines[pos.line][pos.column:].startswith(string)
+
+
+def FindFirstInLine(line, token_table):
+  best_match_start = -1
+  for (regex, token_type) in token_table:
+    m = regex.search(line)
+    if m:
+      # We found regex in lines
+      if best_match_start < 0 or m.start() < best_match_start:
+        best_match_start = m.start()
+        best_match_length = m.end() - m.start()
+        best_match_token_type = token_type
+
+  if best_match_start < 0:
+    return None
+
+  return (best_match_start, best_match_length, best_match_token_type)
+
+
+def FindFirst(lines, token_table, cursor):
+  """Finds the first occurrence of any string in strings in lines."""
+
+  start = cursor.Clone()
+  cur_line_number = cursor.line
+  for line in lines[start.line:]:
+    if cur_line_number == start.line:
+      line = line[start.column:]
+    m = FindFirstInLine(line, token_table)
+    if m:
+      # We found a regex in line.
+      (start_column, length, token_type) = m
+      if cur_line_number == start.line:
+        start_column += start.column
+      found_start = Cursor(cur_line_number, start_column)
+      found_end = found_start + length
+      return MakeToken(lines, found_start, found_end, token_type)
+    cur_line_number += 1
+  # We failed to find str in lines
+  return None
+
+
+def SubString(lines, start, end):
+  """Returns a substring in lines."""
+
+  if end == Eof():
+    end = Cursor(len(lines) - 1, len(lines[-1]))
+
+  if start >= end:
+    return ''
+
+  if start.line == end.line:
+    return lines[start.line][start.column:end.column]
+
+  result_lines = ([lines[start.line][start.column:]] +
+                  lines[start.line + 1:end.line] +
+                  [lines[end.line][:end.column]])
+  return ''.join(result_lines)
+
+
+def StripMetaComments(_str):
+  """Strip meta comments from each line in the given string."""
+
+  # First, completely remove lines containing nothing but a meta
+  # comment, including the trailing \n.
+  _str = re.sub(r'^\s*\$\$.*\n', '', _str)
+
+  # Then, remove meta comments from contentful lines.
+  return re.sub(r'\s*\$\$.*', '', _str)
+
+
+def MakeToken(lines, start, end, token_type):
+  """Creates a new instance of Token."""
+
+  return Token(start, end, SubString(lines, start, end), token_type)
+
+
+def ParseToken(lines, pos, regex, token_type):
+  line = lines[pos.line][pos.column:]
+  m = regex.search(line)
+  if m and not m.start():
+    return MakeToken(lines, pos, pos + m.end(), token_type)
+  else:
+    print 'ERROR: %s expected at %s.' % (token_type, pos)
+    sys.exit(1)
+
+
+ID_REGEX = re.compile(r'[_A-Za-z]\w*')
+EQ_REGEX = re.compile(r'=')
+REST_OF_LINE_REGEX = re.compile(r'.*?(?=$|\$\$)')
+OPTIONAL_WHITE_SPACES_REGEX = re.compile(r'\s*')
+WHITE_SPACE_REGEX = re.compile(r'\s')
+DOT_DOT_REGEX = re.compile(r'\.\.')
+
+
+def Skip(lines, pos, regex):
+  line = lines[pos.line][pos.column:]
+  m = re.search(regex, line)
+  if m and not m.start():
+    return pos + m.end()
+  else:
+    return pos
+
+
+def SkipUntil(lines, pos, regex, token_type):
+  line = lines[pos.line][pos.column:]
+  m = re.search(regex, line)
+  if m:
+    return pos + m.start()
+  else:
+    print ('ERROR: %s expected on line %s after column %s.' %
+           (token_type, pos.line + 1, pos.column))
+    sys.exit(1)
+
+
+def ParseExpTokenInParens(lines, pos):
+  def ParseInParens(pos):
+    pos = Skip(lines, pos, OPTIONAL_WHITE_SPACES_REGEX)
+    pos = Skip(lines, pos, r'\(')
+    pos = Parse(pos)
+    pos = Skip(lines, pos, r'\)')
+    return pos
+
+  def Parse(pos):
+    pos = SkipUntil(lines, pos, r'\(|\)', ')')
+    if SubString(lines, pos, pos + 1) == '(':
+      pos = Parse(pos + 1)
+      pos = Skip(lines, pos, r'\)')
+      return Parse(pos)
+    else:
+      return pos
+
+  start = pos.Clone()
+  pos = ParseInParens(pos)
+  return MakeToken(lines, start, pos, 'exp')
+
+
+def RStripNewLineFromToken(token):
+  if token.value.endswith('\n'):
+    return Token(token.start, token.end, token.value[:-1], token.token_type)
+  else:
+    return token
+
+
+def TokenizeLines(lines, pos):
+  while True:
+    found = FindFirst(lines, TOKEN_TABLE, pos)
+    if not found:
+      yield MakeToken(lines, pos, Eof(), 'code')
+      return
+
+    if found.start == pos:
+      prev_token = None
+      prev_token_rstripped = None
+    else:
+      prev_token = MakeToken(lines, pos, found.start, 'code')
+      prev_token_rstripped = RStripNewLineFromToken(prev_token)
+
+    if found.token_type == '$var':
+      if prev_token_rstripped:
+        yield prev_token_rstripped
+      yield found
+      id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
+      yield id_token
+      pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX)
+
+      eq_token = ParseToken(lines, pos, EQ_REGEX, '=')
+      yield eq_token
+      pos = Skip(lines, eq_token.end, r'\s*')
+
+      if SubString(lines, pos, pos + 2) != '[[':
+        exp_token = ParseToken(lines, pos, REST_OF_LINE_REGEX, 'exp')
+        yield exp_token
+        pos = Cursor(exp_token.end.line + 1, 0)
+    elif found.token_type == '$for':
+      if prev_token_rstripped:
+        yield prev_token_rstripped
+      yield found
+      id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
+      yield id_token
+      pos = Skip(lines, id_token.end, WHITE_SPACE_REGEX)
+    elif found.token_type == '$range':
+      if prev_token_rstripped:
+        yield prev_token_rstripped
+      yield found
+      id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
+      yield id_token
+      pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX)
+
+      dots_pos = SkipUntil(lines, pos, DOT_DOT_REGEX, '..')
+      yield MakeToken(lines, pos, dots_pos, 'exp')
+      yield MakeToken(lines, dots_pos, dots_pos + 2, '..')
+      pos = dots_pos + 2
+      new_pos = Cursor(pos.line + 1, 0)
+      yield MakeToken(lines, pos, new_pos, 'exp')
+      pos = new_pos
+    elif found.token_type == '$':
+      if prev_token:
+        yield prev_token
+      yield found
+      exp_token = ParseExpTokenInParens(lines, found.end)
+      yield exp_token
+      pos = exp_token.end
+    elif (found.token_type == ']]' or found.token_type == '$if' or
+          found.token_type == '$elif' or found.token_type == '$else'):
+      if prev_token_rstripped:
+        yield prev_token_rstripped
+      yield found
+      pos = found.end
+    else:
+      if prev_token:
+        yield prev_token
+      yield found
+      pos = found.end
+
+
+def Tokenize(s):
+  """A generator that yields the tokens in the given string."""
+  if s != '':
+    lines = s.splitlines(True)
+    for token in TokenizeLines(lines, Cursor(0, 0)):
+      yield token
+
+
+class CodeNode:
+  def __init__(self, atomic_code_list=None):
+    self.atomic_code = atomic_code_list
+
+
+class VarNode:
+  def __init__(self, identifier=None, atomic_code=None):
+    self.identifier = identifier
+    self.atomic_code = atomic_code
+
+
+class RangeNode:
+  def __init__(self, identifier=None, exp1=None, exp2=None):
+    self.identifier = identifier
+    self.exp1 = exp1
+    self.exp2 = exp2
+
+
+class ForNode:
+  def __init__(self, identifier=None, sep=None, code=None):
+    self.identifier = identifier
+    self.sep = sep
+    self.code = code
+
+
+class ElseNode:
+  def __init__(self, else_branch=None):
+    self.else_branch = else_branch
+
+
+class IfNode:
+  def __init__(self, exp=None, then_branch=None, else_branch=None):
+    self.exp = exp
+    self.then_branch = then_branch
+    self.else_branch = else_branch
+
+
+class RawCodeNode:
+  def __init__(self, token=None):
+    self.raw_code = token
+
+
+class LiteralDollarNode:
+  def __init__(self, token):
+    self.token = token
+
+
+class ExpNode:
+  def __init__(self, token, python_exp):
+    self.token = token
+    self.python_exp = python_exp
+
+
+def PopFront(a_list):
+  head = a_list[0]
+  a_list[:1] = []
+  return head
+
+
+def PushFront(a_list, elem):
+  a_list[:0] = [elem]
+
+
+def PopToken(a_list, token_type=None):
+  token = PopFront(a_list)
+  if token_type is not None and token.token_type != token_type:
+    print 'ERROR: %s expected at %s' % (token_type, token.start)
+    print 'ERROR: %s found instead' % (token,)
+    sys.exit(1)
+
+  return token
+
+
+def PeekToken(a_list):
+  if not a_list:
+    return None
+
+  return a_list[0]
+
+
+def ParseExpNode(token):
+  python_exp = re.sub(r'([_A-Za-z]\w*)', r'self.GetValue("\1")', token.value)
+  return ExpNode(token, python_exp)
+
+
+def ParseElseNode(tokens):
+  def Pop(token_type=None):
+    return PopToken(tokens, token_type)
+
+  _next = PeekToken(tokens)
+  if not next:
+    return None
+  if _next.token_type == '$else':
+    Pop('$else')
+    Pop('[[')
+    code_node = ParseCodeNode(tokens)
+    Pop(']]')
+    return code_node
+  elif _next.token_type == '$elif':
+    Pop('$elif')
+    exp = Pop('code')
+    Pop('[[')
+    code_node = ParseCodeNode(tokens)
+    Pop(']]')
+    inner_else_node = ParseElseNode(tokens)
+    return CodeNode([IfNode(ParseExpNode(exp), code_node, inner_else_node)])
+  elif not _next.value.strip():
+    Pop('code')
+    return ParseElseNode(tokens)
+  else:
+    return None
+
+
+def ParseAtomicCodeNode(tokens):
+  def Pop(token_type=None):
+    return PopToken(tokens, token_type)
+
+  head = PopFront(tokens)
+  t = head.token_type
+  if t == 'code':
+    return RawCodeNode(head)
+  elif t == '$var':
+    id_token = Pop('id')
+    Pop('=')
+    _next = PeekToken(tokens)
+    if _next.token_type == 'exp':
+      exp_token = Pop()
+      return VarNode(id_token, ParseExpNode(exp_token))
+    Pop('[[')
+    code_node = ParseCodeNode(tokens)
+    Pop(']]')
+    return VarNode(id_token, code_node)
+  elif t == '$for':
+    id_token = Pop('id')
+    next_token = PeekToken(tokens)
+    if next_token.token_type == 'code':
+      sep_token = next_token
+      Pop('code')
+    else:
+      sep_token = None
+    Pop('[[')
+    code_node = ParseCodeNode(tokens)
+    Pop(']]')
+    return ForNode(id_token, sep_token, code_node)
+  elif t == '$if':
+    exp_token = Pop('code')
+    Pop('[[')
+    code_node = ParseCodeNode(tokens)
+    Pop(']]')
+    else_node = ParseElseNode(tokens)
+    return IfNode(ParseExpNode(exp_token), code_node, else_node)
+  elif t == '$range':
+    id_token = Pop('id')
+    exp1_token = Pop('exp')
+    Pop('..')
+    exp2_token = Pop('exp')
+    return RangeNode(id_token, ParseExpNode(exp1_token),
+                     ParseExpNode(exp2_token))
+  elif t == '$id':
+    return ParseExpNode(Token(head.start + 1, head.end, head.value[1:], 'id'))
+  elif t == '$($)':
+    return LiteralDollarNode(head)
+  elif t == '$':
+    exp_token = Pop('exp')
+    return ParseExpNode(exp_token)
+  elif t == '[[':
+    code_node = ParseCodeNode(tokens)
+    Pop(']]')
+    return code_node
+  else:
+    PushFront(tokens, head)
+    return None
+
+
+def ParseCodeNode(tokens):
+  atomic_code_list = []
+  while True:
+    if not tokens:
+      break
+    atomic_code_node = ParseAtomicCodeNode(tokens)
+    if atomic_code_node:
+      atomic_code_list.append(atomic_code_node)
+    else:
+      break
+  return CodeNode(atomic_code_list)
+
+
+def ParseToAST(pump_src_text):
+  """Convert the given Pump source text into an AST."""
+  tokens = list(Tokenize(pump_src_text))
+  code_node = ParseCodeNode(tokens)
+  return code_node
+
+
+class Env:
+  def __init__(self):
+    self.variables = []
+    self.ranges = []
+
+  def Clone(self):
+    clone = Env()
+    clone.variables = self.variables[:]
+    clone.ranges = self.ranges[:]
+    return clone
+
+  def PushVariable(self, var, value):
+    # If value looks like an int, store it as an int.
+    try:
+      int_value = int(value)
+      if ('%s' % int_value) == value:
+        value = int_value
+    except Exception:
+      pass
+    self.variables[:0] = [(var, value)]
+
+  def PopVariable(self):
+    self.variables[:1] = []
+
+  def PushRange(self, var, lower, upper):
+    self.ranges[:0] = [(var, lower, upper)]
+
+  def PopRange(self):
+    self.ranges[:1] = []
+
+  def GetValue(self, identifier):
+    for (var, value) in self.variables:
+      if identifier == var:
+        return value
+
+    print 'ERROR: meta variable %s is undefined.' % (identifier,)
+    sys.exit(1)
+
+  def EvalExp(self, exp):
+    try:
+      result = eval(exp.python_exp)
+    except Exception, e:
+      print 'ERROR: caught exception %s: %s' % (e.__class__.__name__, e)
+      print ('ERROR: failed to evaluate meta expression %s at %s' %
+             (exp.python_exp, exp.token.start))
+      sys.exit(1)
+    return result
+
+  def GetRange(self, identifier):
+    for (var, lower, upper) in self.ranges:
+      if identifier == var:
+        return (lower, upper)
+
+    print 'ERROR: range %s is undefined.' % (identifier,)
+    sys.exit(1)
+
+
+class Output:
+  def __init__(self):
+    self.string = ''
+
+  def GetLastLine(self):
+    index = self.string.rfind('\n')
+    if index < 0:
+      return ''
+
+    return self.string[index + 1:]
+
+  def Append(self, s):
+    self.string += s
+
+
+def RunAtomicCode(env, node, output):
+  if isinstance(node, VarNode):
+    identifier = node.identifier.value.strip()
+    result = Output()
+    RunAtomicCode(env.Clone(), node.atomic_code, result)
+    value = result.string
+    env.PushVariable(identifier, value)
+  elif isinstance(node, RangeNode):
+    identifier = node.identifier.value.strip()
+    lower = int(env.EvalExp(node.exp1))
+    upper = int(env.EvalExp(node.exp2))
+    env.PushRange(identifier, lower, upper)
+  elif isinstance(node, ForNode):
+    identifier = node.identifier.value.strip()
+    if node.sep is None:
+      sep = ''
+    else:
+      sep = node.sep.value
+    (lower, upper) = env.GetRange(identifier)
+    for i in range(lower, upper + 1):
+      new_env = env.Clone()
+      new_env.PushVariable(identifier, i)
+      RunCode(new_env, node.code, output)
+      if i != upper:
+        output.Append(sep)
+  elif isinstance(node, RawCodeNode):
+    output.Append(node.raw_code.value)
+  elif isinstance(node, IfNode):
+    cond = env.EvalExp(node.exp)
+    if cond:
+      RunCode(env.Clone(), node.then_branch, output)
+    elif node.else_branch is not None:
+      RunCode(env.Clone(), node.else_branch, output)
+  elif isinstance(node, ExpNode):
+    value = env.EvalExp(node)
+    output.Append('%s' % (value,))
+  elif isinstance(node, LiteralDollarNode):
+    output.Append('$')
+  elif isinstance(node, CodeNode):
+    RunCode(env.Clone(), node, output)
+  else:
+    print 'BAD'
+    print node
+    sys.exit(1)
+
+
+def RunCode(env, code_node, output):
+  for atomic_code in code_node.atomic_code:
+    RunAtomicCode(env, atomic_code, output)
+
+
+def IsSingleLineComment(cur_line):
+  return '//' in cur_line
+
+
+def IsInPreprocessorDirective(prev_lines, cur_line):
+  if cur_line.lstrip().startswith('#'):
+    return True
+  return prev_lines and prev_lines[-1].endswith('\\')
+
+
+def WrapComment(line, output):
+  loc = line.find('//')
+  before_comment = line[:loc].rstrip()
+  if before_comment == '':
+    indent = loc
+  else:
+    output.append(before_comment)
+    indent = len(before_comment) - len(before_comment.lstrip())
+  prefix = indent*' ' + '// '
+  max_len = 80 - len(prefix)
+  comment = line[loc + 2:].strip()
+  segs = [seg for seg in re.split(r'(\w+\W*)', comment) if seg != '']
+  cur_line = ''
+  for seg in segs:
+    if len((cur_line + seg).rstrip()) < max_len:
+      cur_line += seg
+    else:
+      if cur_line.strip() != '':
+        output.append(prefix + cur_line.rstrip())
+      cur_line = seg.lstrip()
+  if cur_line.strip() != '':
+    output.append(prefix + cur_line.strip())
+
+
+def WrapCode(line, line_concat, output):
+  indent = len(line) - len(line.lstrip())
+  prefix = indent*' '  # Prefix of the current line
+  max_len = 80 - indent - len(line_concat)  # Maximum length of the current line
+  new_prefix = prefix + 4*' '  # Prefix of a continuation line
+  new_max_len = max_len - 4  # Maximum length of a continuation line
+  # Prefers to wrap a line after a ',' or ';'.
+  segs = [seg for seg in re.split(r'([^,;]+[,;]?)', line.strip()) if seg != '']
+  cur_line = ''  # The current line without leading spaces.
+  for seg in segs:
+    # If the line is still too long, wrap at a space.
+    while cur_line == '' and len(seg.strip()) > max_len:
+      seg = seg.lstrip()
+      split_at = seg.rfind(' ', 0, max_len)
+      output.append(prefix + seg[:split_at].strip() + line_concat)
+      seg = seg[split_at + 1:]
+      prefix = new_prefix
+      max_len = new_max_len
+
+    if len((cur_line + seg).rstrip()) < max_len:
+      cur_line = (cur_line + seg).lstrip()
+    else:
+      output.append(prefix + cur_line.rstrip() + line_concat)
+      prefix = new_prefix
+      max_len = new_max_len
+      cur_line = seg.lstrip()
+  if cur_line.strip() != '':
+    output.append(prefix + cur_line.strip())
+
+
+def WrapPreprocessorDirective(line, output):
+  WrapCode(line, ' \\', output)
+
+
+def WrapPlainCode(line, output):
+  WrapCode(line, '', output)
+
+
+def IsMultiLineIWYUPragma(line):
+  return re.search(r'/\* IWYU pragma: ', line)
+
+
+def IsHeaderGuardIncludeOrOneLineIWYUPragma(line):
+  return (re.match(r'^#(ifndef|define|endif\s*//)\s*[\w_]+\s*$', line) or
+          re.match(r'^#include\s', line) or
+          # Don't break IWYU pragmas, either; that causes iwyu.py problems.
+          re.search(r'// IWYU pragma: ', line))
+
+
+def WrapLongLine(line, output):
+  line = line.rstrip()
+  if len(line) <= 80:
+    output.append(line)
+  elif IsSingleLineComment(line):
+    if IsHeaderGuardIncludeOrOneLineIWYUPragma(line):
+      # The style guide made an exception to allow long header guard lines,
+      # includes and IWYU pragmas.
+      output.append(line)
+    else:
+      WrapComment(line, output)
+  elif IsInPreprocessorDirective(output, line):
+    if IsHeaderGuardIncludeOrOneLineIWYUPragma(line):
+      # The style guide made an exception to allow long header guard lines,
+      # includes and IWYU pragmas.
+      output.append(line)
+    else:
+      WrapPreprocessorDirective(line, output)
+  elif IsMultiLineIWYUPragma(line):
+    output.append(line)
+  else:
+    WrapPlainCode(line, output)
+
+
+def BeautifyCode(string):
+  lines = string.splitlines()
+  output = []
+  for line in lines:
+    WrapLongLine(line, output)
+  output2 = [line.rstrip() for line in output]
+  return '\n'.join(output2) + '\n'
+
+
+def ConvertFromPumpSource(src_text):
+  """Return the text generated from the given Pump source text."""
+  ast = ParseToAST(StripMetaComments(src_text))
+  output = Output()
+  RunCode(Env(), ast, output)
+  return BeautifyCode(output.string)
+
+
+def main(argv):
+  if len(argv) == 1:
+    print __doc__
+    sys.exit(1)
+
+  file_path = argv[-1]
+  output_str = ConvertFromPumpSource(file(file_path, 'r').read())
+  if file_path.endswith('.pump'):
+    output_file_path = file_path[:-5]
+  else:
+    output_file_path = '-'
+  if output_file_path == '-':
+    print output_str,
+  else:
+    output_file = file(output_file_path, 'w')
+    output_file.write('// This file was GENERATED by command:\n')
+    output_file.write('//     %s %s\n' %
+                      (os.path.basename(__file__), os.path.basename(file_path)))
+    output_file.write('// DO NOT EDIT BY HAND!!!\n\n')
+    output_file.write(output_str)
+    output_file.close()
+
+
+if __name__ == '__main__':
+  main(sys.argv)

+ 0 - 1
vendor/native_mate

@@ -1 +0,0 @@
-Subproject commit 875706f66008e03a0c7a699de16d7e2bde0efb90