[mapguide-commits] r7635 - sandbox/jng/node/Oem/SWIGEx/Source/Modules
svn_mapguide at osgeo.org
svn_mapguide at osgeo.org
Thu Jun 20 08:00:57 PDT 2013
Author: jng
Date: 2013-06-20 08:00:57 -0700 (Thu, 20 Jun 2013)
New Revision: 7635
Modified:
sandbox/jng/node/Oem/SWIGEx/Source/Modules/nodejs.cxx
Log:
This submission includes:
* Codegen for "wrap" constructors, which are constructors that allow us to attach native pointers to. This is needed to support APIs that return JS proxies for our MapGuide C++ classes
* Codegen for proper polymorphism support, for any API that returns a Mg object, we use the class id mechanism to resolve the appropriate "wrap" constructor to invoke. Otherwise APIs like MgSiteConnection.CreateService will return a JS object with the MgService prototype (and not the prototype of the most derived class).
* Constructor codegen to guard against calls without the JS new operator
Modified: sandbox/jng/node/Oem/SWIGEx/Source/Modules/nodejs.cxx
===================================================================
--- sandbox/jng/node/Oem/SWIGEx/Source/Modules/nodejs.cxx 2013-06-20 05:04:57 UTC (rev 7634)
+++ sandbox/jng/node/Oem/SWIGEx/Source/Modules/nodejs.cxx 2013-06-20 15:00:57 UTC (rev 7635)
@@ -4,13 +4,15 @@
#include <sstream>
#define EXPORTS_VAR "exports"
-#define CLASS_EXPORT_VAR "tpl"
+#define CLASS_EXPORT_VAR "constructor_tpl"
#define CLASS_PROXY_CTOR_NAME "New"
#define BASE_CLASS_FUNC_TEMPLATE_VAR "baseCls"
#define WRAPPED_PTR_VAR "wrappedPtr"
#define FUNC_RET_VAR "retVal"
#define ARGS_VAR "args"
+extern std::map<std::string, int> clsIds;
+
class Indenter
{
private:
@@ -237,6 +239,7 @@
writeToFile("#include <node.h>\n\n\n");
writeToFile("//TODO: Should learn how to process SWIG %module directive instead of hard-coding headers\n");
+ writeToFile("#include <map>\n");
writeToFile("#include \"MapGuideCommon.h\"\n");
writeToFile("#include \"WebApp.h\"\n");
writeToFile("#include \"WebSupport.h\"\n");
@@ -250,6 +253,18 @@
Language::top(n);
writeToFile("//=====================================\n");
+ writeToFile("//Polymorphism support\n");
+ writeToFile("//=====================================\n");
+ writeToFile("class JsProxyFactory\n");
+ writeToFile("{\n");
+ writeToFile("public:\n");
+ {
+ Indenter ind(m_indentationLevels);
+ writeToFile("static v8::Handle<v8::Value> CreateJsProxy(MgObject* obj);\n");
+ }
+ writeToFile("};\n\n");
+
+ writeToFile("//=====================================\n");
writeToFile("//Proxy class definitions\n");
writeToFile("//=====================================\n");
for (StringMap::iterator it = m_classDecls.begin(); it != m_classDecls.end(); it++)
@@ -259,7 +274,41 @@
writeToFile("\n");
}
+ // Add main polymorphism support code
writeToFile("//=====================================\n");
+ writeToFile("//Polymorphism support implementation\n");
+ writeToFile("//=====================================\n");
+ writeToFile("v8::Handle<v8::Value> JsProxyFactory::CreateJsProxy(MgObject* obj)\n");
+ writeToFile("{\n");
+ {
+ Indenter ind(m_indentationLevels);
+ writeToFile("CHECKARGUMENTNULL(obj, L\"JsProxyFactory::CreateJsProxy\");\n");
+
+ writeToFile("INT32 clsId = obj->GetClassId();\n");
+ writeToFile("switch(clsId)\n");
+ writeToFile("{\n");
+ {
+ Indenter ind2(m_indentationLevels);
+ for(std::map<std::string, int>::const_iterator it = clsIds.begin(); it != clsIds.end(); it++)
+ {
+ std::string clsName = it->first;
+ //Skip exception classes
+ if (clsName.find("Exception") != std::string::npos)
+ continue;
+
+ int clsId = it->second;
+
+ std::string proxyClsName;
+ setProxyClassName(clsName.c_str(), proxyClsName);
+ writeToFile(NewStringf("case %d: return %s::CreateJsProxy(obj);\n", clsId, proxyClsName.c_str()));
+ }
+ writeToFile("default: return v8::ThrowException(v8::Exception::Error(v8::String::New(\"Could not find JavaScript proxy factory for unmanaged pointer\")));\n");
+ }
+ writeToFile("}\n");
+ }
+ writeToFile("}\n");
+
+ writeToFile("//=====================================\n");
writeToFile("//v8 persistent Proxy class constructors\n");
writeToFile("//=====================================\n");
for (StringMap::iterator it = m_classDecls.begin(); it != m_classDecls.end(); it++)
@@ -304,6 +353,27 @@
mbMethodName += "::";
mbMethodName += CLASS_PROXY_CTOR_NAME;
+ codeWriter.writeToFragment(NewStringf("if (!%s.IsConstructCall())\n", ARGS_VAR));
+ codeWriter.writeToFragment("{\n");
+ {
+ Indenter ind2(m_indentationLevels);
+ codeWriter.writeToFragment(NewStringf("return v8::ThrowException(v8::Exception::TypeError(v8::String::New(\"Use the new operator to create instances of %s\")));\n", clsName.c_str()));
+ }
+ codeWriter.writeToFragment("}\n");
+
+ //wrap constructor
+ codeWriter.writeToFragment("//Check if this is a C++ class wrap constructor call\n");
+ codeWriter.writeToFragment(NewStringf("if (%s.Length() == 1 && %s[0]->IsExternal())\n", ARGS_VAR, ARGS_VAR));
+ codeWriter.writeToFragment("{\n");
+ {
+ Indenter ind2(m_indentationLevels);
+ codeWriter.writeToFragment(NewStringf("%s* obj = (%s*)v8::External::Unwrap(%s[0]);\n", proxyClsName.c_str(), proxyClsName.c_str(), ARGS_VAR));
+ codeWriter.writeToFragment("//Wrap to \"this\"\n");
+ codeWriter.writeToFragment(NewStringf("obj->Wrap(%s.This());\n", ARGS_VAR));
+ codeWriter.writeToFragment(NewStringf("return %s.This();\n", ARGS_VAR));
+ }
+ codeWriter.writeToFragment("}\n");
+
codeWriter.writeToFragment(NewStringf("Ptr<%s> %s;\n", clsName.c_str(), WRAPPED_PTR_VAR));
ExceptionCodeWriter writer(codeWriter, mbMethodName);
codeWriter.writeToFragment(m_ctorSetupCode[clsName]);
@@ -315,7 +385,20 @@
}
else
{
- writeToFile(NewStringf("\treturn v8::ThrowException(v8::Exception::Error(v8::String::New(\"Class %s has no public constructors\")));\n", clsName.c_str()));
+ Indenter ind(m_indentationLevels);
+ //wrap constructor
+ writeToFile("//Check if this is a C++ class wrap constructor call\n");
+ writeToFile(NewStringf("if (%s.Length() == 1 && %s[0]->IsExternal())\n", ARGS_VAR, ARGS_VAR));
+ writeToFile("{\n");
+ {
+ Indenter ind2(m_indentationLevels);
+ writeToFile(NewStringf("%s* obj = (%s*)v8::External::Unwrap(%s[0]);\n", proxyClsName.c_str(), proxyClsName.c_str(), ARGS_VAR));
+ writeToFile("//Wrap to \"this\"\n");
+ writeToFile(NewStringf("obj->Wrap(%s.This());\n", ARGS_VAR));
+ writeToFile(NewStringf("return %s.This();\n", ARGS_VAR));
+ }
+ writeToFile("}\n");
+ writeToFile(NewStringf("return v8::ThrowException(v8::Exception::Error(v8::String::New(\"Class %s has no public constructors\")));\n", clsName.c_str()));
}
writeToFile("}\n\n");
}
@@ -581,10 +664,12 @@
m_currentExportFragment += EXPORTS_VAR;
m_currentExportFragment += ");";
+ /*
m_currentInheritFragment += proxyClsName;
m_currentInheritFragment += "::ApplyInheritanceChain(";
m_currentInheritFragment += EXPORTS_VAR;
m_currentInheritFragment += ");";
+ */
//Unmanaged pointer member
cls.writeToFragment(clsHead);
@@ -638,10 +723,10 @@
//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(NewStringf("static v8::Handle<v8::Value> CreateJsProxy(%s* ptr);\n", clsName.c_str()));
+ //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");
+ //cls.writeToFragment("static void ApplyInheritanceChain(v8::Handle<v8::Object> exports);\n");
}
//Class body
@@ -681,6 +766,7 @@
cls.writeToFragment(NewStringf("static v8::Persistent<v8::Function> constructor;\n"));
}
+ /*
//node/v8 public factory
{
Indenter ind(m_indentationLevels);
@@ -703,18 +789,25 @@
}
clsSetup.writeToFragment("}\n");
}
+ */
//node/v8 wrap mg pointer factory method
{
Indenter ind(m_indentationLevels);
- clsSetup.writeToFragment(NewStringf("v8::Handle<v8::Value> %s::CreateJsProxy(%s* ptr)\n", proxyClsName.c_str(), m_currentClassName));
+ clsSetup.writeToFragment(NewStringf("v8::Handle<v8::Value> %s::CreateJsProxy(MgObject* ptr)\n", proxyClsName.c_str()));
clsSetup.writeToFragment("{\n");
{
Indenter ind2(m_indentationLevels);
clsSetup.writeToFragment("v8::HandleScope scope;\n");
- clsSetup.writeToFragment("v8::Local<v8::Object> instance = constructor->NewInstance();\n");
- clsSetup.writeToFragment(NewStringf("%s* proxyVal = new %s(ptr);\n", proxyClsName.c_str(), proxyClsName.c_str()));
- clsSetup.writeToFragment("proxyVal->Wrap(instance);\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");
@@ -727,11 +820,22 @@
clsSetup.writeToFragment("{\n");
{
Indenter ind2(m_indentationLevels);
- clsSetup.writeToFragment(NewStringf("v8::Local<v8::FunctionTemplate> %s = v8::FunctionTemplate::New(%s::%s);\n", CLASS_EXPORT_VAR, proxyClsName.c_str(), CLASS_PROXY_CTOR_NAME));
- clsSetup.writeToFragment(NewStringf("constructor_tpl = v8::Persistent<v8::FunctionTemplate>::New(%s);\n", CLASS_EXPORT_VAR));
- clsSetup.writeToFragment(NewStringf("%s->SetClassName(v8::String::NewSymbol(\"%s\"));\n", CLASS_EXPORT_VAR, m_currentClassName));
+ clsSetup.writeToFragment(NewStringf("v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(%s::%s);\n", proxyClsName.c_str(), CLASS_PROXY_CTOR_NAME));
+ clsSetup.writeToFragment(NewStringf("%s = v8::Persistent<v8::FunctionTemplate>::New(tpl);\n", CLASS_EXPORT_VAR));
+
+ //This is ok because export calls are ordered with base classes first, so we're assured to be
+ //inheriting from an initialized base class function template
+ if (Strcmp("", baseClassName) != 0)
+ {
+ std::string proxyBaseClsName;
+ setProxyClassName(baseClassName, proxyBaseClsName);
+ clsSetup.writeToFragment("//Inherit from base class function template\n");
+ clsSetup.writeToFragment(NewStringf("constructor_tpl->Inherit(%s::constructor_tpl);\n", proxyBaseClsName.c_str()));
+ }
+
clsSetup.writeToFragment("//For the internal pointer\n");
clsSetup.writeToFragment(NewStringf("%s->InstanceTemplate()->SetInternalFieldCount(1);\n", CLASS_EXPORT_VAR));
+ clsSetup.writeToFragment(NewStringf("%s->SetClassName(v8::String::NewSymbol(\"%s\"));\n", CLASS_EXPORT_VAR, m_currentClassName));
std::string ctorReg;
ctorReg += proxyClsName;
@@ -759,6 +863,7 @@
clsSetup.writeToFragment("}\n");
}
+ /*
//node/v8 export function
{
Indenter ind(m_indentationLevels);
@@ -780,6 +885,7 @@
}
clsSetup.writeToFragment("}\n");
}
+ */
cls.writeToFragment("};");
Delete(m_currentClassName);
@@ -787,7 +893,7 @@
m_classDecls[clsName] = m_currentFragment;
m_classExportCalls.push_back(m_currentExportFragment);
- m_classInheritCalls.push_back(m_currentInheritFragment);
+ //m_classInheritCalls.push_back(m_currentInheritFragment);
m_classSetupCalls.push_back(m_currentClassSetupFragment);
}
@@ -914,7 +1020,7 @@
if (isMgPointer) //Stub
{
meth.writeToFragment("v8::HandleScope scope;\n");
- meth.writeToFragment(NewStringf("v8::Handle<v8::Value> instance = Proxy%s::CreateJsProxy(%s);\n", retTypeUnprefixed, FUNC_RET_VAR));
+ meth.writeToFragment(NewStringf("v8::Handle<v8::Value> instance = JsProxyFactory::CreateJsProxy(%s);\n", FUNC_RET_VAR));
meth.writeToFragment("return scope.Close(instance);\n");
}
else
More information about the mapguide-commits
mailing list