Fix function dispatching for v8.

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/branches/oliverb-javascript-v8@13812 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Oliver Buchtala 2012-09-08 01:12:18 +00:00
commit d13289cc91
4 changed files with 160 additions and 60 deletions

View file

@ -64,6 +64,24 @@ JSValueRef $jswrapper(JSContextRef context, JSObjectRef function, JSObjectRef th
}
%}
%fragment ("JS_function_dispatcher", "templates")
%{
JSValueRef $jswrapper(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exception)
{
$jslocals
JSValueRef jsresult;
int res;
$jscode
SWIG_exception_fail(SWIG_ERROR, "Illegal arguments for function $jsname.");
return jsresult;
goto fail;
fail:
return NULL;
}
%}
%fragment ("JS_functionwrapper_overload", "templates")
%{
int $jswrapper(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exception, JSValueRef* result)
@ -96,11 +114,6 @@ int $jswrapper(JSContextRef context, JSObjectRef function, JSObjectRef thisObjec
}
%}
%fragment ("JS_function_dispatch_case_default", "templates")
%{
SWIG_exception_fail(SWIG_ERROR, "Illegal arguments for function $jsname.");
%}
/* Added template for function declaration */
%fragment ("JS_variabledecl", "templates")

View file

@ -19,7 +19,38 @@ v8::Handle<v8::Value> $jsctor(const v8::Arguments& args) {
v8::HandleScope scope;
SWIG_exception(SWIG_ERROR, "Class $jsname can not be instantiated");
return scope.Close(v8::Undefined());
}%}
}
%}
%fragment ("JS_mainctordefn", "templates") %{
v8::Handle<v8::Value> $jswrapper(const v8::Arguments& args) {
v8::HandleScope scope;
// switch all cases by means of series of if-returns.
$jsdispatchcases
// default:
SWIG_exception_fail(SWIG_ERROR, "Illegal arguments for contruction of $jsmangledname");
fail:
scope.Close(v8::Undefined());
}
%}
%fragment ("JS_ctor_dispatch_case", "templates")
%{if(args.Length() == $jsargcount) {
v8::Handle<v8::Value> self = $jswrapper(args);
if(!self->IsUndefined()) {
return scope.Close(self);
}
}
%}
%fragment ("JS_destructordefn", "templates")
%{
// TODO: implement JS_destructordefn
%}
%fragment("JS_getproperty", "templates") %{
v8::Handle<v8::Value> $jsgetter(v8::Local<v8::String> property, const v8::AccessorInfo& info) {
@ -53,37 +84,55 @@ v8::Handle<v8::Value> $jswrapper(const v8::Arguments &args) {
goto fail;
fail:
return scope.Close(v8::Undefined());
}%}
%fragment ("JS_mainctordefn", "templates") %{
v8::Handle<v8::Value> $jswrapper(const v8::Arguments& args) {
v8::HandleScope scope;
v8::TryCatch tryCatch;
// switch all cases by means of series of if-returns.
$jsdispatchcases
// default:
if(!tryCatch.HasCaught())
SWIG_exception_fail(SWIG_ERROR, "Illegal arguments for contruction of $jsmangledname");
fail:
scope.Close(v8::Undefined());
}
%}
%fragment ("JS_ctor_dispatch_case", "templates")
%{if(args.Length() == $jsargcount) {
v8::Handle<v8::Value> self = $jswrapper(args);
if(!self->IsUndefined()) {
tryCatch.Reset(); return scope.Close(self); /* reset exception and return */
}
%fragment("JS_function_dispatcher", "templates") %{
v8::Handle<v8::Value> $jswrapper(const v8::Arguments &args) {
v8::HandleScope scope;
v8::Handle<v8::Value> jsresult;
OverloadErrorHandler errorHandler;
$jscode
SWIG_exception_fail(SWIG_ERROR, "Illegal arguments for function $jsname.");
goto fail;
fail:
return scope.Close(v8::Undefined());
}
%}
%fragment ("JS_functionwrapper_overload", "templates")
%{
v8::Handle<v8::Value> $jswrapper(const v8::Arguments &args, V8ErrorHandler& SWIGV8_ErrorHandler)
{
v8::HandleScope scope;
v8::Handle<v8::Value> jsresult;
$jslocals
if(args.Length() != $jsargcount) SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments for $jswrapper.");
$jscode
return scope.Close(jsresult);
goto fail;
fail:
return scope.Close(jsresult);
}
%}
%fragment ("JS_function_dispatch_case", "templates")
%{
if(args.Length() == $jsargcount) {
errorHandler.err.Clear();
jsresult = $jswrapper(args, errorHandler);
if(errorHandler.err.IsEmpty()) {
return scope.Close(jsresult);
}
}
%}
%fragment ("JS_destructordefn", "templates")
%fragment ("JS_function_dispatch_case_default", "templates")
%{
// TODO: implement JS_destructordefn
SWIG_exception_fail(SWIG_ERROR, "Illegal arguments for function $jsname.");
%}
%fragment("jsv8_declare_class_template", "templates")

View file

@ -14,9 +14,48 @@
%insert(runtime) "swigerrors.swg"; /* SWIG errors */
%insert(runtime) %{
#define SWIG_Error(code, msg) SWIG_V8_exception(code, msg)
#define SWIG_exception(code, msg) SWIG_V8_exception(code, msg)
#define SWIG_Error(code, msg) SWIGV8_ErrorHandler.error(code, msg)
#define SWIG_exception(code, msg) SWIGV8_ErrorHandler.error(code, msg)
#define SWIG_fail goto fail
#define SWIGV8_OVERLOAD false
void SWIG_V8_Raise(const char* msg) {
v8::ThrowException(v8::Exception::Error(v8::String::New(msg)));
}
/*
Note: There are two contexts for handling errors.
A static V8ErrorHandler is used in not overloaded methods.
For overloaded methods the throwing type checking mechanism is used
during dispatching. As V8 exceptions can not be resetted properly
the trick is to use a dynamic ErrorHandler with same local name as the global
one.
- See defintion of SWIG_Error above.
- See code templates 'JS_function_dispatcher', 'JS_functionwrapper_overload',
and 'JS_function_dispatch_case' in javascriptcode.swg
*/
class V8ErrorHandler {
public:
virtual void error(int code, const char* msg) {
SWIG_V8_Raise(msg);
}
};
// this is used in usually
V8ErrorHandler SWIGV8_ErrorHandler;
// instances of this are used in overloaded functions
class OverloadErrorHandler: public V8ErrorHandler {
public:
virtual void error(int code, const char* msg) {
err = v8::Exception::Error(v8::String::New(msg));
if(code != SWIG_TypeError) {
v8::ThrowException(err);
}
}
v8::Handle<v8::Value> err;
};
%}
%insert(runtime) %{
@ -27,18 +66,6 @@ typedef struct {
} SWIG_PRV_DATA;
%}
%insert(runtime) %{
void SWIG_V8_Raise(const char* msg) {
v8::ThrowException(v8::Exception::Error(v8::String::New(msg)));
}
void SWIG_V8_exception(int code, const char* msg) {
SWIG_V8_Raise(msg);
}
%}
%insert(runtime) %{
int SWIG_V8_ConvertInstancePtr(v8::Handle<v8::Object> objRef, void** ptr, swig_type_info *info, int flags) {

View file

@ -766,6 +766,12 @@ int JSEmitter::enterFunction(Node *n) {
if(Equal(Getattr(n, "storage"), "static")) {
SetFlag(state.function(), IS_STATIC);
}
/* Initialize DOH for collecting function dispatchers */
bool is_overloaded = GetFlag(n, "sym:overloaded");
if (is_overloaded && state.global(FUNCTION_DISPATCHERS) == 0) {
state.global(FUNCTION_DISPATCHERS, NewString(""));
}
return SWIG_OK;
}
@ -1012,16 +1018,13 @@ int JSEmitter::emitFunction(Node *n, bool is_member, bool is_static) {
int JSEmitter::emitFunctionDispatcher(Node *n, bool /*is_member */ ) {
Template t_function(getTemplate("JS_functionwrapper"));
Template t_function(getTemplate("JS_function_dispatcher"));
Wrapper *wrapper = NewWrapper();
String *wrap_name = Swig_name_wrapper(Getattr(n, "name"));
Setattr(n, "wrap:name", wrap_name);
Wrapper_add_local(wrapper, "res", "int res");
Append(wrapper->code, state.global(FUNCTION_DISPATCHERS));
Append(wrapper->code, getTemplate("JS_function_dispatch_case_default").str());
t_function.replace(T_LOCALS, wrapper->locals)
.replace(T_CODE, wrapper->code);
@ -1365,12 +1368,6 @@ int JSCEmitter::enterFunction(Node *n) {
JSEmitter::enterFunction(n);
/* Initialize DOH for collecting function dispatchers */
bool is_overloaded = GetFlag(n, "sym:overloaded");
if (is_overloaded && state.global(FUNCTION_DISPATCHERS) == 0) {
state.global(FUNCTION_DISPATCHERS, NewString(""));
}
return SWIG_OK;
}
@ -1808,20 +1805,34 @@ int V8Emitter::enterFunction(Node* n)
}
int V8Emitter::exitFunction(Node* n)
{
{
bool is_member = GetFlag(n, "ismember");
// create a dispatcher for overloaded functions
bool is_overloaded = GetFlag(n, "sym:overloaded");
if (is_overloaded) {
if (!Getattr(n, "sym:nextSibling")) {
state.function(WRAPPER_NAME, Swig_name_wrapper(Getattr(n, "name")));
emitFunctionDispatcher(n, is_member);
} else {
//don't register wrappers of overloaded functions in function tables
return SWIG_OK;
}
}
// register the function at the specific context
if(GetFlag(n, "ismember")) {
if(is_member) {
if(GetFlag(state.function(), IS_STATIC)) {
Template t_register(getTemplate("jsv8_register_static_function"));
t_register.replace(T_PARENT, state.clazz(NAME_MANGLED))
.replace(T_NAME, state.function(NAME))
.replace(T_WRAPPER, Getattr(n, "wrap:name"))
.replace(T_WRAPPER, state.function(WRAPPER_NAME))
.pretty_print(f_init_static_wrappers);
} else {
Template t_register(getTemplate("jsv8_register_member_function"));
t_register.replace(T_NAME_MANGLED, state.clazz(NAME_MANGLED))
.replace(T_NAME, state.function(NAME))
.replace(T_WRAPPER, Getattr(n, "wrap:name"))
.replace(T_WRAPPER, state.function(WRAPPER_NAME))
.pretty_print(f_init_wrappers);
}
} else {
@ -1830,8 +1841,8 @@ int V8Emitter::exitFunction(Node* n)
Template t_register(getTemplate("jsv8_register_static_function"));
t_register.replace(T_PARENT, Getattr(current_namespace, NAME))
.replace(T_NAME, state.function(NAME))
.replace(T_WRAPPER, Getattr(n, "wrap:name"))
.pretty_print(f_init_wrappers);
.replace(T_WRAPPER, state.function(WRAPPER_NAME))
.pretty_print(f_init_static_wrappers);
}
return SWIG_OK;