[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