[mapguide-commits] r7638 - sandbox/jng/node/Oem/SWIGEx/Source/Modules

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Sat Jun 22 10:40:12 PDT 2013


Author: jng
Date: 2013-06-22 10:40:12 -0700 (Sat, 22 Jun 2013)
New Revision: 7638

Modified:
   sandbox/jng/node/Oem/SWIGEx/Source/Modules/nodejs.cxx
Log:
This submission implements method overload resolution. The SWIG-decorated overloaded methods are no longer exported. Instead we export the undecorated method which checks the number of arguments and approximate type of each argument to determine which SWIG-decorated overloaded method to forward the call to. 

Modified: sandbox/jng/node/Oem/SWIGEx/Source/Modules/nodejs.cxx
===================================================================
--- sandbox/jng/node/Oem/SWIGEx/Source/Modules/nodejs.cxx	2013-06-21 16:26:01 UTC (rev 7637)
+++ sandbox/jng/node/Oem/SWIGEx/Source/Modules/nodejs.cxx	2013-06-22 17:40:12 UTC (rev 7638)
@@ -1,6 +1,7 @@
 #include "swigmod.h"
 #include <vector>
 #include <map>
+#include <set>
 #include <sstream>
 
 #define EXPORTS_VAR "exports"
@@ -156,6 +157,10 @@
 };
 
 typedef std::map<std::string, std::string> StringMap;
+typedef std::vector<std::string> StringList;
+typedef std::set<std::string> StringSet;
+typedef std::map<std::string, StringList> StringListMap;
+typedef std::map<std::string, StringSet> StringSetMap;
 
 class NODEJS : public Language
 {
@@ -163,14 +168,15 @@
     String* m_namespace;
     String* m_currentClassName;
     File* m_fOutputFile;
-    std::vector<std::string> m_classFwdDecls;
     StringMap m_classDecls;
-    std::vector<std::string> m_classMethodDecls;
-    std::vector<std::string> m_classExportCalls;
-    std::vector<std::string> m_classInheritCalls;
-    std::vector<std::string> m_classMemberExportCalls;
-    std::vector<std::string> m_classSetupCalls;
+    StringList m_classMethodDecls;
+    StringList m_classExportCalls;
+    StringList m_classInheritCalls;
+    StringList m_classMemberExportCalls;
+    StringList m_classSetupCalls;
     StringMap m_ctorSetupCode;
+    StringSetMap m_classMethodOverloads;
+    StringMap m_classMethodOverloadResolution;
     std::string m_currentFragment;
     std::string m_currentExportFragment;
     std::string m_currentInheritFragment;
@@ -325,7 +331,7 @@
         writeToFile("//=====================================\n");
         writeToFile("//Proxy class method definitions\n");
         writeToFile("//=====================================\n");
-        for (std::vector<std::string>::iterator it = m_classMethodDecls.begin(); it != m_classMethodDecls.end(); it++)
+        for (StringList::iterator it = m_classMethodDecls.begin(); it != m_classMethodDecls.end(); it++)
         {
             std::string call = (*it);
             writeToFile(call);
@@ -333,6 +339,36 @@
         }
 
         writeToFile("//=====================================\n");
+        writeToFile("//Proxy class method overloaded methods\n");
+        writeToFile("//=====================================\n");
+        for (StringSetMap::iterator it = m_classMethodOverloads.begin(); it != m_classMethodOverloads.end(); it++)
+        {
+            std::string clsName = it->first;
+            StringSet lst = it->second;
+            for (StringSet::iterator it2 = lst.begin(); it2 != lst.end(); it2++)
+            {
+                std::string ovMethodName = (*it2);
+                writeToFile(NewStringf("//Overloaded method %s::%s\n", clsName.c_str(), ovMethodName.c_str()));
+                writeToFile(NewStringf("static v8::Handle<v8::Value> %s(const v8::Arguments& %s)\n", ovMethodName.c_str(), ARGS_VAR));
+                writeToFile("{\n");
+                {
+                    Indenter ind(m_indentationLevels);
+                    StringMap::iterator it3 = m_classMethodOverloadResolution.find(ovMethodName);
+                    if (it3 != m_classMethodOverloadResolution.end())
+                    {
+                        writeToFile(it3->second);
+                        writeToFile("return v8::ThrowException(v8::Exception::Error(v8::String::New(\"Could not resolve appropriate overloaded method based on the arguments given\")));\n");
+                    }
+                    else
+                    {
+                        writeToFile("//FIXME: This is probably a bug. An registered overloaded method should have matching resolution code\n");
+                    }
+                }
+                writeToFile("}\n");
+            }
+        }
+
+        writeToFile("//=====================================\n");
         writeToFile("//Proxy class constructor definitions\n");
         writeToFile("//=====================================\n");
         for (StringMap::iterator it = m_classDecls.begin(); it != m_classDecls.end(); it++)
@@ -407,7 +443,7 @@
         writeToFile("//=====================================\n");
         writeToFile("//Proxy class setup methods\n");
         writeToFile("//=====================================\n");
-        for (std::vector<std::string>::iterator it = m_classSetupCalls.begin(); it != m_classSetupCalls.end(); it++)
+        for (StringList::iterator it = m_classSetupCalls.begin(); it != m_classSetupCalls.end(); it++)
         {
             std::string call = (*it);
             writeToFile(call);
@@ -417,14 +453,14 @@
         writeToFile(NewStringf("extern \"C\" void init(v8::Handle<v8::Object> %s) {\n", EXPORTS_VAR));
         {
             Indenter ind(m_indentationLevels);
-            for (std::vector<std::string>::iterator it = m_classExportCalls.begin(); it != m_classExportCalls.end(); it++)
+            for (StringList::iterator it = m_classExportCalls.begin(); it != m_classExportCalls.end(); it++)
             {
                 std::string call = (*it);
                 writeToFile(call);
                 writeToFile("\n");
             }
 
-            for (std::vector<std::string>::iterator it = m_classInheritCalls.begin(); it != m_classInheritCalls.end(); it++)
+            for (StringList::iterator it = m_classInheritCalls.begin(); it != m_classInheritCalls.end(); it++)
             {
                 std::string call = (*it);
                 writeToFile(call);
@@ -650,11 +686,6 @@
             std::string proxyClsName;
             setProxyClassName(m_currentClassName, proxyClsName);
             
-            std::string fwdDecl = "class ";
-            fwdDecl += proxyClsName;
-            fwdDecl += ";";
-            m_classFwdDecls.push_back(fwdDecl);
-
             std::string clsHead = "class "; 
             clsHead += proxyClsName;
             clsHead += " : node::ObjectWrap\n";
@@ -665,13 +696,6 @@
             m_currentExportFragment += EXPORTS_VAR;
             m_currentExportFragment += ");";
 
-            /*
-            m_currentInheritFragment += proxyClsName;
-            m_currentInheritFragment += "::ApplyInheritanceChain(";
-            m_currentInheritFragment += EXPORTS_VAR;
-            m_currentInheritFragment += ");";
-            */
-
             //Unmanaged pointer member
             cls.writeToFragment(clsHead);
             cls.writeToFragment("{\n");
@@ -724,10 +748,8 @@
             //Stubs to be implemented further down
             {
                 Indenter ind(m_indentationLevels);
-                //cls.writeToFragment("static v8::Handle<v8::Value> NewInstance(const v8::Arguments& args);\n");
                 cls.writeToFragment("static v8::Handle<v8::Value> CreateJsProxy(MgObject* ptr);\n"); 
                 cls.writeToFragment("static void Export(v8::Handle<v8::Object> exports);\n");
-                //cls.writeToFragment("static void ApplyInheritanceChain(v8::Handle<v8::Object> exports);\n");
             }
 
             //Class body
@@ -767,31 +789,6 @@
                 cls.writeToFragment(NewStringf("static v8::Persistent<v8::Function> constructor;\n"));
             }
 
-            /*
-            //node/v8 public factory
-            {
-                Indenter ind(m_indentationLevels);
-                clsSetup.writeToFragment(NewStringf("v8::Handle<v8::Value> %s::NewInstance(const v8::Arguments& %s)\n", proxyClsName.c_str(), ARGS_VAR));
-                clsSetup.writeToFragment("{\n");
-                {
-                    Indenter ind2(m_indentationLevels);
-                    clsSetup.writeToFragment("v8::HandleScope scope;\n");
-                    clsSetup.writeToFragment(NewStringf("const unsigned argc = %s.Length();\n", ARGS_VAR));
-                    clsSetup.writeToFragment("v8::Handle<v8::Value>* argv = new v8::Handle<v8::Value>[argc];\n");
-                    clsSetup.writeToFragment("for (unsigned i = 0; i < argc; i++) {\n");
-                    {
-                        Indenter ind3(m_indentationLevels);
-                        clsSetup.writeToFragment("argv[i] = args[i];\n");
-                    }
-                    clsSetup.writeToFragment("}\n");
-                    clsSetup.writeToFragment("v8::Local<v8::Object> instance = constructor->NewInstance(argc, argv);\n");
-                    clsSetup.writeToFragment("delete [] argv;\n");
-                    clsSetup.writeToFragment("return scope.Close(instance);\n");
-                }
-                clsSetup.writeToFragment("}\n");
-            }
-            */
-
             //node/v8 wrap mg pointer factory method
             {
                 Indenter ind(m_indentationLevels);
@@ -800,15 +797,10 @@
                 {
                     Indenter ind2(m_indentationLevels);
                     clsSetup.writeToFragment("v8::HandleScope scope;\n");
-                    //clsSetup.writeToFragment("v8::Handle<v8::Value> argv[1] = { v8::Undefined() };\n");
-                    //clsSetup.writeToFragment("v8::Local<v8::Object> instance = constructor->NewInstance();\n");
                     clsSetup.writeToFragment(NewStringf("%s* proxyVal = new %s((%s*)ptr);\n", proxyClsName.c_str(), proxyClsName.c_str(), m_currentClassName));
                     clsSetup.writeToFragment("//Invoke the \"wrap\" constructor\n");
                     clsSetup.writeToFragment("v8::Handle<v8::Value> argv[1] = { v8::External::New(proxyVal) };\n");
                     clsSetup.writeToFragment("v8::Local<v8::Object> instance = constructor->NewInstance(1, argv);\n");
-                    //clsSetup.writeToFragment("//Bug? Or are we doing something wrong? Internal field count is 0 and blows up the next line\n");
-                    //clsSetup.writeToFragment("proxyVal->Wrap(instance);\n");
-                    //clsSetup.writeToFragment("instance->SetInternalField(0, v8::External::New(proxyVal));\n");
                     clsSetup.writeToFragment("return scope.Close(instance);\n");
                 }
                 clsSetup.writeToFragment("}\n");
@@ -855,7 +847,7 @@
                     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++)
+                    for (StringList::iterator it = m_classMemberExportCalls.begin(); it != m_classMemberExportCalls.end(); it++)
                     {
                         clsSetup.writeToFragment((*it));
                         clsSetup.writeToFragment("\n");
@@ -864,29 +856,6 @@
                 clsSetup.writeToFragment("}\n");
             }
 
-            /*
-            //node/v8 export function
-            {
-                Indenter ind(m_indentationLevels);
-                clsSetup.writeToFragment(NewStringf("void %s::ApplyInheritanceChain(v8::Handle<v8::Object> %s)\n", proxyClsName.c_str(), EXPORTS_VAR));
-                clsSetup.writeToFragment("{\n");
-                {
-                    Indenter ind2(m_indentationLevels);
-                    
-                    if (Strcmp("", baseClassName) == 0)
-                    {
-                        clsSetup.writeToFragment("//This class has no base class. Nothing to do here\n");
-                    }
-                    else
-                    {
-                        std::string mbBaseClass;
-                        setProxyClassName(baseClassName, mbBaseClass);
-                        clsSetup.writeToFragment(NewStringf("%s::constructor_tpl->Inherit(%s::constructor_tpl);\n", proxyClsName.c_str(), mbBaseClass.c_str()));
-                    }
-                }
-                clsSetup.writeToFragment("}\n");
-            }
-            */
             cls.writeToFragment("};");
 
             Delete(m_currentClassName);
@@ -894,7 +863,6 @@
 
             m_classDecls[clsName] = m_currentFragment;
             m_classExportCalls.push_back(m_currentExportFragment);
-            //m_classInheritCalls.push_back(m_currentInheritFragment);
             m_classSetupCalls.push_back(m_currentClassSetupFragment);
 
         }
@@ -934,6 +902,20 @@
         FragmentWriter meth(m_indentationLevels, m_currentMethodFragment);
         //Proxy method is encoded as ClassName_SwigQualifiedMethodName
 
+        std::string mbName;
+        std::string mbOvName;
+        mbName += Char(name);
+        mbOvName += Char(overloaded_name);
+
+        std::string clsName;
+        clsName += Char(m_currentClassName);
+
+        String* name_qualified = Swig_name_member(m_currentClassName, name);
+        std::string ovMethodName;
+        ovMethodName += Char(name_qualified);
+
+        FunctionCallSetup setup;
+
         meth.writeToFragment(NewStringf("//\tMember Function: %s::%s\n", m_currentClassName, overloaded_name));
         meth.writeToFragment(NewStringf("static v8::Handle<v8::Value> %s(const v8::Arguments& %s) {\n", overloaded_name_qualified, ARGS_VAR));
         {
@@ -978,8 +960,7 @@
                 {
                     Indenter ind2(m_indentationLevels);
                     if (parms)
-                    {
-                        FunctionCallSetup setup;
+                    {   
                         std::string mbQName;
                         mbQName += Char(overloaded_name_qualified);
                         getFunctionArgumentAssignmentCode(parms, mbQName, meth, &setup);
@@ -1007,9 +988,7 @@
             }
             if (isCurrentClassMgObject())
                 meth.writeToFragment(NewStringf("if (%s) { ((MgDisposable*)%s)->Release(); %s = NULL; }\n", WRAPPED_PTR_VAR, WRAPPED_PTR_VAR, WRAPPED_PTR_VAR));
-            //meth.writeToFragment("v8::HandleScope scope;\n");
-            //meth.writeToFragment("return scope.Close();\n");
-
+            
             meth.writeToFragment("\n");
             meth.writeToFragment("//Return value to javascript\n");
             if (isVoid)
@@ -1045,22 +1024,224 @@
         }
         meth.writeToFragment("}\n");
 
-        String* regCall = NewStringf(
-            "%s->PrototypeTemplate()->Set(v8::String::NewSymbol(\"%s\"), v8::FunctionTemplate::New(%s)->GetFunction());\n",
-            CLASS_EXPORT_VAR,
-            overloaded_name,
-            overloaded_name_qualified);
-        std::string sRegCall;
-        sRegCall += Char(regCall);
+        //Check if this is an overload
+        bool bIsOverload = (Strcmp(name, overloaded_name) != 0);
+        if (bIsOverload)
+        {
+            const std::vector<ArgInfo>& args = setup.getArgs();
 
-        m_classMemberExportCalls.push_back(sRegCall);
+            std::string overloadResFrag;
+            FragmentWriter ovRes(m_indentationLevels, overloadResFrag);
+            
+            ovRes.writeToFragment(NewStringf("//Checking args suitability for method: %s\n", overloaded_name_qualified));
+            ovRes.writeToFragment(NewStringf("if (%s.Length() == %d)\n", ARGS_VAR, args.size()));
+            ovRes.writeToFragment("{\n");
+            {
+                Indenter ind2(m_indentationLevels);
+                std::string condition;
+                writeArgumentsMatchCondition(args, condition);
+                if (!condition.empty())
+                {
+                    //We need to add an argument check before invocation
+                    ovRes.writeToFragment(NewStringf("if (%s)\n", condition.c_str()));
+                    ovRes.writeToFragment("{\n");
+                    {
+                        Indenter ind3(m_indentationLevels);
+                        ovRes.writeToFragment("//Forward method call\n");
+                        if (isVoid)
+                        {
+                            ovRes.writeToFragment(NewStringf("%s(args);\n", overloaded_name_qualified));
+                            ovRes.writeToFragment("return v8::Undefined();\n");
+                        }
+                        else
+                        {
+                            ovRes.writeToFragment(NewStringf("return %s(args);\n", overloaded_name_qualified));
+                        }
+                    }
+                    ovRes.writeToFragment("}\n");
+                }
+                else
+                {
+                    ovRes.writeToFragment("//Forward method call\n");
+                    if (isVoid)
+                    {
+                        ovRes.writeToFragment(NewStringf("%s(args);\n", overloaded_name_qualified));
+                        ovRes.writeToFragment("return v8::Undefined();\n");
+                    }
+                    else
+                    {
+                        ovRes.writeToFragment(NewStringf("return %s(args);\n", overloaded_name_qualified));
+                    }
+                }
+            }
+            ovRes.writeToFragment("}\n\n");
+
+            //Append to method resolution code
+            if (m_classMethodOverloadResolution.find(ovMethodName) == m_classMethodOverloadResolution.end())
+            {
+                m_classMethodOverloadResolution[ovMethodName] = overloadResFrag;
+            }
+            else
+            {
+                std::string& frag = m_classMethodOverloadResolution[ovMethodName];
+                frag += overloadResFrag;
+            }
+        }
+
+        if (bIsOverload)
+        {
+            //Have we registered this as a method with multiple overloads?
+            if (m_classMethodOverloads.find(clsName) == m_classMethodOverloads.end())
+            {
+                m_classMethodOverloads[clsName] = StringSet();
+            }
+            if (m_classMethodOverloads[clsName].find(ovMethodName) == m_classMethodOverloads[clsName].end())
+            {
+                String* regCall = NewStringf(
+                    "%s->PrototypeTemplate()->Set(v8::String::NewSymbol(\"%s\"), v8::FunctionTemplate::New(%s)->GetFunction());",
+                    CLASS_EXPORT_VAR,
+                    name,
+                    name_qualified);
+                std::string sRegCall;
+                sRegCall += Char(regCall);
+                m_classMemberExportCalls.push_back(sRegCall);
+                Delete(regCall);
+
+                m_classMethodOverloads[clsName].insert(ovMethodName);
+            }
+        }
+        else
+        {
+            String* regCall = NewStringf(
+                "%s->PrototypeTemplate()->Set(v8::String::NewSymbol(\"%s\"), v8::FunctionTemplate::New(%s)->GetFunction());",
+                CLASS_EXPORT_VAR,
+                overloaded_name,
+                overloaded_name_qualified);
+            std::string sRegCall;
+            sRegCall += Char(regCall);
+            m_classMemberExportCalls.push_back(sRegCall);
+            Delete(regCall);
+        }
         m_classMethodDecls.push_back(m_currentMethodFragment);
         
-        Delete(regCall);
         Delete(overloaded_name);
         return SWIG_OK;
     }
 
+    void writeArgumentsMatchCondition(const std::vector<ArgInfo>& args, std::string& condition)
+    {
+        for (std::vector<ArgInfo>::const_iterator it = args.begin(); it != args.end(); it++)
+        {
+            if (it->isMgPointer)
+            {
+                if (condition.empty())
+                {
+                    String* str = NewStringf("%s[%d]->IsObject()", ARGS_VAR, it->offset);
+                    condition += Char(str);
+                    Delete(str);
+                }
+                else
+                {
+                    String* str = NewStringf(" && %s[%d]->IsObject()", ARGS_VAR, it->offset);
+                    condition += Char(str);
+                    Delete(str);
+                }
+            }
+            else
+            {
+                const char* type = it->type.c_str();
+                if (Strcmp(type, "BYTE") == 0 ||
+                    Strcmp(type, "INT8") == 0 ||
+                    Strcmp(type, "INT16") == 0 ||
+                    Strcmp(type, "INT32") == 0 ||
+                    Strcmp(type, "STATUS") == 0 ||                    //Huh?
+                    Strcmp(type, "MgSiteInfo::MgSiteStatus") == 0 ||  //Huh? I thought MapGuide API doesn't expose enums!
+                    Strcmp(type, "MgSiteInfo::MgPortType") == 0 ||    //Huh? I thought MapGuide API doesn't expose enums!
+                    Strcmp(type, "int") == 0 ||
+                    Strcmp(type, "UINT32") == 0 ||
+                    Strcmp(type, "INT64") == 0 ||
+                    Strcmp(type, "long") == 0 ||
+                    Strcmp(type, "long long") == 0)
+                {
+                    if (condition.empty())
+                    {
+                        String* str = NewStringf("%s[%d]->IsInt32()", ARGS_VAR, it->offset);
+                        condition += Char(str);
+                        Delete(str);
+                    }
+                    else
+                    {
+                        String* str = NewStringf(" && %s[%d]->IsInt32()", ARGS_VAR, it->offset);
+                        condition += Char(str);
+                        Delete(str);
+                    }
+                }
+                else if (Strcmp(type, "double") == 0 ||
+                         Strcmp(type, "float") == 0)
+                {
+                    if (condition.empty())
+                    {
+                        String* str = NewStringf("%s[%d]->IsNumber()", ARGS_VAR, it->offset);
+                        condition += Char(str);
+                        Delete(str);
+                    }
+                    else
+                    {
+                        String* str = NewStringf(" && %s[%d]->IsNumber()", ARGS_VAR, it->offset);
+                        condition += Char(str);
+                        Delete(str);
+                    }
+                }
+                else if (Strcmp(type, "BYTE_ARRAY_IN") == 0 ||
+                         Strcmp(type, "BYTE_ARRAY_OUT") == 0)
+                {
+                    if (condition.empty())
+                    {
+                        String* str = NewStringf("node::Buffer::HasInstance(%s[%d])", ARGS_VAR, it->offset);
+                        condition += Char(str);
+                        Delete(str);
+                    }
+                    else
+                    {
+                        String* str = NewStringf(" && node::Buffer::HasInstance(%s[%d])", ARGS_VAR, it->offset);
+                        condition += Char(str);
+                        Delete(str);
+                    }
+                }
+                else if (Strcmp(type, "STRINGPARAM") == 0)
+                {
+                    if (condition.empty())
+                    {
+                        String* str = NewStringf("%s[%d]->IsString()", ARGS_VAR, it->offset);
+                        condition += Char(str);
+                        Delete(str);
+                    }
+                    else
+                    {
+                        String* str = NewStringf(" && %s[%d]->IsString()", ARGS_VAR, it->offset);
+                        condition += Char(str);
+                        Delete(str);
+                    }
+                }
+                else if (Strcmp(type, "bool") == 0)
+                {
+                    if (condition.empty())
+                    {
+                        String* str = NewStringf("%s[%d]->IsBoolean()", ARGS_VAR, it->offset);
+                        condition += Char(str);
+                        Delete(str);
+                    }
+                    else
+                    {
+                        String* str = NewStringf(" && %s[%d]->IsBoolean()", ARGS_VAR, it->offset);
+                        condition += Char(str);
+                        Delete(str);
+                    }
+                }
+            }
+        }
+    }
+
     void writeArgumentCheckFragment(FragmentWriter& frag, std::string& callingMethodName, String* name, SwigType* type, int argNo, bool isArgMgPointer, bool bThrowV8Exceptions = true)
     {
         if (isArgMgPointer)



More information about the mapguide-commits mailing list