diff --git a/CMakeLists.txt b/CMakeLists.txt index 442fa6d6a..e7d96cc8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,6 +137,8 @@ add_library(modules "${SWIG_SOURCE_DIR}/Modules/allegrocl.cxx" "${SWIG_SOURCE_DIR}/Modules/javascript.cxx" "${SWIG_SOURCE_DIR}/Modules/javascript_emitter.h" "${SWIG_SOURCE_DIR}/Modules/javascript_emitter.cxx" + "${SWIG_SOURCE_DIR}/Modules/javascript_v8.h" + "${SWIG_SOURCE_DIR}/Modules/javascript_v8.cxx" "${SWIG_SOURCE_DIR}/Modules/lang.cxx" "${SWIG_SOURCE_DIR}/Modules/lua.cxx" "${SWIG_SOURCE_DIR}/Modules/modula3.cxx" diff --git a/Lib/javascript/v8/javascriptcode.swg b/Lib/javascript/v8/javascriptcode.swg new file mode 100644 index 000000000..1b6d33662 --- /dev/null +++ b/Lib/javascript/v8/javascriptcode.swg @@ -0,0 +1,73 @@ + +%fragment("v8_initializer", "templates") %{ +void ${MODULE}_Initialize(v8::Handle context) +{ + v8::HandleScope scope; + + // register the module in globale context + v8::Local global = context->Global(); + + ${PART_NAMESPACES} + + ${PART_CLASS_TEMPLATES} + + ${PART_WRAPPERS} + + ${PART_INHERITANCE} + + ${PART_REGISTER} +}%} + +%fragment("v8_declare_class_template", "templates") %{ +v8::Persistent SWIGV8_${NAME_MANGLED};%} + +%fragment("v8_define_class_template", "templates") %{ +SWIGV8_${NAME_MANGLED} = SWIGV8_CreateClassTemplate("${NAME_UNQUALIFIED}" , ${NAME_MANGLED}_new);%} + +%fragment("v8_inherit", "templates") %{ +SWIGV8_${NAME_MANGLED}->Inherit(SWIGV8_${BASE_CLASS});%} + +%fragment("v8_register_class", "templates") %{ +${CONTEXT}->Set(v8::String::NewSymbol("${NAME_UNQUALIFIED}", SWIGV8_${NAME_MANGLED}->GetFunction()));%} + +%fragment("v8_ctor_wrapper", "templates") %{ +v8::Handle ${NAME_MANGLED}_new(const v8::Arguments& args) { + v8::HandleScope scope; + v8::Handle self = args.Holder(); + ${LOCALS} + ${ACTION} + self->SetInternalField(0, v8::External::New(ptr)); + return self; +} +%} + +%fragment("v8_getter", "templates") %{ +v8::Handle ${NAME_MANGLED}_get(v8::Local property, const v8::AccessorInfo& info) { + v8::HandleScope scope; + v8::Handle ret; + ${LOCALS} + ${ACTION} + ${MARSHAL_OUTPUT} + return scope.Close(ret); +} +%} + +%fragment("v8_setter", "templates") %{ +void ${NAME_MANGLED}_set(v8::Local property, v8::Local value, const v8::AccessorInfo& info) { + ${LOCALS} + ${MARSHAL_INPUT} + ${ACTION} +} +%} + +%fragment("v8_function", "templates") %{ +v8::Handle ${NAME_MANGLED}(const Arguments &args) { + v8::HandleScope scope; + v8::Handle ret; + ${LOCALS} + ${MARSHAL_INPUT} + ${ACTION} + ${MARSHAL_OUTPUT} + return scope.Close(ret); +} +%} diff --git a/Lib/javascript/v8/javascripthelpers.swg b/Lib/javascript/v8/javascripthelpers.swg new file mode 100644 index 000000000..61836c87d --- /dev/null +++ b/Lib/javascript/v8/javascripthelpers.swg @@ -0,0 +1,58 @@ + +%insert(runtime) %{ + +/** + * Creates a class template for a class without extra initialization function. + */ +v8::Persistent SWIGV8_CreateClassTemplate(const char* symbol) { + v8::Local class_templ = v8::FunctionTemplate::New(); + class_templ->SetClassName(v8::String::NewSymbol(symbol)); + + v8::Handle inst_templ = class_templ->InstanceTemplate(); + inst_templ->SetInternalFieldCount(1); + + return v8::Persistent::New(class_templ); +} + +/** + * Creates a class template for a class with specified initialization function. + */ +v8::Persistent SWIGV8_CreateClassTemplate(const char* symbol, v8::InvocationCallback _func) { + v8::Local class_templ = v8::FunctionTemplate::New(_func); + class_templ->SetClassName(v8::String::NewSymbol(symbol)); + + v8::Handle inst_templ = class_templ->InstanceTemplate(); + inst_templ->SetInternalFieldCount(1); + + return v8::Persistent::New(class_templ); +} + +/** + * Sets the pimpl data of a V8 class. + */ +v8::Handle V8GeneratorUtils::SetInstance(const v8::Arguments& args, void* data) { + v8::HandleScope scope; + + v8::Handle self = args.Holder(); + self->SetInternalField(0, v8::External::New(data)); + + return self; +} + +/** + * Registers a class method with given name for a given class template. + */ +void V8GeneratorUtils::AddClassMethod(v8::Handle class_templ, const char* symbol, v8::InvocationCallback _func) { + v8::Handle proto_templ = class_templ->PrototypeTemplate(); + proto_templ->Set(v8::String::NewSymbol(symbol), v8::FunctionTemplate::New(_func)); +} + +/** + * Registers a class property with given name for a given class template. + */ +void V8GeneratorUtils::AddProperty(v8::Handle class_templ, const char* varname, v8::AccessorGetter getter, v8::AccessorSetter setter) { + v8::Handle proto_templ = class_templ->InstanceTemplate(); + proto_templ->SetAccessor(v8::String::New(varname), getter, setter); +} + +%} // v8_helper_functions diff --git a/Lib/javascript/v8/javascriptprimitives.swg b/Lib/javascript/v8/javascriptprimitives.swg new file mode 100644 index 000000000..d5c89c690 --- /dev/null +++ b/Lib/javascript/v8/javascriptprimitives.swg @@ -0,0 +1,265 @@ +// Primitive types +%typemap(in) char, + signed char, + unsigned char, + short, + unsigned short, + int, + unsigned int, + long, + unsigned long, + long long, + unsigned long long, + float, + double +%{ $1 = ($1_ltype)JSValueToNumber(context, $input, NULL); %} + +%typemap(in) const bool &, bool &, + const char &, char &, + const signed char &, signed char &, + const unsigned char &, unsigned char &, + const short &, short &, + const unsigned short &, unsigned short &, + const int &, int &, + const unsigned int &, unsigned int &, + const long &, long &, + const unsigned long &, unsigned long &, + const long long &, long long &, + const unsigned long long &,unsigned long long &, + const float &, float &, + const double &, double & +%{ $1 = ($1_ltype)&$input; %} + +%typemap(out) char, + signed char, + unsigned char, + short, + unsigned short, + int, + unsigned int, + long, + unsigned long, + long long, + unsigned long long, + float, + double +%{ $result = JSValueMakeNumber(context, $1); %} + +%typemap(out) const bool &, bool &, + const char &, char &, + const signed char &, signed char &, + const unsigned char &, unsigned char &, + const short &, short &, + const unsigned short &, unsigned short &, + const int &, int &, + const unsigned int &, unsigned int &, + const long &, long &, + const unsigned long &, unsigned long &, + const long long &, long long &, + const unsigned long long &,unsigned long long &, + const float &, float &, + const double &, double & +%{ $result = JSValueMakeNumber(context,*$1); %} + + +%typemap(in) short *, + unsigned short *, + int *, + unsigned int *, + long *, + unsigned long *, + long long *, + unsigned long long *, + float *, + double * +%{ + JSObjectRef o$1 = JSValueToObject(context,$input, NULL); + SWIG_PRV_DATA *$1_privatedata = (SWIG_PRV_DATA *)JSObjectGetPrivate(o$1); + $1 = ($1_ltype)$1_privatedata->swigCObject; +%} + + +%typemap(out) short *, + unsigned short *, + int *, + unsigned int *, + long *, + unsigned long *, + long long *, + unsigned long long *, + float *, + double * +%{ + SWIG_PRV_DATA *privatedata = new SWIG_PRV_DATA(); + privatedata->swigCMemOwn = false; + privatedata->swigCObject = result; + $result = JSObjectMake(context, _wrap_swig_ptr_$*1_ltype_createJSClass(context), privatedata); +%} + +%typemap(in) bool +%{ + $1 = ($1_ltype)JSValueToBoolean(context, $input); +%} + +%typemap(out) bool +%{ + $result = JSValueMakeBoolean(context, $1); +%} + + +%typemap(out) void +%{ $result = JSValueMakeUndefined(context); %} + + +%typemap(in) char * +%{ + JSStringRef $1_str = JSValueToStringCopy(context, $input, NULL); + size_t $1_strsize = JSStringGetMaximumUTF8CStringSize($1_str); + $1 = (char *)malloc($1_strsize * sizeof(char)); + JSStringGetUTF8CString($1_str, $1, $1_strsize); +%} + +%typemap(out) char * +%{ + JSStringRef jsstring = JSStringCreateWithUTF8CString($1); + $result = JSValueMakeString(context, jsstring); + JSStringRelease(jsstring); +%} + +%typemap(arginit) char * "" + +%typemap(in) char *& ($*1_ltype temp = 0) %{ + temp = ($*1_ltype)$input; + JSStringRef $1_str = JSValueToStringCopy(context, $input, NULL); + size_t $1_strsize = JSStringGetMaximumUTF8CStringSize($1_str); + $1 = (char *)malloc($1_strsize * sizeof(char)); + JSStringGetUTF8CString($1_str, $1, $1_strsize); +%} + +%typemap(out) char *& +%{ + JSStringRef jsstring = JSStringCreateWithUTF8CString((const char *)*$1); + $result = JSValueMakeString(context, jsstring); + JSStringRelease(jsstring); +%} + +/* char arrays - treat as String */ +%typemap(in) char[ANY], char[] %{ + JSStringRef $1_str = JSValueToStringCopy(context, $input, NULL); + size_t $1_strsize = JSStringGetMaximumUTF8CStringSize($1_str); + JSStringGetUTF8CString($1_str, $1, $1_strsize); +%} + +%typemap(out) char[ANY], char[] +%{ + JSStringRef jsstring = JSStringCreateWithUTF8CString($1); + $result = JSValueMakeString(context, jsstring); + JSStringRelease(jsstring); +%} + +%typemap(freearg) char *, char *&, char[ANY], char[] //TODO: Not working: A memory leak +%{ free($1); %} + + +/* Typemaps for composite types */ +%typemap(in) SWIGTYPE ($&1_type argp) // Objects passed by value, convert to a pointer +%{ + JSObjectRef o$1 = JSValueToObject(context,$input, NULL); + SWIG_PRV_DATA *$1_privatedata = (SWIG_PRV_DATA *)JSObjectGetPrivate(o$1); + argp = ($&1_ltype)$1_privatedata->swigCObject; + $1 = *argp; +%} + +%typemap(out) SWIGTYPE ($&1_type temp) +#ifdef __cplusplus +%{ + temp = new $1_ltype((const $1_ltype &)$1); + SWIG_PRV_DATA *privatedata = new SWIG_PRV_DATA(); + privatedata->swigCMemOwn = false; + privatedata->swigCObject = temp; + $result = JSObjectMake(context, _wrap_$1_type_createJSClass(context), privatedata); + //$result = JSObjectMake(context, _wrap_$1_basetype_createJSClass(context), privatedata); + //$result = JSObjectMake(context, _wrap_$objecttype_createJSClass(context), privatedata); + // $1_mangle + // $1_descriptor +%} +#else +{ + $&1_ltype $1ptr = ($&1_ltype) malloc(sizeof($1_ltype)); + memmove($1ptr, &$1, sizeof($1_type)); + temp = $1ptr; + SWIG_PRV_DATA *privatedata = (SWIG_PRV_DATA *)malloc(sizeof(SWIG_PRV_DATA()); + privatedata->swigCMemOwn = false; + privatedata->swigCObject = temp; + $result = JSObjectMake(context, _wrap_$1_ltype_createJSClass(context), privatedata); + //$result = JSObjectMake(context, _wrap_$1_basetype_createJSClass(context), privatedata); + //$result = JSObjectMake(context, _wrap_$objecttype_createJSClass(context), privatedata); + // $1_mangle + // $1_descriptor +} +#endif + +%typemap(in) SWIGTYPE *, SWIGTYPE & +%{ + JSObjectRef o$1 = JSValueToObject(context,$input, NULL); + SWIG_PRV_DATA *$1_privatedata = (SWIG_PRV_DATA *)JSObjectGetPrivate(o$1); + $1 = ($1_ltype)$1_privatedata->swigCObject; +%} + +%typemap(out) SWIGTYPE *, SWIGTYPE & +%{ + SWIG_PRV_DATA *privatedata = new SWIG_PRV_DATA(); + privatedata->swigCMemOwn = false; + privatedata->swigCObject = result; + $result = JSObjectMake(context, _wrap_$*1_ltype_createJSClass(context), privatedata); + //$result = JSObjectMake(context, _wrap_$1_basetype_createJSClass(context), privatedata); + //$result = JSObjectMake(context, _wrap_$objecttype_createJSClass(context), privatedata); + // $1_mangle + // $1_descriptor +%} + +%typemap(arginit) SWIGTYPE * +%{ + // Sanity check if the call is not on the global object + if (!JSValueIsEqual(context, + JSValueToObject(context,thisObject,NULL), + JSValueToObject(context,JSContextGetGlobalObject(context), NULL), + NULL)) { + SWIG_PRV_DATA* $1_swigprivatedata = (SWIG_PRV_DATA*)JSObjectGetPrivate(thisObject); + $1 = ($1_ltype)$1_swigprivatedata->swigCObject; + } +%} + +%typemap(in) SWIGTYPE (CLASS::*) "" + +%typemap(out) SWIGTYPE (CLASS::*) +%{ + // Class* out typemap + $result = JSObjectMake(context, _wrap_$*1_ltype_createJSClass(context), result); +%} + + + +/* Typecheck typemaps - The purpose of these is merely to issue a warning for overloaded C++ functions + * that cannot be overloaded in Javascript as more than one C++ type maps to a single Javascript type */ +// TODO + + +// Default array handling +%typemap(in) SWIGTYPE [] %{ $1 = ($1_ltype)$input; %} +%typemap(out) SWIGTYPE [] %{ $result = $1; %} + + +// Javascript specific directives +//TODO + +// Some ANSI C typemaps */ +%apply unsigned long { size_t }; + +%apply const unsigned long & { const size_t & }; + +// Array reference typemaps +%apply SWIGTYPE & { SWIGTYPE ((&)[ANY]) } + +// const pointers +%apply SWIGTYPE * { SWIGTYPE *const } diff --git a/Lib/javascript/v8/javascriptruntime.swg b/Lib/javascript/v8/javascriptruntime.swg new file mode 100644 index 000000000..ad34b6df2 --- /dev/null +++ b/Lib/javascript/v8/javascriptruntime.swg @@ -0,0 +1,9 @@ +/* ----------------------------------------------------------------------------- + * javascriptruntime.swg + * + * Javascript support code + * ----------------------------------------------------------------------------- */ + +%insert(runtime) %{ +#include +%} diff --git a/Source/Makefile.am b/Source/Makefile.am index fa11bfdcb..85530fd45 100644 --- a/Source/Makefile.am +++ b/Source/Makefile.am @@ -51,6 +51,7 @@ eswig_SOURCES = CParse/cscanner.c \ Modules/lang.cxx \ Modules/javascript.cxx \ Modules/javascript_emitter.cxx \ + Modules/javascript_v8.cxx \ Modules/lua.cxx \ Modules/main.cxx \ Modules/modula3.cxx \ diff --git a/Source/Modules/javascript.cxx b/Source/Modules/javascript.cxx index e1336d82a..64d943453 100644 --- a/Source/Modules/javascript.cxx +++ b/Source/Modules/javascript.cxx @@ -6,6 +6,8 @@ #include "javascript_emitter.h" +extern JSEmitter* create_v8_emitter(); + /* ******************************************************************** * JAVASCRIPT * ********************************************************************/ @@ -200,7 +202,7 @@ void JAVASCRIPT::main(int argc, char *argv[]) { switch(mode) { case JSEmitter::V8: { - // TODO: emitter = create_v8_emitter(); + emitter = create_v8_emitter(); break; } case JSEmitter::JavascriptCore: diff --git a/Source/Modules/javascript_v8.cxx b/Source/Modules/javascript_v8.cxx new file mode 100644 index 000000000..7d2583aca --- /dev/null +++ b/Source/Modules/javascript_v8.cxx @@ -0,0 +1,369 @@ +#include "javascript_v8.h" +#include "swigmod.h" + +/* ----------------------------------------------------------------------- + * String constants that are used in Lib/javascript/v8/javascriptcode.swg + *------------------------------------------------------------------------ */ + +// name of templates +#define V8_INITIALIZER "v8_initializer" +#define V8_DECL_CLASSTEMPLATE "v8_declare_class_template" +#define V8_DEFINE_CLASSTEMPLATE "v8_define_class_template" +#define V8_INHERIT "v8_inherit" +#define V8_REGISTER_CLASS "v8_register_class" +#define V8_CTOR_WRAPPER "v8_ctor_wrapper" +#define V8_GETTER "v8_getter" +#define V8_SETTER "v8_setter" +#define V8_FUNCTION "v8_function" +#define V8_RETRIEVE_THIS "v8_retrieve_this" + +// keywords used in templates +#define KW_MODULE_NAME "${MODULE}" +#define KW_MANGLED_NAME "${NAME_MANGLED}" +#define KW_UNQUALIFIED_NAME "${NAME_UNQUALIFIED}" +#define KW_BASE_CLASS "${BASE_CLASS}" +#define KW_CONTEXT "${CONTEXT}" + +#define KW_NAME_SPACES "${PART_NAMESPACES}" +#define KW_CLASS_TEMPLATES "${PART_CLASS_TEMPLATES}" +#define KW_WRAPPERS "${PART_WRAPPERS}" +#define KW_INHERITANCE "${PART_INHERITANCE}" +#define KW_REGISTER "${PART_REGISTER}" + +#define KW_LOCALS "${LOCALS}" +#define KW_MARSHAL_INPUT "${MARSHAL_INPUT}" +#define KW_ACTION "${ACTION}" +#define KW_MARSHAL_OUTPUT "${MARSHAL_OUTPUT}" + +V8Emitter::V8Emitter() + : JSEmitter(), + GLOBAL(NewString("global")), + namespaces(NewHash()) +{ +} + +V8Emitter::~V8Emitter() +{ + Delete(GLOBAL); + Delete(namespaces); +} + +int V8Emitter::Initialize(Node *n) +{ + + /* Get the output file name */ + String *outfile = Getattr(n,"outfile"); + f_wrap_cpp = NewFile(outfile, "w", SWIG_output_files()); + if (!f_wrap_cpp) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + f_runtime = NewString(""); + f_header = NewString(""); + f_class_templates = NewString(""); + f_wrapper = NewString(""); + + f_init_namespaces = NewString(""); + f_init_class_templates = NewString(""); + f_init_wrappers = NewString(""); + f_init_inheritance = NewString(""); + f_init_register = NewString(""); + + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrapper); + + return SWIG_OK; +} + +int V8Emitter::Dump(Node *n) +{ + /* Get the module name */ + String* module = Getattr(n,"name"); + + // write the swig banner + Swig_banner(f_wrap_cpp); + + Printv(f_wrap_cpp, f_runtime, "\n", 0); + Printv(f_wrap_cpp, f_header, "\n", 0); + Printv(f_wrap_cpp, f_class_templates, "\n", 0); + Printv(f_wrap_cpp, f_wrapper, "\n", 0); + + // compose the initializer function using a template + // filled with sub-parts + Template initializer(GetTemplate(V8_INITIALIZER)); + initializer.Replace(KW_MODULE_NAME, module) + .Replace(KW_NAME_SPACES, f_init_namespaces) + .Replace(KW_CLASS_TEMPLATES, f_init_class_templates) + .Replace(KW_WRAPPERS, f_init_wrappers) + .Replace(KW_INHERITANCE, f_init_inheritance) + .Replace(KW_REGISTER, f_init_register); + Wrapper_pretty_print(initializer.str(), f_wrap_cpp); + + return SWIG_OK; +} + +int V8Emitter::Close() +{ + Delete(f_runtime); + Delete(f_header); + Delete(f_class_templates); + Delete(f_wrapper); + Delete(f_init_namespaces); + Delete(f_init_class_templates); + Delete(f_init_wrappers); + Delete(f_init_inheritance); + Delete(f_init_register); + ::Close(f_wrap_cpp); + Delete(f_wrap_cpp); + + return SWIG_OK; +} + +int V8Emitter::SwitchContext(Node *n) +{ + String* scope = Swig_scopename_prefix(Getattr(n, "name")); + + if (scope) { + // if the scope is not yet registered + // create all scopes/namespaces recursively + if(!Getattr(namespaces, scope)) { + CreateNamespace(scope); + } + current_context = Getattr(namespaces, scope); + } else { + current_context = GLOBAL; + } + + return SWIG_OK; +} + +int V8Emitter::CreateNamespace(String* scope) { + String* parent_scope = Swig_scopename_prefix(scope); + + if (parent_scope && !Getattr(namespaces, parent_scope)) { + CreateNamespace(parent_scope); + } + + String* ns = Swig_string_mangle(scope); + Setattr(namespaces, scope, ns); + + // TODO: create namespace object and register it to the parent scope + Printf(f_init_namespaces, "create_ns(%s);\n", ns); + + return SWIG_OK; +} + +int V8Emitter::EnterClass(Node *n) +{ + current_classname_mangled = Swig_string_mangle(Getattr(n, "name")); + current_classname_unqualified = Swig_scopename_last(Getattr(n, "name")); + + // emit declaration of a v8 class template in part + Template t(GetTemplate(V8_DECL_CLASSTEMPLATE)); + t.Replace(KW_MANGLED_NAME, current_classname_mangled); + Printv(f_class_templates, t.str(), 0); + + // emit definition of v8 class template in part + Template t2(GetTemplate(V8_DEFINE_CLASSTEMPLATE)); + t2.Replace(KW_MANGLED_NAME, current_classname_mangled) + .Replace(KW_UNQUALIFIED_NAME, current_classname_unqualified); + Printv(f_init_class_templates, t2.str(), 0); + + return SWIG_OK; +} + +int V8Emitter::ExitClass(Node *n) +{ + // emit inheritance setup + Node* baseClass = GetBaseClass(n); + if(baseClass) { + Template t(GetTemplate(V8_INHERIT)); + t.Replace(KW_MANGLED_NAME, current_classname_mangled) + .Replace(KW_BASE_CLASS, Swig_string_mangle(Getattr(baseClass, "name"))); + Printv(f_init_inheritance, t.str(), 0); + } + + // emit registeration of class template + Template t(GetTemplate(V8_REGISTER_CLASS)); + t.Replace(KW_MANGLED_NAME, current_classname_mangled) + .Replace(KW_UNQUALIFIED_NAME, current_classname_unqualified) + .Replace(KW_CONTEXT, Swig_string_mangle(current_context)); + Printv(f_init_register, t.str(), 0); + + Delete(current_classname_mangled); + Delete(current_classname_unqualified); + current_classname_mangled = 0; + current_classname_unqualified = 0; + + return SWIG_OK; +} + +int V8Emitter::EnterVariable(Node* n) +{ + current_variable_unqualified = Swig_scopename_last(Getattr(n, "name")); + if(GetFlag(n, "ismember")) { + current_variable_mangled = NewString(""); + Printf(current_variable_mangled, "%s_%s", current_classname_mangled, current_variable_unqualified); + } else { + current_variable_mangled = Swig_string_mangle(Getattr(n, "name")); + } + + return SWIG_OK; +} + +int V8Emitter::ExitVariable(Node* n) +{ + + // TODO: Register variable in context + + Delete(current_variable_mangled); + Delete(current_variable_unqualified); + current_variable_mangled = 0; + current_variable_unqualified = 0; + + return SWIG_OK; +} + +int V8Emitter::EnterFunction(Node* n) +{ + current_function_unqualified = Swig_scopename_last(Getattr(n, "name")); + if(GetFlag(n, "ismember")) { + current_function_mangled = NewString(""); + Printf(current_function_mangled, "%s_%s", current_classname_mangled, current_function_unqualified); + } else { + current_function_mangled = Swig_string_mangle(Getattr(n, "name")); + } + + return SWIG_OK; +} + +int V8Emitter::ExitFunction(Node* n) +{ + // TODO: Register function in context + + Delete(current_function_mangled); + Delete(current_function_unqualified); + current_function_mangled = 0; + current_function_unqualified = 0; + + return SWIG_OK; +} + +int V8Emitter::EmitCtor(Node* n) +{ + // TODO: + // - handle overloaded ctors using a dispatcher + // - marshal inputs + Template t(GetTemplate(V8_CTOR_WRAPPER)); + + ParmList *params = Getattr(n,"parms"); + String* action = Getattr(n, "wrap:action"); + String* input = NewString(""); + + emit_parameter_variables(params, current_wrapper); + emit_attach_parmmaps(params, current_wrapper); + + t.Replace(KW_MANGLED_NAME, current_classname_mangled) + .Replace(KW_UNQUALIFIED_NAME, current_classname_unqualified) + .Replace(KW_LOCALS, current_wrapper->locals) + .Replace(KW_ACTION, action) + .Replace(KW_MARSHAL_INPUT, input); + + Wrapper_pretty_print(t.str(), f_wrapper); + + return SWIG_OK; +} + +int V8Emitter::EmitDtor(Node* n) +{ + // TODO: + // find out how to register a dtor in v8 + + Printv(f_wrapper, "/* TODO: Wrap dtor */\n", 0); + + return SWIG_OK; +} + +int V8Emitter::EmitGetter(Node *n, bool is_member) { + Template t(GetTemplate(V8_GETTER)); + + Setattr(n, "wrap:name", Getattr(n, "sym:name")); + Printf(current_wrapper->locals, "%s result;\n", SwigType_str(Getattr(n, "type"), 0)); + + String* action = emit_action(n); + String* output = NewString("// TODO: marshal output.\n ret = v8::Undefined();"); + + t.Replace(KW_MANGLED_NAME, current_variable_mangled) + .Replace(KW_LOCALS, current_wrapper->locals) + .Replace(KW_ACTION, action) + .Replace(KW_MARSHAL_OUTPUT, output); + + Wrapper_pretty_print(t.str(), f_wrapper); + + Delete(output); + + return SWIG_OK; +} + +int V8Emitter::EmitSetter(Node* n, bool is_member) +{ + Template t(GetTemplate(V8_SETTER)); + + Setattr(n, "wrap:name", Getattr(n, "sym:name")); + ParmList *params = Getattr(n,"parms"); + + emit_parameter_variables(params, current_wrapper); + emit_attach_parmmaps(params, current_wrapper); + + String* action = emit_action(n); + String* input = NewString("// TODO: marshal input.\n"); + + t.Replace(KW_MANGLED_NAME, current_variable_mangled) + .Replace(KW_LOCALS, current_wrapper->locals) + .Replace(KW_ACTION, action) + .Replace(KW_MARSHAL_INPUT, input); + + Wrapper_pretty_print(t.str(), f_wrapper); + + Delete(input); + + return SWIG_OK; +} + + +int V8Emitter::EmitFunction(Node* n, bool is_member) +{ + Template t(GetTemplate(V8_FUNCTION)); + + Setattr(n, "wrap:name", Getattr(n, "sym:name")); + ParmList *params = Getattr(n,"parms"); + + emit_parameter_variables(params, current_wrapper); + emit_attach_parmmaps(params, current_wrapper); + Printf(current_wrapper->locals, "%s result;\n", SwigType_str(Getattr(n, "type"), 0)); + + + String* input = NewString("// TODO: marshal input"); + String* action = emit_action(n); + String* output = NewString("// TODO: marshal output.\n ret = v8::Undefined();"); + + t.Replace(KW_MANGLED_NAME, current_function_mangled) + .Replace(KW_LOCALS, current_wrapper->locals) + .Replace(KW_ACTION, action) + .Replace(KW_MARSHAL_INPUT, input) + .Replace(KW_MARSHAL_OUTPUT, output); + + Wrapper_pretty_print(t.str(), f_wrapper); + + Delete(input); + Delete(output); + + return SWIG_OK; +} + +JSEmitter* create_v8_emitter() +{ + return new V8Emitter(); +} diff --git a/Source/Modules/javascript_v8.h b/Source/Modules/javascript_v8.h new file mode 100644 index 000000000..bb190a71b --- /dev/null +++ b/Source/Modules/javascript_v8.h @@ -0,0 +1,77 @@ +#ifndef JAVASCRIPT_V8_H +#define JAVASCRIPT_V8_H + +#include "javascript_emitter.h" + +class V8Emitter: public JSEmitter { + +public: + + V8Emitter(); + + virtual ~V8Emitter(); + + virtual int Initialize(Node *n); + + virtual int Dump(Node *n); + + virtual int Close(); + + virtual int SwitchContext(Node *n); + + virtual int EnterClass(Node *n); + + virtual int ExitClass(Node *n); + + virtual int EnterVariable(Node *n); + + virtual int ExitVariable(Node *n); + + virtual int EnterFunction(Node *n); + + virtual int ExitFunction(Node *n); + +protected: + + int CreateNamespace(String* scope); + + virtual int EmitCtor(Node *n); + + virtual int EmitDtor(Node *n); + + virtual int EmitFunction(Node *n, bool is_member); + + virtual int EmitGetter(Node *n, bool is_member); + + virtual int EmitSetter(Node *n, bool is_member); + +private: + + File *f_runtime; + File *f_header; + File *f_class_templates; + File *f_wrapper; + + File *f_init_namespaces; + File *f_init_class_templates; + File *f_init_wrappers; + File *f_init_inheritance; + File *f_init_register; + + // the output cpp file + File *f_wrap_cpp; + + // state variables + String* current_context; + String* current_classname_mangled; + String* current_classname_unqualified; + String* current_variable_mangled; + String* current_variable_unqualified; + String* current_function_mangled; + String* current_function_unqualified; + + String* GLOBAL; + Hash* namespaces; +}; + +#endif // JAVASCRIPT_V8_H