Commits

Anonymous committed 2e51864

initial checkin

  • Participants

Comments (0)

Files changed (12)

+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright 2009 Jeremy Latt
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+# erlang
+ERL_ROOT = /usr/local/lib/erlang
+ERL_INC  = $(ERL_ROOT)/usr/include
+# v8
+V8_ROOT  = v8
+V8_INC   = $(V8_ROOT)/include
+# compile
+CPP      = g++
+CFLAGS   = -Iinclude -I$(V8_INC) -I$(ERL_INC) -g -c -Wall
+LFLAGS   = -dynamiclib -flat_namespace -undefined suppress -Lv8 -lv8_g -Wall -fPIC
+CPPSRCS  = $(wildcard src/*.cc)
+CPPOBJS  = $(patsubst %.cc,%.o,$(CPPSRCS))
+
+all: $(CPPOBJS) libv8erl.dylib
+
+%.o: %.cc
+	$(CPP) $(CFLAGS) -o $@ $<
+
+
+%.dylib: $(CPPOBJS)
+	$(CPP) $(LFLAGS) -o $@ $(CPPOBJS)
+
+.PHONY: clean
+
+clean:
+	-rm $(CPPOBJS) libv8erl.dylib

File NOTICE

Empty file added.

File busted/node-test

Binary file added.

File busted/node.cc

+#include <stdlib.h>
+
+#include "erl_interface.h"
+#include "ei.h"
+
+int main(int argc, char *argv[]) {
+  int   id       = atoi(argv[0]);
+  char *cookie   = argv[1];
+  int   creation = atoi(argv[2]);
+  char *node     = argv[3];
+
+  erl_init(NULL, 0);
+  
+  int r = 0;
+
+  if (!erl_connect_init(id, cookie, creation)) { erl_err_quit("erl_connect_init"); }
+    
+  int sock = erl_connect(node);
+  if (sock < 0) { erl_err_quit("erl_connect"); }
+
+  unsigned char buf[1024*16];
+  ErlMessage emsg;
+  while (true) {
+    switch(erl_receive_msg(sock, buf, sizeof(buf), &emsg)) {
+    case ERL_MSG:
+      ETERM *resp = erl_mk_atom("ok");
+      erl_send(sock, emsg.from, resp);
+      erl_free_term(resp);
+      break;
+    case ERL_ERROR:
+      // cleanup
+      break;
+    }
+  }
+
+  return r;
+}

File busted/terms.cc

+#include <string>
+#include <map>
+
+#include "erl_interface.h"
+#include "ei.h"
+
+#include <v8.h>
+
+using namespace std;
+using namespace v8;
+
+// templates
+
+static Persistent<ObjectTemplate> global_template;
+static Persistent<ObjectTemplate> term_template;
+
+// term wrapper
+
+Handle<Object> term_wrap(Handle<ObjectTemplate> temp, ETERM *term) {
+  HandleScope scope;
+
+  Handle<Object> obj = term_template->NewInstance();
+  Handle<External> ext = External::New(term);
+  obj->SetInternalField(0, ext);
+
+  return scope.Close(obj);
+}
+
+ETERM *term_unwrap(Handle<Value> val) {
+  Handle<Object> obj = Handle<Object>::Cast(val);
+  Handle<External> ext = Handle<External>::Cast(obj->GetInternalField(0));
+  void *ptr = ext->Value();
+  return static_cast<ETERM *>(ptr);
+}
+
+// contexts
+
+Persistent<Context> context_new() {
+  Handle<Context> context = ;
+  return ;
+}
+
+ETERM *context_execute(Handle<Context> context, char *scriptstr) {
+  Context::Scope context_scope(context);
+  HandleScope handle_scope;
+  TryCatch try_catch;
+
+  Handle<String> script = String::New(scriptstr);
+  Handle<Script> compiled = Script::Compile(script);
+  if (compiled.IsEmpty()) { 
+    // TODO: throw some erlang exception
+    return NULL; // XXX
+  } else {
+    Handle<Value> result = compiled->Run();
+    if (result.IsEmpty()) {
+      // TODO: throw some erlang exception
+      return NULL; // XXX
+    } else {
+      // TODO: convert JS response to term
+      return NULL; // XXX
+    }
+  }
+}
+
+// API
+
+/*
+static Handle<Array> erl_tuple_to_array(ETERM *tuple) {
+  int size = ERL_TUPLE_SIZE(tuple);
+  Handle<Array> array = Array::New(size);
+  for (int i=0; i<size; i++) {
+    array->Set(Integer::New(i), External::New(ERL_TUPLE_ELEMENT(TERM, i)));
+  }
+  return array;
+}
+
+static Handle<Array> erl_list_to_array(ETERM *list) {
+  Handle<Array> array = Array::New(erl_length(list));
+  int i = 0;
+  while(!ERL_IS_NIL(list)) {
+    array->Set(Integer::New(i), External::New(ERL_CONS_HEAD(list)));
+    list = ERL_CONS_TAIL(list);
+  }
+  return array;
+}
+*/
+
+Handle<Value> v8erl_type(const Arguments& args) {
+  if (args.Length() < 1) { return v8::Undefined(); }
+
+  ETERM *term = term_unwrap(args[0]);
+  if (term == NULL) { return v8::Undefined(); }
+  
+  HandleScope scope;
+  switch (ERL_TYPE(term)) {
+  case ERL_UNDEF:       return scope.Close(String::New("undefined"));
+  case ERL_INTEGER:     return scope.Close(String::New("int"));
+  case ERL_U_INTEGER:   return scope.Close(String::New("uint"));
+  case ERL_ATOM:        return scope.Close(String::New("atom"));
+  case ERL_PID:         return scope.Close(String::New("pid"));
+  case ERL_PORT:        return scope.Close(String::New("port"));
+  case ERL_REF:         return scope.Close(String::New("ref"));
+  case ERL_CONS:        // fall-through
+  case ERL_NIL:         return scope.Close(String::New("list"));
+  case ERL_TUPLE:       return scope.Close(String::New("tuple"));
+  case ERL_BINARY:      return scope.Close(String::New("binary"));
+  case ERL_FLOAT:       return scope.Close(String::New("float"));
+  case ERL_VARIABLE:    return scope.Close(String::New("var"));
+  case ERL_SMALL_BIG:   return scope.Close(String::New("sbigint"));
+  case ERL_U_SMALL_BIG: return scope.Close(String::New("usbigint"));
+  case ERL_FUNCTION:    return scope.Close(String::New("fun"));
+  case ERL_BIG:         return scope.Close(String::New("bigint"));
+  default:              return v8::Undefined(); // should never get here
+  }
+}
+
+
+//
+// MAIN
+//
+
+Persistent<ObjectTemplate> erl_global() {
+  Handle<ObjectTemplate> global = ObjectTemplate::New(); 
+  
+  global->Set(String::New("term_type"),
+              FunctionTemplate::New(v8erl_type));
+ 
+  return Persistent<ObjectTemplate>::New(global);
+}
+
+
+Persistent<ObjectTemplate> erl_term_template() {
+  Handle<ObjectTemplate> temp = ObjectTemplate::New();
+  temp->SetInternalFieldCount(1);
+  return Persistent<ObjectTemplate>::New(temp);
+}
+
+int main(int argc, char *argv[]) {
+  // erlang init
+  erl_init(NULL, 0);
+  
+  // v8 init
+  global_template = erl_global();
+  term_template   = erl_term_template();
+  
+  // main loop
+  
+  return 0;
+}
+
+static void cleanup() {
+  global_template.Dispose();
+  term_template.Dispose();
+}

File busted/test.erl

+-module(test).
+-export([run/0]).
+
+run() ->
+    register(regname(), self()),
+    P = open_port({spawn, command()}, [{packet, 1}]),
+    
+    port_close(P),
+    unregister(test).
+    
+
+regname() -> test.
+
+command() ->
+    io_lib:format("./node-test ~d ~a ~d ~a", [502, erlang:get_cookie(), 1, regname()]).

File include/js2erl.h

+// -*- mode: c++ -*-
+#include <v8.h>
+#include "erl_driver.h"
+
+using namespace std;
+using namespace v8;
+
+extern int terms_length(Handle<Value> val);
+extern int value_to_terms(Handle<Value> val, ErlDrvTermData *terms);

File src/driver.cc

+#include <string>
+#include "js2erl.h"
+
+static Persistent<ObjectTemplate> global_template;
+static Persistent<ObjectTemplate> term_template;
+
+static int init();
+static void finish();
+static ErlDrvData start(ErlDrvPort, char *);
+static void stop(ErlDrvData);
+static void output(ErlDrvData, char *, int);
+static void ready_async(ErlDrvData, ErlDrvThreadData);
+// local
+static void run_script(void *);
+static void async_free(void *);
+
+class V8Data {
+public:
+  ErlDrvPort port;
+  Persistent<Context> context;
+
+  V8Data(ErlDrvPort, Handle<Context>);
+  ~V8Data();
+  ErlDrvData castOut();
+  static V8Data *castIn(ErlDrvData);
+};
+
+V8Data::V8Data(ErlDrvPort p, Handle<Context> c) {
+  port = p;
+  context = Persistent<Context>::New(c);
+};
+
+V8Data::~V8Data() {
+  context.Dispose();
+};
+
+ErlDrvData V8Data::castOut() { return reinterpret_cast<ErlDrvData>(this); };
+
+V8Data *V8Data::castIn(ErlDrvData data) {
+  return reinterpret_cast<V8Data *>(data);
+};
+
+class AsyncData {
+public:
+  // input
+  Handle<Context> context;
+  char *buf;
+  int len;
+  // output
+  ErlDrvTermData *terms;
+  int tlen;
+
+  AsyncData(Handle<Context>, char *, int);
+  void setResult(Handle<Value>);
+  void send(ErlDrvPort);
+  void setError(char *);
+  ~AsyncData();
+  void *castOut();
+  static AsyncData *castIn(void *);
+};
+
+AsyncData::AsyncData(Handle<Context> c, char *b, int l) {
+  context = c;
+  buf     = b;
+  len     = l;
+};
+
+AsyncData::~AsyncData() {
+  driver_free(terms);
+};
+
+void AsyncData::setResult(Handle<Value> result) {
+  tlen  = terms_length(result);
+  terms = (ErlDrvTermData *)driver_alloc(sizeof(ErlDrvTermData) * tlen);
+  value_to_terms(result, terms);
+};
+
+void AsyncData::send(ErlDrvPort port) {
+  driver_output_term(port, terms, tlen);
+};
+
+void AsyncData::setError(char *msg) {
+  tlen = 2;
+  terms = (ErlDrvTermData *)driver_alloc(sizeof(ErlDrvTermData) * tlen);
+  terms[0] = ERL_DRV_ATOM;
+  terms[1] = driver_mk_atom(msg);
+};
+
+void *AsyncData::castOut() { return reinterpret_cast<void *>(this); };
+
+AsyncData *AsyncData::castIn(void *data) {
+  return reinterpret_cast<AsyncData *>(data);
+};
+
+//
+//
+//
+
+ErlDrvEntry driver_entry = {
+  init,    // init driver
+  start,   // open_port
+  stop,    // close_port
+  output,  // output		
+  NULL,			/* ready_input */
+  NULL,			/* ready_output */ 
+  "v8erl", // driver name
+  finish,  // unload dynamic driver
+  NULL, // handle: EMULATOR USE ONLY
+  NULL,			/* control */
+  NULL,			/* timeout */
+  NULL,			/* outputv */
+  ready_async, // async event done
+  NULL,			/* flush */
+  NULL,			/* call */
+  NULL			/* event */
+};
+
+extern "C" { 
+  DRIVER_INIT(v8erl) {
+    return &driver_entry;
+  }
+}
+
+Persistent<ObjectTemplate> erl_global() {
+  Handle<ObjectTemplate> global = ObjectTemplate::New(); 
+  return Persistent<ObjectTemplate>::New(global);
+}
+
+Persistent<ObjectTemplate> erl_term_template() {
+  Handle<ObjectTemplate> temp = ObjectTemplate::New();
+  temp->SetInternalFieldCount(1);
+  return Persistent<ObjectTemplate>::New(temp);
+}
+
+static int init() {
+  global_template = erl_global();
+  term_template   = erl_term_template();
+  return 0;
+}
+
+static void finish() {
+  global_template.Dispose();
+  term_template.Dispose();
+}
+
+static ErlDrvData start(ErlDrvPort port, char *cmd) {
+  if (port == NULL) { return ERL_DRV_ERROR_GENERAL; } // why?
+  else { 
+    Handle<Context> context = Context::New(NULL, global_template);
+    V8Data *data = new V8Data(port, context);
+    return data->castOut(); 
+  }
+}
+
+static void stop(ErlDrvData edata) {
+  delete V8Data::castIn(edata);
+}
+
+
+static void output(ErlDrvData edata, char *buf, int len) {
+  V8Data     *data = V8Data::castIn(edata);
+  AsyncData *adata = new AsyncData(data->context, buf, len);
+  driver_async(data->port, 
+               (unsigned int *)&(data->port), // per-port async
+               run_script, 
+               adata, 
+               async_free);
+}
+
+
+static void ready_async(ErlDrvData edata, ErlDrvThreadData tdata) {
+  V8Data     *data = V8Data::castIn(edata);
+  AsyncData *adata = AsyncData::castIn(tdata);
+  adata->send(data->port);
+  delete adata;
+}
+
+
+static void run_script(void *tdata) {
+  AsyncData *adata = AsyncData::castIn(tdata);
+ 
+  Context::Scope context_scope(adata->context);
+  HandleScope handle_scope;
+  TryCatch try_catch;
+
+  Handle<String> script = String::New(adata->buf, adata->len);
+  Handle<Script> compiled = Script::Compile(script);
+  if (compiled.IsEmpty()) { adata->setError("compiler_error"); } 
+  else                    { adata->setResult(compiled->Run()); }
+}
+
+
+static void async_free(void *tdata) {
+  delete AsyncData::castIn(tdata);
+}

File src/driver.o

Binary file added.

File src/js2erl.cc

+#include "js2erl.h"
+
+// internal
+static int date_to_terms(Handle<Date> val, ErlDrvTermData *terms);
+static int object_to_terms(Handle<Object> obj, ErlDrvTermData *terms);
+static int array_to_terms(Handle<Array> arr, ErlDrvTermData *terms);
+static int number_to_terms(Handle<Number> num, ErlDrvTermData *terms);
+static int string_to_terms(Handle<String> str, ErlDrvTermData *terms);
+
+
+static int atom(const char *a, ErlDrvTermData *terms) {
+  if (terms != NULL) {
+    terms[0] = ERL_DRV_ATOM;
+    terms[1] = driver_mk_atom(const_cast<char *>(a));
+  }
+  return 2;
+}
+
+// public
+
+int terms_length(Handle<Value> val) {
+  return value_to_terms(val, NULL);
+}
+
+
+int value_to_terms(Handle<Value> val, ErlDrvTermData *terms) {
+  HandleScope scope;
+  if (val->IsObject()) {
+    Handle<Object> obj = Handle<Object>::Cast(val);
+    if (val->IsArray()) {
+      return array_to_terms(Handle<Array>::Cast(obj), terms);
+    } else if (val->IsDate()) {
+      return date_to_terms(Handle<Date>::Cast(obj), terms);
+    } else {
+      return object_to_terms(obj, terms);
+    }
+  } else if (val->IsString()) {
+    return string_to_terms(Handle<String>::Cast(val), terms);
+  } else if (val->IsNumber()) {
+    return number_to_terms(Handle<Number>::Cast(val), terms);
+  } else if (val->IsBoolean()) {
+    return atom(val->IsTrue() ? "true" : "false", terms);
+  } else { // functions, etc.
+    return atom("undefined", terms);
+  }
+}
+
+// private
+
+int array_to_terms(Handle<Array> arr, ErlDrvTermData *terms) {
+  int tlen = 0;
+
+  int alen = arr->Length();
+  for (int i=0; i<alen; ++i) {
+    tlen += value_to_terms(arr->Get(Integer::New(i)), terms+tlen);
+  }
+
+  if (terms != NULL) {
+    terms[tlen]   = ERL_DRV_LIST;
+    terms[tlen+1] = alen;
+  }
+  tlen += 2;
+
+  return tlen;
+}
+
+
+int object_to_terms(Handle<Object> obj, ErlDrvTermData *terms) {
+  int tlen = 0;
+
+  tlen += atom("struct", terms+tlen);
+
+  Handle<Array> keys = obj->GetPropertyNames();
+  int olen = keys->Length();
+  for (int i=0; i<olen; ++i) {
+    Handle<Value> key = keys->Get(Integer::New(i));
+    tlen += string_to_terms(Handle<String>::Cast(key), terms+tlen);
+    tlen += value_to_terms(obj->Get(key), terms+tlen);
+    
+    if (terms != NULL) {
+      terms[tlen]   = ERL_DRV_TUPLE;
+      terms[tlen+1] = 2;
+    }
+    tlen += 2;
+  }
+
+  if (terms != NULL) {
+    terms[tlen]   = ERL_DRV_LIST;
+    terms[tlen+1] = olen;
+    terms[tlen+2] = ERL_DRV_TUPLE;
+    terms[tlen+3] = 2;
+  }
+  tlen += 4;
+
+  return tlen;
+}
+
+
+int number_to_terms(Handle<Number> num, ErlDrvTermData *terms) {
+  if (terms != NULL) {
+    if (num->IsInt32()) {
+      terms[0] = ERL_DRV_INT;
+      terms[1] = num->Int32Value();
+    } else {
+      double f = num->Value();
+      terms[0] = ERL_DRV_FLOAT;
+      terms[1] = (ErlDrvTermData)&f;
+    }
+  }
+  return 2;
+}
+
+
+int string_to_terms(Handle<String> str, ErlDrvTermData *terms) {
+  if (terms != NULL) {
+    String::Utf8Value utf8(str);
+    terms[0] = ERL_DRV_BUF2BINARY;
+    terms[1] = (ErlDrvTermData)*utf8;
+    terms[2] = utf8.length();
+  }
+  return 3;
+}
+
+
+int date_to_terms(Handle<Date> date, ErlDrvTermData *terms) {
+  if (terms != NULL) {
+    double f = date->NumberValue();
+    terms[0] = ERL_DRV_FLOAT;
+    terms[1] = (ErlDrvTermData)&f;
+  }
+  return 2;
+}

File src/js2erl.o

Binary file added.