[mapguide-commits] r7624 - in sandbox/jng/node/Oem/SWIGEx: Source/Modules Win32

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Sat Jun 15 04:45:01 PDT 2013


Author: jng
Date: 2013-06-15 04:45:01 -0700 (Sat, 15 Jun 2013)
New Revision: 7624

Modified:
   sandbox/jng/node/Oem/SWIGEx/Source/Modules/nodejs.cxx
   sandbox/jng/node/Oem/SWIGEx/Win32/Swig.exe
Log:
This submission allows the generated NodeJS binding (when compiled) to export the classes and its methods, which can be verified in NodeJS like so.

Given this import statement:
 * var mapguide = require("./MapGuideNodeJsApi.node")

The classes show up as top-level properties of "mapguide"
Class methods show up as top-level properties of its prototype (eg. mapguide.MgFeatureService.prototype)

MgException classes are not exported because there is no real practical method of consuming and handling them from within the node.js environment. We catch thrown MgExceptions at the wrapper method invocation level and rethrow them as the standard JS Error via v8's exception throwing mechanism

We still can't instantiate objects and any method invocations (if it's even currently possible atm) still do nothing as we still have to figure out:

 * How to handle method overload resolution
 * How to handle marshalling parameters in the v8::Arguments to parameters of the underlying MapGuide API method.
 * How to handle return values

Modified: sandbox/jng/node/Oem/SWIGEx/Source/Modules/nodejs.cxx
===================================================================
--- sandbox/jng/node/Oem/SWIGEx/Source/Modules/nodejs.cxx	2013-06-15 07:02:28 UTC (rev 7623)
+++ sandbox/jng/node/Oem/SWIGEx/Source/Modules/nodejs.cxx	2013-06-15 11:45:01 UTC (rev 7624)
@@ -2,6 +2,8 @@
 #include <vector>
 
 #define EXPORTS_VAR "exports"
+#define CLASS_EXPORT_VAR "tpl"
+#define CLASS_PROXY_CTOR_NAME "New"
 
 class Indenter
 {
@@ -23,7 +25,8 @@
     String* m_currentClassName;
     File* m_fOutputFile;
     std::vector<std::string> m_classDecls;
-    std::vector<std::string> m_exportCalls;
+    std::vector<std::string> m_classExportCalls;
+    std::vector<std::string> m_classMemberExportCalls;
     std::string m_currentFragment;
     std::string m_currentExportFragment;
     int m_indentationLevels;
@@ -86,7 +89,11 @@
 
         writeToFile("#include <node.h>\n\n\n");
 
-        writeToFile("//TODO: Need to include MapGuide headers here\n\n\n");
+        writeToFile("//TODO: Should learn how to process SWIG %module directive instead of hard-coding headers\n");
+        writeToFile("#include \"MapGuideCommon.h\"\n");
+        writeToFile("#include \"WebApp.h\"\n");
+        writeToFile("#include \"WebSupport.h\"\n");
+        writeToFile("#include \"HttpHandler.h\"\n\n\n");
 
         Language::top(n);
 
@@ -98,14 +105,15 @@
         }
 
         writeToFile(NewStringf("extern \"C\" void init(v8::Handle<v8::Object> %s) {\n", EXPORTS_VAR));
-
-        for (std::vector<std::string>::iterator it = m_exportCalls.begin(); it != m_exportCalls.end(); it++)
         {
-            std::string call = (*it);
-            writeToFile(call);
-            writeToFile("\n");
+            Indenter ind(m_indentationLevels);
+            for (std::vector<std::string>::iterator it = m_classExportCalls.begin(); it != m_classExportCalls.end(); it++)
+            {
+                std::string call = (*it);
+                writeToFile(call);
+                writeToFile("\n");
+            }
         }
-
         writeToFile("}\n");
         writeToFile(NewStringf("NODE_MODULE(%s, init)\n", modName));
         return SWIG_OK;
@@ -126,19 +134,22 @@
             writeToFile(NewStringf("static v8::Handle<v8::Value> %s(const v8::Arguments& args) {\n", name));
             {
                 Indenter ind(m_indentationLevels);
-                writeToFile("v8::HandleScope scope;\n");
-                writeToFile("return scope.Close();\n");
+                //writeToFile("v8::HandleScope scope;\n");
+                //writeToFile("return scope.Close();\n");
+                writeToFile("return v8::Undefined();\n");
             }
             writeToFile("}\n");
         }
         else if (Strstr(name, ctorPrefix))
         {
-            writeToCurrentClassFragment(NewStringf("//\ctor Function Wrapper: %s\n", name));
-            writeToCurrentClassFragment(NewStringf("static v8::Handle<v8::Value> %s(const v8::Arguments& args) {\n", name));
+            String* ovName = getOverloadedName(n);
+            writeToCurrentClassFragment(NewStringf("//ctor Function Wrapper: %s\n", name));
+            writeToCurrentClassFragment(NewStringf("static v8::Handle<v8::Value> %s(const v8::Arguments& args) {\n", ovName));
             {
                 Indenter ind(m_indentationLevels);
-                writeToCurrentClassFragment("v8::HandleScope scope;\n");
-                writeToCurrentClassFragment("return scope.Close();\n");
+                //writeToCurrentClassFragment("v8::HandleScope scope;\n");
+                //writeToCurrentClassFragment("return scope.Close();\n");
+                writeToCurrentClassFragment("return v8::Undefined();\n");
             }
             writeToCurrentClassFragment("}\n");
         }
@@ -148,8 +159,9 @@
             writeToCurrentClassFragment(NewStringf("static v8::Handle<v8::Value> %s(const v8::Arguments& args) {\n", name));
             {
                 Indenter ind(m_indentationLevels);
-                writeToCurrentClassFragment("v8::HandleScope scope;\n");
-                writeToCurrentClassFragment("return scope.Close();\n");
+                //writeToCurrentClassFragment("v8::HandleScope scope;\n");
+                //writeToCurrentClassFragment("return scope.Close();\n");
+                writeToCurrentClassFragment("return v8::Undefined();\n");
             }
             writeToCurrentClassFragment("}\n");
         }
@@ -219,72 +231,170 @@
         Printf(m_fOutputFile, str);
     }
 
+    static void setProxyClassName(String* clsName, std::string& sOut)
+    {
+        sOut = "Proxy";
+        sOut += Char(clsName);
+    }
+
+    bool isCurrentClassMgObject()
+    {
+        String* clsCmp = NewString("MgObject");
+        bool bRet = (Strcmp(clsCmp, m_currentClassName) == 0);
+        Delete(clsCmp);
+        return bRet;
+    }
+
     virtual int classHandler(Node* n)
     {
+        m_classMemberExportCalls.clear();
         m_currentFragment = std::string();
         m_currentExportFragment = std::string();
-
         m_currentClassName = NewString(Getattr(n,"sym:name"));
 
-        writeToCurrentClassFragment(NewStringf("//Node.js wrapper for class: %s\n", m_currentClassName));
+        //NOTE: We currently don't export MgException classes, they're unusable in JavaScript, any exceptions that
+        //any MapGuide API will throw will be caught by this node.js extension and re-thrown as a JavaScript
+        //Error object.
+        if (!Strstr(m_currentClassName, "Exception"))
+        {
+            writeToCurrentClassFragment(NewStringf("//Node.js wrapper for class: %s\n", m_currentClassName));
 
-        m_currentExportFragment += "//TODO: Write export call for ";
-        m_currentExportFragment += Char(m_currentClassName);
+            std::string proxyClsName;
+            setProxyClassName(m_currentClassName, proxyClsName);
+            std::string clsHead = "class "; 
+            clsHead += proxyClsName;
+            clsHead += " : node::ObjectWrap\n";
+            
+            //Export call
+            m_currentExportFragment += proxyClsName;
+            m_currentExportFragment += "::Export(";
+            m_currentExportFragment += EXPORTS_VAR;
+            m_currentExportFragment += ");";
 
-        std::string proxyClsName = "Proxy";
-        proxyClsName += Char(m_currentClassName);
-        std::string clsHead = "class "; 
-        clsHead += proxyClsName;
-        clsHead += " : node::ObjectWrap\n";
-
-        writeToCurrentClassFragment(clsHead);
-        writeToCurrentClassFragment("{\n");
-        writeToCurrentClassFragment("protected:\n");
-        {
-            Indenter ind(m_indentationLevels);
-            std::string ptrDecl = "Ptr<";
-            ptrDecl += Char(m_currentClassName);
-            ptrDecl += "> m_ptr;\n";
-            writeToCurrentClassFragment(ptrDecl);
-        }
-        writeToCurrentClassFragment("public:\n");
-        std::string ctorDecl;
-        ctorDecl += proxyClsName;
-        ctorDecl += "(";
-        ctorDecl += Char(m_currentClassName);
-        ctorDecl += "* ptr)\n";
-        {
-            Indenter ind(m_indentationLevels);
-            writeToCurrentClassFragment(ctorDecl);
+            //Unmanaged pointer member
+            writeToCurrentClassFragment(clsHead);
             writeToCurrentClassFragment("{\n");
-            writeToCurrentClassFragment("\tm_ptr = SAFE_ADDREF(ptr);\n");
-            writeToCurrentClassFragment("}\n");
-        }
-        std::string dtorDecl;
-        dtorDecl += "~";
-        dtorDecl += proxyClsName;
-        dtorDecl += "()\n";
-        {
-            Indenter ind(m_indentationLevels);
-            writeToCurrentClassFragment(dtorDecl);
-            writeToCurrentClassFragment("{\n");
-            writeToCurrentClassFragment("\tm_ptr = NULL;\n");
-            writeToCurrentClassFragment("}\n");
-        }
+            writeToCurrentClassFragment("protected:\n");
+            
+            bool isMgObject = isCurrentClassMgObject();
 
-        {
-            Indenter ind(m_indentationLevels);
-            Language::classHandler(n);
-        }
+            if (isMgObject)
+            {
+                Indenter ind(m_indentationLevels);
+                std::string ptrDecl;
+                ptrDecl += Char(m_currentClassName);
+                ptrDecl += "* m_ptr;\n";
+                writeToCurrentClassFragment(ptrDecl);
+            }
+            else
+            {
+                Indenter ind(m_indentationLevels);
+                std::string ptrDecl = "Ptr<";
+                ptrDecl += Char(m_currentClassName);
+                ptrDecl += "> m_ptr;\n";
+                writeToCurrentClassFragment(ptrDecl);
+            }
+            writeToCurrentClassFragment("public:\n");
+            std::string ctorDecl;
+            ctorDecl += proxyClsName;
+            ctorDecl += "(";
+            ctorDecl += Char(m_currentClassName);
+            ctorDecl += "* ptr)\n";
+            //ctor
+            {
+                Indenter ind(m_indentationLevels);
+                writeToCurrentClassFragment(ctorDecl);
+                writeToCurrentClassFragment("{\n");
+                if (isMgObject) //Anything inheriting from MgObject will be MgDisposable
+                    writeToCurrentClassFragment("\tm_ptr = SAFE_ADDREF((MgDisposable*)ptr);\n");
+                else
+                    writeToCurrentClassFragment("\tm_ptr = SAFE_ADDREF(ptr);\n");
+                writeToCurrentClassFragment("}\n");
+            }
+            std::string dtorDecl;
+            dtorDecl += "~";
+            dtorDecl += proxyClsName;
+            dtorDecl += "()\n";
+            //dtor
+            {
+                Indenter ind(m_indentationLevels);
+                writeToCurrentClassFragment(dtorDecl);
+                writeToCurrentClassFragment("{\n");
+                if (isMgObject) //Anything inheriting from MgObject will be MgDisposable 
+                    writeToCurrentClassFragment("\t((MgDisposable*)m_ptr)->Release();\n");
+                else
+                    writeToCurrentClassFragment("\tm_ptr = NULL;\n");
+                writeToCurrentClassFragment("}\n");
+            }
 
-        writeToCurrentClassFragment("};");
+            //Class body
+            {
+                Indenter ind(m_indentationLevels);
+                Language::classHandler(n);
+            }
 
-        Delete(m_currentClassName);
-        m_currentClassName = NULL;
+            //Internal pointer accessor
+            {
+                Indenter ind(m_indentationLevels);
+                if (isMgObject)
+                    writeToCurrentClassFragment(NewStringf("%s* GetInternalPointer() { return SAFE_ADDREF((MgDisposable*)m_ptr); }\n", m_currentClassName));
+                else
+                    writeToCurrentClassFragment(NewStringf("%s* GetInternalPointer() { return SAFE_ADDREF(m_ptr.p); }\n", m_currentClassName));
+            }
 
-        m_classDecls.push_back(m_currentFragment);
-        m_exportCalls.push_back(m_currentExportFragment);
+            //Proxy Constructor
+            {
+                Indenter ind(m_indentationLevels);
+                writeToCurrentClassFragment(NewStringf("static v8::Handle<v8::Value> %s(const v8::Arguments& args) {\n", CLASS_PROXY_CTOR_NAME));
+                {
+                    Indenter ind2(m_indentationLevels);
+                    writeToCurrentClassFragment("//TODO: Parse arguments and determine which actual native constructor to invoke\n");
+                    writeToCurrentClassFragment("return v8::Undefined();\n");
+                }
+                writeToCurrentClassFragment("}\n");
+            }
 
+            //node/v8 export function
+            {
+                Indenter ind(m_indentationLevels);
+                writeToCurrentClassFragment(NewStringf("static void Export(v8::Handle<v8::Object> %s)\n", EXPORTS_VAR));
+                writeToCurrentClassFragment("{\n");
+                {
+                    Indenter ind2(m_indentationLevels);
+                    writeToCurrentClassFragment(NewStringf("v8::Local<v8::FunctionTemplate> %s = v8::FunctionTemplate::New(%s::%s);\n", CLASS_EXPORT_VAR, proxyClsName.c_str(), CLASS_PROXY_CTOR_NAME));
+                    writeToCurrentClassFragment(NewStringf("%s->SetClassName(v8::String::NewSymbol(\"%s\"));\n", CLASS_EXPORT_VAR, m_currentClassName));
+
+                    std::string ctorReg = "v8::Persistent<v8::Function> constructor = v8::Persistent<v8::Function>::New(";
+                    ctorReg += CLASS_EXPORT_VAR;
+                    ctorReg += "->GetFunction());\n";
+
+                    std::string ctorReg2;
+                    ctorReg2 += EXPORTS_VAR;
+                    ctorReg2 += "->Set(v8::String::NewSymbol(\"";
+                    ctorReg2 += Char(m_currentClassName);
+                    ctorReg2 += "\"), constructor);\n";
+
+                    m_classMemberExportCalls.push_back(ctorReg);
+                    m_classMemberExportCalls.push_back(ctorReg2);
+
+                    for (std::vector<std::string>::iterator it = m_classMemberExportCalls.begin(); it != m_classMemberExportCalls.end(); it++)
+                    {
+                        writeToCurrentClassFragment((*it));
+                        writeToCurrentClassFragment("\n");
+                    }
+                }
+                writeToCurrentClassFragment("}\n");
+            }
+
+            writeToCurrentClassFragment("};");
+
+            Delete(m_currentClassName);
+            m_currentClassName = NULL;
+
+            m_classDecls.push_back(m_currentFragment);
+            m_classExportCalls.push_back(m_currentExportFragment);
+
+        }
         return SWIG_OK;
     }
 
@@ -292,23 +402,76 @@
     {
         String* name = Getattr(n, "sym:name");
         writeToCurrentClassFragment(NewStringf("//\tMember Constant: %s::%s\n", m_currentClassName, name));
+        String* swExpCall = NewStringf("//TODO: Export constant %s::%s", m_currentClassName, name);
+        std::string expCall = Char(swExpCall);
+        Delete(swExpCall);
+        m_classMemberExportCalls.push_back(expCall);
         return SWIG_OK;
     }
 
+    void emitNativeClassMethodCall(Node* n)
+    {
+        //proxy - The wrapped proxy object pointer
+        //wrappedPtr - The native MapGuide object pointer
+        writeToCurrentClassFragment("//TODO: Do your thing\n");
+    }
+
     virtual int memberfunctionHandler(Node* n)
     {
         String* name = Getattr(n, "sym:name");
         String* overloaded_name = Copy(getOverloadedName(n));
         String* overloaded_name_qualified = Swig_name_member(m_currentClassName, overloaded_name);
 
+        std::string proxyClsName;
+        setProxyClassName(m_currentClassName, proxyClsName);
+        
         writeToCurrentClassFragment(NewStringf("//\tMember Function: %s::%s\n", m_currentClassName, overloaded_name));
         writeToCurrentClassFragment(NewStringf("static v8::Handle<v8::Value> %s(const v8::Arguments& args) {\n", overloaded_name_qualified));
         {
             Indenter ind(m_indentationLevels);
-            writeToCurrentClassFragment("v8::HandleScope scope;\n");
-            writeToCurrentClassFragment("return scope.Close();\n");
+            if (isCurrentClassMgObject())
+                writeToCurrentClassFragment(NewStringf("%s* wrappedPtr = NULL;\n", m_currentClassName));
+            else
+                writeToCurrentClassFragment(NewStringf("Ptr<%s> wrappedPtr;\n", m_currentClassName));
+            writeToCurrentClassFragment("MG_TRY()\n");
+            writeToCurrentClassFragment(NewStringf("%s* proxy = ObjectWrap::Unwrap<%s>(args.This());\n", proxyClsName.c_str(), proxyClsName.c_str()));
+            writeToCurrentClassFragment("wrappedPtr = proxy->GetInternalPointer();\n");
+            emitNativeClassMethodCall(n);
+            writeToCurrentClassFragment(NewStringf("MG_CATCH(L\"%s::%s\")\n", proxyClsName.c_str(), overloaded_name_qualified));
+            writeToCurrentClassFragment("if (mgException != NULL) {\n");
+            {
+                Indenter ind2(m_indentationLevels);
+                writeToCurrentClassFragment("//NOTE: Unlike previous iterations of the MapGuide API, MgException::GetDetails() finally gives us *everything*\n");
+                writeToCurrentClassFragment("STRING details = mgException->GetDetails();\n");
+                writeToCurrentClassFragment("std::string mbDetails = MgUtil::WideCharToMultiByte(details);\n");
+                writeToCurrentClassFragment("v8::Local<v8::Value> v8ex = v8::Exception::Error(v8::String::New(mbDetails.c_str()));\n");
+                writeToCurrentClassFragment("//Release our MgException before throwing the v8 one\n");
+                writeToCurrentClassFragment("mgException = NULL;\n");
+                if (isCurrentClassMgObject())
+                    writeToCurrentClassFragment("if (wrappedPtr) { ((MgDisposable*)wrappedPtr)->Release(); wrappedPtr = NULL; }\n");
+                writeToCurrentClassFragment("return v8::ThrowException(v8ex);\n");
+            }
+            writeToCurrentClassFragment("}\n");
+            if (isCurrentClassMgObject())
+                writeToCurrentClassFragment("if (wrappedPtr) { ((MgDisposable*)wrappedPtr)->Release(); wrappedPtr = NULL; }\n");
+            //writeToCurrentClassFragment("v8::HandleScope scope;\n");
+            //writeToCurrentClassFragment("return scope.Close();\n");
+            writeToCurrentClassFragment("return v8::Undefined();\n");
         }
         writeToCurrentClassFragment("}\n");
+
+        String* regCall = NewStringf(
+            "%s->PrototypeTemplate()->Set(v8::String::NewSymbol(\"%s\"), v8::FunctionTemplate::New(%s::%s)->GetFunction());\n",
+            CLASS_EXPORT_VAR,
+            overloaded_name,
+            proxyClsName.c_str(),
+            overloaded_name_qualified);
+        std::string sRegCall;
+        sRegCall += Char(regCall);
+
+        m_classMemberExportCalls.push_back(sRegCall);
+        
+        Delete(regCall);
         Delete(overloaded_name);
         return SWIG_OK;
     }
@@ -317,6 +480,12 @@
     {
         String* name = Getattr(n, "sym:name");
         writeToCurrentClassFragment(NewStringf("//\tMember Variable: %s::%s\n", m_currentClassName, name));
+        
+        String* swExpCall = NewStringf("//TODO: Export member variable %s::%s", m_currentClassName, name);
+        std::string expCall = Char(swExpCall);
+        Delete(swExpCall);
+        m_classMemberExportCalls.push_back(expCall);
+
         return SWIG_OK;
     }
 

Modified: sandbox/jng/node/Oem/SWIGEx/Win32/Swig.exe
===================================================================
(Binary files differ)



More information about the mapguide-commits mailing list