* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at https://www.swig.org/legal.html.
*
* javascript.cxx
*
* Javascript language module for SWIG.
* ----------------------------------------------------------------------------- */
#include "swigmod.h"
#include "cparse.h"
* Enables extra debugging information in typemaps.
*/
static bool js_template_enable_debug = false;
#define ERR_MSG_ONLY_ONE_ENGINE_PLEASE "Only one engine can be specified at a time."
#define NAME "name"
#define NAME_MANGLED "name_mangled"
#define INDEX "idx"
#define TYPE "type"
#define TYPE_MANGLED "type_mangled"
#define WRAPPER_NAME "wrapper"
#define IS_IMMUTABLE "is_immutable"
#define IS_STATIC "is_static"
#define IS_ABSTRACT "is_abstract"
#define IS_WRAPPED "is_wrapped"
#define GETTER "getter"
#define SETTER "setter"
#define PARENT "parent"
#define PARENT_MANGLED "parent_mangled"
#define CTOR "ctor"
#define CTOR_WRAPPERS "ctor_wrappers"
#define CTOR_DISPATCHERS "ctor_dispatchers"
#define DTOR "dtor"
#define ARGCOUNT "wrap:argc"
#define ARGREQUIRED "wrap:argmin"
#define HAS_TEMPLATES "has_templates"
#define FORCE_CPP "force_cpp"
#define RESET true
#define CREATE_NAMESPACES "create_namespaces"
#define REGISTER_NAMESPACES "register_namespaces"
#define INITIALIZER "initializer"
#define MEMBER_VARIABLES "member_variables"
#define MEMBER_FUNCTIONS "member_functions"
#define STATIC_FUNCTIONS "static_functions"
#define STATIC_VARIABLES "static_variables"
* A convenience class to manage state variables for emitters.
* The implementation delegates to SWIG Hash DOHs and provides
* named sub-hashes for class, variable, and function states.
*/
class JSEmitterState {
public:
JSEmitterState();
~JSEmitterState();
DOH *globals();
DOH *globals(const char *key, DOH *initial = 0);
DOH *clazz(bool reset = false);
DOH *clazz(const char *key, DOH *initial = 0);
DOH *function(bool reset = false);
DOH *function(const char *key, DOH *initial = 0);
DOH *variable(bool reset = false);
DOH *variable(const char *key, DOH *initial = 0);
static int IsSet(DOH *val);
private:
DOH *getState(const char *key, bool reset = false);
Hash *globalHash;
};
* A convenience class that wraps a code snippet used as template
* for code generation.
*/
class Template {
public:
Template(const String *code);
Template(const String *code, const String *templateName);
Template(const Template & other);
~Template();
String *str();
Template & replace(const String *pattern, const String *repl);
Template & print(DOH *doh);
Template & pretty_print(DOH *doh);
void operator=(const Template & t);
Template & trim();
private:
String *code;
String *templateName;
};
* JSEmitter represents an abstraction of javascript code generators
* for different javascript engines.
**/
class JSEmitter {
protected:
typedef JSEmitterState State;
enum MarshallingMode {
Setter,
Getter,
Ctor,
Function
};
public:
enum JSEngine {
JavascriptCore,
V8,
NodeJS,
NAPI
};
JSEmitter(JSEngine engine);
virtual ~ JSEmitter();
* Opens output files and temporary output DOHs.
*/
virtual int initialize(Node *n);
* Writes all collected code into the output file(s).
*/
virtual int dump(Node *n) = 0;
* Cleans up all open output DOHs.
*/
virtual int close() = 0;
* Switches the context for code generation.
*
* Classes, global variables and global functions may need to
* be registered in certain static tables.
* This method should be used to switch output DOHs correspondingly.
*/
virtual int switchNamespace(Node *);
* Invoked at the beginning of the classHandler.
*/
virtual int enterClass(Node *);
* Invoked at the end of the classHandler.
*/
virtual int exitClass(Node *) {
return SWIG_OK;
}
* Invoked at the beginning of the variableHandler.
*/
virtual int enterVariable(Node *);
* Invoked at the end of the variableHandler.
*/
virtual int exitVariable(Node *) {
return SWIG_OK;
}
* Invoked at the beginning of the functionHandler.
*/
virtual int enterFunction(Node *);
* Invoked at the end of the functionHandler.
*/
virtual int exitFunction(Node *) {
return SWIG_OK;
}
* Invoked by functionWrapper callback after call to Language::functionWrapper.
*/
virtual int emitWrapperFunction(Node *n);
* Invoked by nativeWrapper callback
*/
virtual int emitNativeFunction(Node *n);
* Invoked from constantWrapper after call to Language::constantWrapper.
**/
virtual int emitConstant(Node *n);
* Registers a given code snippet for a given key name.
*
* This method is called by the fragmentDirective handler
* of the JAVASCRIPT language module.
**/
int registerTemplate(const String *name, const String *code);
* Retrieve the code template registered for a given name.
*/
Template getTemplate(const String *name);
State & getState();
protected:
* Helper function for detecting if the constructor Node does not use a name that matches
* the expected name for a constructor. Occurs when %rename is used for just a constructor
* or %template instantiates a templated constructor with a different name to the class.
*/
bool isRenamedConstructor(Node *n);
* Generates code for a constructor function.
*/
virtual int emitCtor(Node *n);
* Generates code for a destructor function.
*/
virtual int emitDtor(Node *n);
* Generates code for a function.
*/
virtual int emitFunction(Node *n, bool is_member, bool is_static);
virtual int emitFunctionDispatcher(Node *n, bool );
* Generates code for a getter function.
*/
virtual int emitGetter(Node *n, bool is_member, bool is_static);
* Generates code for a setter function.
*/
virtual int emitSetter(Node *n, bool is_member, bool is_static);
virtual void marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static) = 0;
virtual String *emitInputTypemap(Node *n, Parm *params, Wrapper *wrapper, String *arg);
virtual String *emitCheckTypemap(Node *n, Parm *params, Wrapper *wrapper, String *arg);
virtual void marshalOutput(Node *n, ParmList *params, Wrapper *wrapper, String *actioncode, const String *cresult = 0, bool emitReturnVariable = true);
virtual void emitCleanupCode(Node *n, Wrapper *wrapper, ParmList *params);
* Helper function to retrieve the first parent class node.
*/
Node *getBaseClass(Node *n);
virtual int createNamespace(String *scope);
virtual Hash *createNamespaceEntry(const char *name, const char *parent, const char *parent_mangled);
virtual int emitNamespaces() = 0;
virtual const char *getFunctionTemplate(bool);
virtual const char *getFunctionDispatcherTemplate(bool);
virtual const char *getOverloadedFunctionTemplate(bool);
virtual const char *getSetterTemplate(bool);
virtual const char *getGetterTemplate(bool);
protected:
JSEngine engine;
Hash *templates;
State state;
Hash *namespaces;
Hash *current_namespace;
String *defaultResultName;
File *f_wrappers;
};
JSEmitter *swig_javascript_create_JSCEmitter();
JSEmitter *swig_javascript_create_V8Emitter();
JSEmitter *swig_javascript_create_NodeJSEmitter();
JSEmitter *swig_javascript_create_NAPIEmitter();
* JAVASCRIPT: SWIG module implementation
**********************************************************************/
class JAVASCRIPT:public Language {
public:
JAVASCRIPT():emitter(NULL) {
}
~JAVASCRIPT() {
delete emitter;
}
virtual int functionHandler(Node *n);
virtual int globalfunctionHandler(Node *n);
virtual int variableHandler(Node *n);
virtual int globalvariableHandler(Node *n);
virtual int staticmemberfunctionHandler(Node *n);
virtual int classHandler(Node *n);
virtual int functionWrapper(Node *n);
virtual int constantWrapper(Node *n);
virtual int nativeWrapper(Node *n);
virtual void main(int argc, char *argv[]);
virtual int top(Node *n);
* Registers all %fragments assigned to section "templates".
**/
virtual int fragmentDirective(Node *n);
public:
virtual String *getNSpace() const;
private:
JSEmitter *emitter;
};
* functionWrapper()
*
* Low level code generator for functions
* --------------------------------------------------------------------- */
int JAVASCRIPT::functionWrapper(Node *n) {
emitter->emitWrapperFunction(n);
return SWIG_OK;
}
* functionHandler()
*
* Function handler for generating wrappers for functions
* --------------------------------------------------------------------- */
int JAVASCRIPT::functionHandler(Node *n) {
if (GetFlag(n, "isextension") == 1) {
SetFlag(n, "ismember");
}
emitter->enterFunction(n);
Language::functionHandler(n);
emitter->exitFunction(n);
return SWIG_OK;
}
* globalfunctionHandler()
*
* Function handler for generating wrappers for functions
* --------------------------------------------------------------------- */
int JAVASCRIPT::globalfunctionHandler(Node *n) {
emitter->switchNamespace(n);
Language::globalfunctionHandler(n);
return SWIG_OK;
}
* staticmemberfunctionHandler()
*
* Function handler for generating wrappers for static member functions
* --------------------------------------------------------------------- */
int JAVASCRIPT::staticmemberfunctionHandler(Node *n) {
* Note: storage=static is removed by Language::staticmemberfunctionHandler.
* So, don't rely on that after here. Instead use the state variable which is
* set by JSEmitter::enterFunction().
*/
Language::staticmemberfunctionHandler(n);
return SWIG_OK;
}
* variableHandler()
*
* Function handler for generating wrappers for variables
* --------------------------------------------------------------------- */
int JAVASCRIPT::variableHandler(Node *n) {
emitter->enterVariable(n);
Language::variableHandler(n);
emitter->exitVariable(n);
return SWIG_OK;
}
* globalvariableHandler()
*
* Function handler for generating wrappers for global variables
* --------------------------------------------------------------------- */
int JAVASCRIPT::globalvariableHandler(Node *n) {
emitter->switchNamespace(n);
Language::globalvariableHandler(n);
return SWIG_OK;
}
* constantHandler()
*
* Function handler for generating wrappers for constants
* --------------------------------------------------------------------- */
int JAVASCRIPT::constantWrapper(Node *n) {
emitter->switchNamespace(n);
if (Equal(Getattr(n, "kind"), "function")) {
return SWIG_OK;
}
emitter->emitConstant(n);
return SWIG_OK;
}
* nativeWrapper()
*
* Function wrapper for generating placeholders for native functions
* --------------------------------------------------------------------- */
int JAVASCRIPT::nativeWrapper(Node *n) {
emitter->emitNativeFunction(n);
return SWIG_OK;
}
* classHandler()
*
* Function handler for generating wrappers for class
* --------------------------------------------------------------------- */
int JAVASCRIPT::classHandler(Node *n) {
emitter->switchNamespace(n);
emitter->enterClass(n);
Language::classHandler(n);
emitter->exitClass(n);
return SWIG_OK;
}
int JAVASCRIPT::fragmentDirective(Node *n) {
String *section = Getattr(n, "section");
if (Equal(section, "templates") && !ImportMode) {
emitter->registerTemplate(Getattr(n, "value"), Getattr(n, "code"));
} else {
return Language::fragmentDirective(n);
}
return SWIG_OK;
}
String *JAVASCRIPT::getNSpace() const {
return Language::getNSpace();
}
* top()
*
* Function handler for processing top node of the parse tree
* Wrapper code generation essentially starts from here
* --------------------------------------------------------------------- */
int JAVASCRIPT::top(Node *n) {
emitter->initialize(n);
Language::top(n);
emitter->dump(n);
emitter->close();
return SWIG_OK;
}
static const char *usage = (char *)"\
Javascript Options (available with -javascript)\n\
-jsc - creates a JavascriptCore extension \n\
-v8 - creates a v8 extension \n\
-node - creates a node.js extension \n\
-napi - creates a NAPI extension \n\
-debug-codetemplates - generates information about the origin of code templates\n";
* main()
*
* Entry point for the JAVASCRIPT module
* --------------------------------------------------------------------- */
void JAVASCRIPT::main(int argc, char *argv[]) {
SWIG_library_directory("javascript");
int engine = -1;
for (int i = 1; i < argc; i++) {
if (argv[i]) {
if (strcmp(argv[i], "-v8") == 0) {
if (engine != -1) {
Printf(stderr, ERR_MSG_ONLY_ONE_ENGINE_PLEASE);
Exit(EXIT_FAILURE);
}
Swig_mark_arg(i);
engine = JSEmitter::V8;
} else if (strcmp(argv[i], "-jsc") == 0) {
if (engine != -1) {
Printf(stderr, ERR_MSG_ONLY_ONE_ENGINE_PLEASE);
Exit(EXIT_FAILURE);
}
Swig_mark_arg(i);
engine = JSEmitter::JavascriptCore;
} else if (strcmp(argv[i], "-node") == 0) {
if (engine != -1) {
Printf(stderr, ERR_MSG_ONLY_ONE_ENGINE_PLEASE);
Exit(EXIT_FAILURE);
}
Swig_mark_arg(i);
engine = JSEmitter::NodeJS;
} else if (strcmp(argv[i], "-napi") == 0) {
if (engine != -1) {
Printf(stderr, ERR_MSG_ONLY_ONE_ENGINE_PLEASE);
Exit(EXIT_FAILURE);
}
Swig_mark_arg(i);
engine = JSEmitter::NAPI;
} else if (strcmp(argv[i], "-debug-codetemplates") == 0) {
Swig_mark_arg(i);
js_template_enable_debug = true;
} else if (strcmp(argv[i], "-help") == 0) {
fputs(usage, stdout);
return;
}
}
}
switch (engine) {
case JSEmitter::NodeJS:
case JSEmitter::V8:
{
emitter = swig_javascript_create_V8Emitter();
Preprocessor_define("SWIG_JAVASCRIPT_V8 1", 0);
SWIG_library_directory("javascript/v8");
if (!cparse_cplusplus) {
Swig_cparse_cplusplusout(1);
}
if (engine == JSEmitter::NodeJS) {
Preprocessor_define("BUILDING_NODE_EXTENSION 1", 0);
}
break;
}
case JSEmitter::JavascriptCore:
{
emitter = swig_javascript_create_JSCEmitter();
Preprocessor_define("SWIG_JAVASCRIPT_JSC 1", 0);
SWIG_library_directory("javascript/jsc");
break;
}
case JSEmitter::NAPI:
{
emitter = swig_javascript_create_NAPIEmitter();
Preprocessor_define("SWIG_JAVASCRIPT_NAPI 1", 0);
SWIG_library_directory("javascript/napi");
Preprocessor_define("BUILDING_NODE_EXTENSION 1", 0);
if (!cparse_cplusplus) {
Swig_cparse_cplusplusout(1);
}
break;
}
default:
{
Printf(stderr, "SWIG Javascript: Unknown engine. Please specify one of '-jsc', '-v8', '-node' or '-napi'.\n");
Exit(EXIT_FAILURE);
break;
}
}
Preprocessor_define("SWIGJAVASCRIPT 1", 0);
SWIG_config_file("javascript.swg");
allow_overloading();
}
* swig_javascript() - Instantiate module
* ----------------------------------------------------------------------------- */
static Language *new_swig_javascript() {
return new JAVASCRIPT();
}
extern "C" Language *swig_javascript(void) {
return new_swig_javascript();
}
* Emitter implementations
**********************************************************************/
* JSEmitter()
* ----------------------------------------------------------------------------- */
JSEmitter::JSEmitter(JSEmitter::JSEngine engine)
: engine(engine), templates(NewHash()), namespaces(NULL), current_namespace(NULL), defaultResultName(NewString("result")), f_wrappers(NULL) {
}
* ~JSEmitter()
* ----------------------------------------------------------------------------- */
JSEmitter::~JSEmitter() {
Delete(templates);
}
* JSEmitter::RegisterTemplate() : Registers a code template
*
* Note: this is used only by JAVASCRIPT::fragmentDirective().
* ----------------------------------------------------------------------------- */
int JSEmitter::registerTemplate(const String *name, const String *code) {
if (!State::IsSet(state.globals(HAS_TEMPLATES))) {
SetFlag(state.globals(), HAS_TEMPLATES);
}
return Setattr(templates, name, code);
}
* JSEmitter::getTemplate() : Provides a registered code template
* ----------------------------------------------------------------------------- */
Template JSEmitter::getTemplate(const String *name) {
String *templ = Getattr(templates, name);
if (!templ) {
Printf(stderr, "Could not find template %s\n.", name);
Exit(EXIT_FAILURE);
}
Template t(templ, name);
return t;
}
JSEmitterState & JSEmitter::getState() {
return state;
}
int JSEmitter::initialize(Node * ) {
if (namespaces != NULL) {
Delete(namespaces);
}
namespaces = NewHash();
Hash *global_namespace = createNamespaceEntry("exports", 0, 0);
Setattr(namespaces, "::", global_namespace);
current_namespace = global_namespace;
f_wrappers = NewString("");
return SWIG_OK;
}
* JSEmitter::getBaseClass() : the node of the base class or NULL
*
* Note: the first base class is provided. Multiple inheritance is not
* supported.
* ----------------------------------------------------------------------------- */
Node *JSEmitter::getBaseClass(Node *n) {
List *baselist = Getattr(n, "bases");
if (baselist) {
Iterator base = First(baselist);
while (base.item && GetFlag(base.item, "feature:ignore")) {
base = Next(base);
}
return base.item;
}
return NULL;
}
* JSEmitter::emitWrapperFunction() : dispatches emitter functions.
*
* This allows having small sized, dedicated emitting functions.
* All state dependent branching is done here.
* ----------------------------------------------------------------------------- */
int JSEmitter::emitWrapperFunction(Node *n) {
int ret = SWIG_OK;
String *kind = Getattr(n, "kind");
if (kind) {
if (Equal(kind, "function")
|| (Equal(kind, "variable") && Equal(Getattr(n, "view"), "globalfunctionHandler"))
) {
bool is_member = GetFlag(n, "ismember") != 0 || GetFlag(n, "feature:extend") != 0;
bool is_static = GetFlag(state.function(), IS_STATIC) != 0;
ret = emitFunction(n, is_member, is_static);
} else if (Cmp(kind, "variable") == 0) {
bool is_static = GetFlag(state.variable(), IS_STATIC) != 0;
if (GetFlag(n, "allocate:smartpointeraccess")) {
is_static = false;
}
bool is_member = GetFlag(n, "ismember") != 0;
bool is_setter = GetFlag(n, "memberset") != 0 || GetFlag(n, "varset") != 0;
bool is_getter = GetFlag(n, "memberget") != 0 || GetFlag(n, "varget") != 0;
if (is_setter) {
ret = emitSetter(n, is_member, is_static);
} else if (is_getter) {
ret = emitGetter(n, is_member, is_static);
}
} else {
Printf(stderr, "Warning: unsupported wrapper function type\n");
ret = SWIG_ERROR;
}
} else {
String *view = Getattr(n, "view");
if (Cmp(view, "constructorHandler") == 0) {
ret = emitCtor(n);
} else if (Cmp(view, "destructorHandler") == 0) {
ret = emitDtor(n);
} else {
Printf(stderr, "Warning: unsupported wrapper function type");
ret = SWIG_ERROR;
}
}
return ret;
}
int JSEmitter::emitNativeFunction(Node *n) {
String *wrapname = Getattr(n, "wrap:name");
enterFunction(n);
state.function(WRAPPER_NAME, wrapname);
exitFunction(n);
return SWIG_OK;
}
int JSEmitter::enterClass(Node *n) {
state.clazz(RESET);
state.clazz(NAME, Getattr(n, "sym:name"));
state.clazz("nspace", current_namespace);
String *mangled_name = NewString("");
Printf(mangled_name, "%s_%s", Getattr(current_namespace, NAME_MANGLED), Getattr(n, "sym:name"));
state.clazz(NAME_MANGLED, SwigType_manglestr(mangled_name));
Delete(mangled_name);
state.clazz(TYPE, NewString(Getattr(n, "classtype")));
String *type = SwigType_manglestr(Getattr(n, "classtypeobj"));
String *classtype_mangled = NewString("");
Printf(classtype_mangled, "p%s", type);
state.clazz(TYPE_MANGLED, classtype_mangled);
Delete(type);
String *ctor_wrapper = NewString("_wrap_new_veto_");
Append(ctor_wrapper, state.clazz(NAME));
state.clazz(CTOR, ctor_wrapper);
state.clazz(CTOR_DISPATCHERS, NewString(""));
state.clazz(DTOR, NewString("0"));
SetFlag(state.clazz(), IS_ABSTRACT);
return SWIG_OK;
}
int JSEmitter::enterFunction(Node *n) {
state.function(RESET);
state.function(NAME, Getattr(n, "sym:name"));
if (Equal(Getattr(n, "storage"), "static")) {
SetFlag(state.function(), IS_STATIC);
}
return SWIG_OK;
}
int JSEmitter::enterVariable(Node *n) {
state.variable(RESET);
if (Equal(Getattr(n, "view"), "memberconstantHandler")) {
state.variable(NAME, Getattr(n, "memberconstantHandler:sym:name"));
} else {
state.variable(NAME, Swig_scopename_last(Getattr(n, "sym:name")));
}
if (Equal(Getattr(n, "storage"), "static")) {
SetFlag(state.variable(), IS_STATIC);
}
if (Language::instance()->is_immutable(n)) {
SetFlag(state.variable(), IS_IMMUTABLE);
}
if (Equal(Getattr(n, "type"), "a().char")) {
SetFlag(state.variable(), IS_IMMUTABLE);
}
return SWIG_OK;
}
const char *JSEmitter::getFunctionTemplate(bool) {
return "js_function";
}
const char *JSEmitter::getFunctionDispatcherTemplate(bool) {
return "js_function_dispatcher";
}
const char *JSEmitter::getOverloadedFunctionTemplate(bool) {
return "js_overloaded_function";
}
const char *JSEmitter::getGetterTemplate(bool) {
return "js_getter";
}
const char *JSEmitter::getSetterTemplate(bool) {
return "js_setter";
}
bool JSEmitter::isRenamedConstructor(Node *n) {
Node *cls = parentNode(n);
if (!Equal(nodeType(cls), "class")) {
cls = parentNode(cls);
assert(Equal(nodeType(cls), "class"));
}
return !Equal(Getattr(n, "constructorHandler:sym:name"), Getattr(cls, "sym:name"));
}
int JSEmitter::emitCtor(Node *n) {
if (isRenamedConstructor(n))
return SWIG_ERROR;
Wrapper *wrapper = NewWrapper();
bool is_overloaded = GetFlag(n, "sym:overloaded") != 0;
Template t_ctor(getTemplate("js_ctor"));
String *iname = Getattr(n, "sym:name");
SwigType *returntype = Getattr(n, "type");
String *wrap_name = Swig_name_wrapper(iname);
if (is_overloaded) {
t_ctor = getTemplate("js_overloaded_ctor");
Append(wrap_name, Getattr(n, "sym:overname"));
}
Setattr(n, "wrap:name", wrap_name);
Setattr(state.clazz(), IS_ABSTRACT, 0);
ParmList *params = Getattr(n, "parms");
emit_parameter_variables(params, wrapper);
emit_attach_parmmaps(params, wrapper);
Printf(wrapper->locals, "%sresult;", SwigType_str(Getattr(n, "type"), 0));
marshalInputArgs(n, params, wrapper, Ctor, true, false);
String *action = emit_action(n);
Printv(wrapper->code, action, "\n", 0);
emitCleanupCode(n, wrapper, params);
bool isvoid = !Cmp(returntype, "void");
Replaceall(wrapper->code, "$isvoid", isvoid ? "1" : "0");
Replaceall(wrapper->code, "$symname", iname);
t_ctor.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", wrap_name)
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jslocals", wrapper->locals)
.replace("$jscode", wrapper->code)
.replace("$jsargcount", Getattr(n, ARGCOUNT))
.replace("$jsparent", state.clazz(PARENT_MANGLED))
.replace("$jsargrequired", Getattr(n, ARGREQUIRED))
.pretty_print(f_wrappers);
Template t_ctor_case(getTemplate("js_ctor_dispatch_case"));
t_ctor_case.replace("$jswrapper", wrap_name)
.replace("$jsargcount", Getattr(n, ARGCOUNT))
.replace("$jsargrequired", Getattr(n, ARGREQUIRED));
Append(state.clazz(CTOR_DISPATCHERS), t_ctor_case.str());
DelWrapper(wrapper);
if (is_overloaded) {
if (!Getattr(n, "sym:nextSibling")) {
String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name"));
Template t_mainctor(getTemplate("js_ctor_dispatcher"));
t_mainctor.replace("$jswrapper", wrap_name)
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsdispatchcases", state.clazz(CTOR_DISPATCHERS))
.replace("$jsparent", state.clazz(PARENT_MANGLED))
.pretty_print(f_wrappers);
state.clazz(CTOR, wrap_name);
}
} else {
state.clazz(CTOR, wrap_name);
}
return SWIG_OK;
}
int JSEmitter::emitDtor(Node *n) {
String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name"));
SwigType *type = state.clazz(TYPE);
String *p_classtype = SwigType_add_pointer(state.clazz(TYPE));
String *ctype = SwigType_lstr(p_classtype, "");
String *jsfree = NewString("");
* The problem is that in the case of an %extend to create a destructor for a struct to coordinate automatic memory cleanup with the Javascript collector,
* the SWIG function was not being generated. More specifically:
struct MyData {
%extend {
~MyData() {
FreeData($self);
}
}
};
%newobject CreateData;
struct MyData* CreateData(void);
%delobject FreeData;
void FreeData(struct MyData* the_data);
where the use case is something like:
var my_data = example.CreateData();
my_data = null;
This function was not being generated:
SWIGINTERN void delete_MyData(struct MyData *self){
FreeData(self);
}
I don't understand fully why it wasn't being generated. It just seems to happen in the Lua generator.
There is a comment about staticmemberfunctionHandler having an inconsistency and I tracked down dome of the SWIGINTERN void delete_*
code to that function in the Language base class.
The Ruby implementation seems to have an explicit check for if(Extend) and explicitly generates the code, so that's what I'm doing here.
The Ruby implementation does other stuff which I omit.
*/
if (Extend) {
String *wrap = Getattr(n, "wrap:code");
if (wrap) {
Printv(f_wrappers, wrap, NIL);
}
}
if (SwigType_isarray(type)) {
Printf(jsfree, "delete [] (%s)", ctype);
} else {
Printf(jsfree, "delete (%s)", ctype);
}
String *destructor_action = Getattr(n, "wrap:action");
Originally, it would use this fragment from javascriptcode.swg
%fragment ("JS_destructordefn", "templates")
%{
void _wrap_${classname_mangled}_finalize(JSObjectRef thisObject)
{
SWIG_PRV_DATA* t = (SWIG_PRV_DATA*)JSObjectGetPrivate(thisObject);
if(t && t->swigCMemOwn) free ((${type}*)t->swigCObject);
free(t);
}
%}
But for the above example case of %extend to define a destructor on a struct, we need to override the system to not call
free ((${type}*)t->swigCObject);
and substitute it with what the user has provided.
To solve this, I created a variation fragment called JS_destructoroverridedefn:
SWIG_PRV_DATA* t = (SWIG_PRV_DATA*)JSObjectGetPrivate(thisObject);
if(t && t->swigCMemOwn) {
${type}* arg1 = (${type}*)t->swigCObject;
${destructor_action}
}
free(t);
Based on what I saw in the Lua and Ruby modules, I use Getattr(n, "wrap:action")
to decide if the user has a preferred destructor action.
Based on that, I decide which fragment to use.
And in the case of the custom action, I substitute that action in.
I noticed that destructor_action has the form
delete_MyData(arg1);
The explicit arg1 is a little funny, so I structured the fragment to create a temporary variable called arg1 to make the generation easier.
This might suggest this solution misunderstands a more complex case.
Also, there is a problem where destructor_action is always true for me, even when not requesting %extend as above.
So this code doesn't actually quite work as I expect. The end result is that the code still works because
destructor_action calls free like the original template. The one caveat is the string in destructor_action casts to char* which is weird.
I think there is a deeper underlying SWIG issue because I don't think it should be char*. However, it doesn't really matter for free.
Maybe the fix for the destructor_action always true problem is that this is supposed to be embedded in the if(Extend) block above.
But I don't fully understand the conditions of any of these things, and since it works for the moment, I don't want to break more stuff.
*/
if (destructor_action) {
Template t_dtor = getTemplate("js_dtoroverride");
state.clazz(DTOR, wrap_name);
t_dtor.replace("${classname_mangled}", state.clazz(NAME_MANGLED))
.replace("$jswrapper", wrap_name)
.replace("$jsfree", jsfree)
.replace("$jstype", ctype);
t_dtor.replace("${destructor_action}", destructor_action);
Wrapper_pretty_print(t_dtor.str(), f_wrappers);
} else {
Template t_dtor = getTemplate("js_dtor");
state.clazz(DTOR, wrap_name);
t_dtor.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", wrap_name)
.replace("$jsfree", jsfree)
.replace("$jstype", ctype)
.pretty_print(f_wrappers);
}
Delete(p_classtype);
Delete(ctype);
Delete(jsfree);
return SWIG_OK;
}
int JSEmitter::emitGetter(Node *n, bool is_member, bool is_static) {
Wrapper *wrapper = NewWrapper();
Template t_getter(getTemplate(getGetterTemplate(is_member)));
String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name"));
Setattr(n, "wrap:name", wrap_name);
state.variable(GETTER, wrap_name);
ParmList *params = Getattr(n, "parms");
emit_parameter_variables(params, wrapper);
emit_attach_parmmaps(params, wrapper);
String *action = emit_action(n);
marshalInputArgs(n, params, wrapper, Getter, is_member, is_static);
marshalOutput(n, params, wrapper, action);
emitCleanupCode(n, wrapper, params);
t_getter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", wrap_name)
.replace("$jslocals", wrapper->locals)
.replace("$jscode", wrapper->code)
.pretty_print(f_wrappers);
DelWrapper(wrapper);
return SWIG_OK;
}
int JSEmitter::emitSetter(Node *n, bool is_member, bool is_static) {
if (State::IsSet(state.variable(IS_IMMUTABLE))) {
return SWIG_OK;
}
Wrapper *wrapper = NewWrapper();
Template t_setter(getTemplate(getSetterTemplate(is_member)));
String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name"));
Setattr(n, "wrap:name", wrap_name);
state.variable(SETTER, wrap_name);
ParmList *params = Getattr(n, "parms");
emit_parameter_variables(params, wrapper);
emit_attach_parmmaps(params, wrapper);
String *action = emit_action(n);
marshalInputArgs(n, params, wrapper, Setter, is_member, is_static);
Append(wrapper->code, action);
emitCleanupCode(n, wrapper, params);
t_setter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", wrap_name)
.replace("$jslocals", wrapper->locals)
.replace("$jscode", wrapper->code)
.pretty_print(f_wrappers);
DelWrapper(wrapper);
return SWIG_OK;
}
* JSEmitter::emitConstant() : triggers code generation for constants
* ----------------------------------------------------------------------------- */
int JSEmitter::emitConstant(Node *n) {
if (!State::IsSet(state.globals(HAS_TEMPLATES))) {
return SWIG_ERROR;
}
Wrapper *wrapper = NewWrapper();
SwigType *type = Getattr(n, "type");
String *iname = Getattr(n, "sym:name");
String *wname = Swig_name_get(Getattr(current_namespace, NAME_MANGLED), iname);
String *value = Getattr(n, "value");
if (State::IsSet(state.globals(FORCE_CPP)) && Getattr(n, "cppvalue") != NULL) {
value = Getattr(n, "cppvalue");
}
bool is_member = GetFlag(n, "ismember");
Template t_getter(getTemplate(getGetterTemplate(is_member)));
enterVariable(n);
state.variable(GETTER, wname);
Setattr(n, "wrap:name", wname);
if (SwigType_type(type) == T_MPOINTER) {
String *mpointer_wname = NewString("");
Printf(mpointer_wname, "_wrapConstant_%s", iname);
Setattr(n, "memberpointer:constant:wrap:name", mpointer_wname);
String *str = SwigType_str(type, mpointer_wname);
Printf(f_wrappers, "static %s = %s;\n", str, value);
Delete(str);
value = mpointer_wname;
}
marshalOutput(n, 0, wrapper, NewString(""), value, false);
t_getter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", wname)
.replace("$jslocals", wrapper->locals)
.replace("$jscode", wrapper->code)
.pretty_print(f_wrappers);
exitVariable(n);
SetFlag(n, "constant");
DelWrapper(wrapper);
return SWIG_OK;
}
int JSEmitter::emitFunction(Node *n, bool is_member, bool is_static) {
Wrapper *wrapper = NewWrapper();
Template t_function(getTemplate(getFunctionTemplate(is_member)));
bool is_overloaded = GetFlag(n, "sym:overloaded") != 0;
String *iname = Getattr(n, "sym:name");
SwigType *returntype = Getattr(n, "type");
String *wrap_name = Swig_name_wrapper(iname);
if (is_overloaded) {
t_function = getTemplate(getOverloadedFunctionTemplate(is_member));
Append(wrap_name, Getattr(n, "sym:overname"));
}
Setattr(n, "wrap:name", wrap_name);
state.function(WRAPPER_NAME, wrap_name);
ParmList *params = Getattr(n, "parms");
emit_parameter_variables(params, wrapper);
emit_attach_parmmaps(params, wrapper);
marshalInputArgs(n, params, wrapper, Function, is_member, is_static);
String *action = emit_action(n);
marshalOutput(n, params, wrapper, action);
emitCleanupCode(n, wrapper, params);
bool isvoid = !Cmp(returntype, "void");
Replaceall(wrapper->code, "$isvoid", isvoid ? "1" : "0");
Replaceall(wrapper->code, "$symname", iname);
t_function.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", wrap_name)
.replace("$jslocals", wrapper->locals)
.replace("$jscode", wrapper->code)
.replace("$jsargcount", Getattr(n, ARGCOUNT))
.replace("$jsargrequired", Getattr(n, ARGREQUIRED))
.pretty_print(f_wrappers);
DelWrapper(wrapper);
return SWIG_OK;
}
int JSEmitter::emitFunctionDispatcher(Node *n, bool is_member) {
Wrapper *wrapper = NewWrapper();
Node *sibl = n;
while (Getattr(sibl, "sym:previousSibling"))
sibl = Getattr(sibl, "sym:previousSibling");
do {
String *siblname = Getattr(sibl, "wrap:name");
if (siblname) {
Template t_dispatch_case = getTemplate("js_function_dispatch_case");
t_dispatch_case.replace("$jswrapper", siblname)
.replace("$jsargcount", Getattr(sibl, ARGCOUNT))
.replace("$jsargrequired", Getattr(sibl, ARGREQUIRED));
Append(wrapper->code, t_dispatch_case.str());
}
} while ((sibl = Getattr(sibl, "sym:nextSibling")));
Template t_function(getTemplate(getFunctionDispatcherTemplate(is_member)));
String *wrap_name = NewString(Getattr(n, "wrap:name"));
String *overname = Getattr(n, "sym:overname");
Node *methodclass = Swig_methodclass(n);
String *class_name = Getattr(methodclass, "sym:name");
int l1 = Len(wrap_name);
int l2 = Len(overname);
Delslice(wrap_name, l1 - l2, l1);
String *new_string = NewStringf("%s_%s", class_name, wrap_name);
String *final_wrap_name = Swig_name_wrapper(new_string);
Setattr(n, "wrap:name", final_wrap_name);
state.function(WRAPPER_NAME, final_wrap_name);
t_function.replace("$jslocals", wrapper->locals)
.replace("$jscode", wrapper->code);
t_function.replace("$jswrapper", final_wrap_name)
.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.function(NAME))
.pretty_print(f_wrappers);
DelWrapper(wrapper);
return SWIG_OK;
}
String *JSEmitter::emitInputTypemap(Node *n, Parm *p, Wrapper *wrapper, String *arg) {
String *code = NewString("");
String *tm = Getattr(p, "tmap:in");
String *tm_def = Getattr(p, "tmap:default");
SwigType *type = Getattr(p, "type");
int argmin = -1;
int argidx = -1;
bool is_optional = false;
if (Getattr(n, ARGREQUIRED)) {
argmin = GetInt(n, ARGREQUIRED);
}
if (Getattr(p, INDEX)) {
argidx = GetInt(p, INDEX);
}
if (tm_def != NULL) {
is_optional = true;
}
if (argmin >= 0 && argidx >= 0 && argidx >= argmin) {
is_optional = true;
}
if (is_optional && Getattr(p, INDEX) == NULL) {
Printf(stderr, "Argument %s in %s cannot be a default argument\n", Getattr(p, NAME), state.function(NAME));
return SWIG_ERROR;
}
if (is_optional) {
Template t_check_default(getTemplate("js_check_arg"));
t_check_default.replace("$jsarg", Getattr(p, INDEX)).pretty_print(code);
Printf(code, "{\n");
}
if (tm != NULL) {
Replaceall(tm, "$input", arg);
Setattr(p, "emit:input", arg);
if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) {
Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN");
} else {
Replaceall(tm, "$disown", "0");
}
Replaceall(tm, "$symname", Getattr(n, "sym:name"));
if (!checkAttribute(p, "tmap:in:noblock", "1")) {
Printf(code, "{\n");
}
Printf(code, "%s", tm);
if (!checkAttribute(p, "tmap:in:noblock", "1")) {
Printf(code, "\n}\n");
}
} else {
Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(type, 0));
return NULL;
}
if (is_optional) {
Printf(code, "}\n");
}
if (!checkAttribute(p, "tmap:in:numinputs", "0")) {
Append(wrapper->code, code);
}
return code;
}
String *JSEmitter::emitCheckTypemap(Node *, Parm *p, Wrapper *wrapper, String *arg) {
String *tm = Getattr(p, "tmap:check");
if (tm != NULL) {
Replaceall(tm, "$input", arg);
Printf(wrapper->code, "%s\n", tm);
}
return tm;
}
void JSEmitter::marshalOutput(Node *n, ParmList *params, Wrapper *wrapper, String *actioncode, const String *cresult, bool emitReturnVariable) {
SwigType *type = Getattr(n, "type");
String *tm;
Parm *p;
if (emitReturnVariable)
emit_return_variable(n, type, wrapper);
if (cresult == 0)
cresult = defaultResultName;
tm = Swig_typemap_lookup_out("out", n, cresult, wrapper, actioncode);
bool should_own = GetFlag(n, "feature:new") != 0;
if (tm) {
Replaceall(tm, "$objecttype", Swig_scopename_last(SwigType_str(SwigType_strip_qualifiers(type), 0)));
if (should_own) {
Replaceall(tm, "$owner", "SWIG_POINTER_OWN");
} else {
Replaceall(tm, "$owner", "0");
}
Append(wrapper->code, tm);
if (Len(tm) > 0) {
Printf(wrapper->code, "\n");
}
} else {
Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(type, 0), Getattr(n, "name"));
}
if (params) {
for (p = params; p;) {
if ((tm = Getattr(p, "tmap:argout"))) {
Replaceall(tm, "$input", Getattr(p, "emit:input"));
Printv(wrapper->code, tm, "\n", NIL);
p = Getattr(p, "tmap:argout:next");
} else {
p = nextSibling(p);
}
}
}
Replaceall(wrapper->code, "$result", "jsresult");
}
void JSEmitter::emitCleanupCode(Node *n, Wrapper *wrapper, ParmList *params) {
Parm *p;
String *tm;
for (p = params; p;) {
if ((tm = Getattr(p, "tmap:freearg"))) {
Replaceall(tm, "$input", Getattr(p, "emit:input"));
Printv(wrapper->code, tm, "\n", NIL);
p = Getattr(p, "tmap:freearg:next");
} else {
p = nextSibling(p);
}
}
if (GetFlag(n, "feature:new")) {
tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0);
if (tm != NIL) {
Printv(wrapper->code, tm, "\n", NIL);
}
}
if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) {
Printf(wrapper->code, "%s\n", tm);
Delete(tm);
}
}
int JSEmitter::switchNamespace(Node *n) {
if (GetFlag(n, "ismember")) {
return SWIG_OK;
}
if (!GetFlag(n, "feature:nspace")) {
current_namespace = Getattr(namespaces, "::");
return SWIG_OK;
}
#if 0
JAVASCRIPT *lang = static_cast<JAVASCRIPT*>(Language::instance());
String *_nspace = lang->getNSpace();
if (!Equal(nspace, _nspace)) {
Printf(stdout, "##### Custom vs Language::getNSpace(): %s | %s\n", nspace, _nspace);
}
#endif
String *nspace = Getattr(n, "sym:nspace");
if (nspace == NULL) {
nspace = Swig_scopename_prefix(Getattr(n, "name"));
}
if (nspace == NULL) {
current_namespace = Getattr(namespaces, "::");
return SWIG_OK;
}
String *scope = NewString(nspace);
Replaceall(scope, ".", "::");
if (!Getattr(namespaces, scope)) {
createNamespace(scope);
}
current_namespace = Getattr(namespaces, scope);
return SWIG_OK;
}
int JSEmitter::createNamespace(String *scope) {
String *parent_scope = Swig_scopename_prefix(scope);
Hash *parent_namespace;
if (parent_scope == 0) {
parent_namespace = Getattr(namespaces, "::");
} else if (!Getattr(namespaces, parent_scope)) {
createNamespace(parent_scope);
parent_namespace = Getattr(namespaces, parent_scope);
} else {
parent_namespace = Getattr(namespaces, parent_scope);
}
assert(parent_namespace != 0);
Hash *new_namespace = createNamespaceEntry(Char(scope), Char(Getattr(parent_namespace, "name")), Char(Getattr(parent_namespace, "name_mangled")));
Setattr(namespaces, scope, new_namespace);
Delete(parent_scope);
return SWIG_OK;
}
Hash *JSEmitter::createNamespaceEntry(const char *_name, const char *parent, const char *parent_mangled) {
Hash *entry = NewHash();
String *name = NewString(_name);
Setattr(entry, NAME, Swig_scopename_last(name));
Setattr(entry, NAME_MANGLED, Swig_name_mangle_string(name));
Setattr(entry, PARENT, NewString(parent));
Setattr(entry, PARENT_MANGLED, NewString(parent_mangled));
Delete(name);
return entry;
}
* JavascriptCore: JSEmitter implementation for JavascriptCore engine
**********************************************************************/
class JSCEmitter:public JSEmitter {
public:
JSCEmitter();
virtual ~ JSCEmitter();
virtual int initialize(Node *n);
virtual int dump(Node *n);
virtual int close();
protected:
virtual int enterVariable(Node *n);
virtual int exitVariable(Node *n);
virtual int enterFunction(Node *n);
virtual int exitFunction(Node *n);
virtual int enterClass(Node *n);
virtual int exitClass(Node *n);
virtual void marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static);
virtual Hash *createNamespaceEntry(const char *name, const char *parent, const char *parent_mangled);
virtual int emitNamespaces();
private:
String *NULL_STR;
String *VETO_SET;
File *f_wrap_cpp;
File *f_runtime;
File *f_header;
File *f_init;
};
JSCEmitter::JSCEmitter()
: JSEmitter(JSEmitter::JavascriptCore), NULL_STR(NewString("NULL")), VETO_SET(NewString("JS_veto_set_variable")), f_wrap_cpp(NULL), f_runtime(NULL), f_header(NULL), f_init(NULL) {
}
JSCEmitter::~JSCEmitter() {
Delete(NULL_STR);
Delete(VETO_SET);
}
* marshalInputArgs()
*
* Process all of the arguments passed into the argv array
* and convert them into C/C++ function arguments using the
* supplied typemaps.
* --------------------------------------------------------------------- */
void JSCEmitter::marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static) {
Parm *p;
String *tm = NULL;
int startIdx = 0;
if (is_member && !is_static && mode != Ctor) {
startIdx = 1;
}
int num_args = emit_num_arguments(parms) - startIdx;
String *argcount = NewString("");
Printf(argcount, "%d", num_args);
Setattr(n, ARGCOUNT, argcount);
int num_required = emit_num_required(parms) - startIdx;
SetInt(n, ARGREQUIRED, num_required);
int i = 0;
for (p = parms; p;) {
String *arg = NewString("");
String *type = Getattr(p, "type");
if (SwigType_isvarargs(type))
break;
switch (mode) {
case Getter:
case Function:
if (is_member && !is_static && i == 0) {
Printv(arg, "thisObject", 0);
i++;
} else {
Printf(arg, "argv[%d]", i - startIdx);
SetInt(p, INDEX, i - startIdx);
i += GetInt(p, "tmap:in:numinputs");
}
break;
case Setter:
if (is_member && !is_static && i == 0) {
Printv(arg, "thisObject", 0);
i++;
} else {
Printv(arg, "value", 0);
i++;
}
break;
case Ctor:
Printf(arg, "argv[%d]", i);
SetInt(p, INDEX, i);
i += GetInt(p, "tmap:in:numinputs");
break;
default:
Printf(stderr, "Illegal MarshallingMode.");
Exit(EXIT_FAILURE);
}
tm = emitInputTypemap(n, p, wrapper, arg);
Delete(arg);
if (tm) {
p = Getattr(p, "tmap:in:next");
} else {
p = nextSibling(p);
}
}
for (p = parms; p;) {
tm = emitCheckTypemap(n, p, wrapper, Getattr(p, "emit:input"));
if (tm) {
p = Getattr(p, "tmap:check:next");
} else {
p = nextSibling(p);
}
}
}
int JSCEmitter::initialize(Node *n) {
JSEmitter::initialize(n);
String *outfile = Getattr(n, "outfile");
f_wrap_cpp = NewFile(outfile, "w", SWIG_output_files());
if (!f_wrap_cpp) {
FileErrorDisplay(outfile);
Exit(EXIT_FAILURE);
}
f_runtime = NewString("");
f_init = NewString("");
f_header = NewString("");
state.globals(CREATE_NAMESPACES, NewString(""));
state.globals(REGISTER_NAMESPACES, NewString(""));
state.globals(INITIALIZER, NewString(""));
Swig_register_filebyname("begin", f_wrap_cpp);
Swig_register_filebyname("header", f_header);
Swig_register_filebyname("wrapper", f_wrappers);
Swig_register_filebyname("runtime", f_runtime);
Swig_register_filebyname("init", f_init);
Swig_banner(f_wrap_cpp);
Swig_obligatory_macros(f_runtime, "JAVASCRIPT");
return SWIG_OK;
}
int JSCEmitter::dump(Node *n) {
String *module = Getattr(n, "name");
Template initializer_define(getTemplate("js_initializer_define"));
initializer_define.replace("$jsname", module).pretty_print(f_header);
SwigType_emit_type_table(f_runtime, f_wrappers);
Printv(f_wrap_cpp, f_runtime, "\n", 0);
Printv(f_wrap_cpp, f_header, "\n", 0);
Printv(f_wrap_cpp, f_wrappers, "\n", 0);
emitNamespaces();
Template initializer(getTemplate("js_initializer"));
initializer.replace("$jsname", module)
.replace("$jsregisterclasses", state.globals(INITIALIZER))
.replace("$jscreatenamespaces", state.globals(CREATE_NAMESPACES))
.replace("$jsregisternamespaces", state.globals(REGISTER_NAMESPACES))
.pretty_print(f_init);
Printv(f_wrap_cpp, f_init, 0);
return SWIG_OK;
}
int JSCEmitter::close() {
Delete(f_runtime);
Delete(f_header);
Delete(f_wrappers);
Delete(f_init);
Delete(namespaces);
Delete(f_wrap_cpp);
return SWIG_OK;
}
int JSCEmitter::enterFunction(Node *n) {
JSEmitter::enterFunction(n);
return SWIG_OK;
}
int JSCEmitter::exitFunction(Node *n) {
Template t_function = getTemplate("jsc_function_declaration");
bool is_member = GetFlag(n, "ismember") != 0 || GetFlag(n, "feature:extend") != 0;
bool is_overloaded = GetFlag(n, "sym:overloaded") != 0;
if (is_overloaded) {
if (!Getattr(n, "sym:nextSibling")) {
emitFunctionDispatcher(n, is_member);
} else {
return SWIG_OK;
}
}
t_function.replace("$jsname", state.function(NAME))
.replace("$jswrapper", state.function(WRAPPER_NAME));
if (is_member) {
if (GetFlag(state.function(), IS_STATIC)) {
t_function.pretty_print(state.clazz(STATIC_FUNCTIONS));
} else {
t_function.pretty_print(state.clazz(MEMBER_FUNCTIONS));
}
} else {
t_function.pretty_print(Getattr(current_namespace, "functions"));
}
return SWIG_OK;
}
int JSCEmitter::enterVariable(Node *n) {
JSEmitter::enterVariable(n);
state.variable(GETTER, NULL_STR);
state.variable(SETTER, VETO_SET);
return SWIG_OK;
}
int JSCEmitter::exitVariable(Node *n) {
Template t_variable(getTemplate("jsc_variable_declaration"));
t_variable.replace("$jsname", state.variable(NAME))
.replace("$jsgetter", state.variable(GETTER))
.replace("$jssetter", state.variable(SETTER));
if (GetFlag(n, "ismember")) {
if (GetFlag(state.variable(), IS_STATIC)
|| Equal(Getattr(n, "nodeType"), "enumitem")) {
t_variable.pretty_print(state.clazz(STATIC_VARIABLES));
} else {
t_variable.pretty_print(state.clazz(MEMBER_VARIABLES));
}
} else {
t_variable.pretty_print(Getattr(current_namespace, "values"));
}
return SWIG_OK;
}
int JSCEmitter::enterClass(Node *n) {
JSEmitter::enterClass(n);
state.clazz(MEMBER_VARIABLES, NewString(""));
state.clazz(MEMBER_FUNCTIONS, NewString(""));
state.clazz(STATIC_VARIABLES, NewString(""));
state.clazz(STATIC_FUNCTIONS, NewString(""));
Template t_class_decl = getTemplate("jsc_class_declaration");
t_class_decl.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.pretty_print(f_wrappers);
return SWIG_OK;
}
int JSCEmitter::exitClass(Node *n) {
Template t_class_tables(getTemplate("jsc_class_tables"));
t_class_tables.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsclassvariables", state.clazz(MEMBER_VARIABLES))
.replace("$jsclassfunctions", state.clazz(MEMBER_FUNCTIONS))
.replace("$jsstaticclassfunctions", state.clazz(STATIC_FUNCTIONS))
.replace("$jsstaticclassvariables", state.clazz(STATIC_VARIABLES))
.pretty_print(f_wrappers);
if (GetFlag(state.clazz(), IS_ABSTRACT)) {
Template t_veto_ctor(getTemplate("js_veto_ctor"));
t_veto_ctor.replace("$jswrapper", state.clazz(CTOR))
.replace("$jsname", state.clazz(NAME))
.pretty_print(f_wrappers);
}
Template t_classtemplate(getTemplate("jsc_class_definition"));
String *jsclass_inheritance = NewString("");
Node *base_class = getBaseClass(n);
if (base_class != NULL) {
Template t_inherit(getTemplate("jsc_class_inherit"));
t_inherit.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsbaseclassmangled", SwigType_manglestr(Getattr(base_class, "name")))
.pretty_print(jsclass_inheritance);
} else {
Template t_inherit(getTemplate("jsc_class_noinherit"));
t_inherit.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.pretty_print(jsclass_inheritance);
}
t_classtemplate.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsclass_inheritance", jsclass_inheritance)
.replace("$jsctor", state.clazz(CTOR))
.replace("$jsdtor", state.clazz(DTOR))
.pretty_print(state.globals(INITIALIZER));
Delete(jsclass_inheritance);
SwigType_remember_clientdata(state.clazz(TYPE_MANGLED), NewString("0"));
Template t_registerclass(getTemplate("jsc_class_registration"));
t_registerclass.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsnspace", Getattr(state.clazz("nspace"), NAME_MANGLED))
.pretty_print(state.globals(INITIALIZER));
return SWIG_OK;
}
Hash *JSCEmitter::createNamespaceEntry(const char *name, const char *parent, const char *parent_mangled) {
Hash *entry = JSEmitter::createNamespaceEntry(name, parent, parent_mangled);
Setattr(entry, "functions", NewString(""));
Setattr(entry, "values", NewString(""));
return entry;
}
int JSCEmitter::emitNamespaces() {
Iterator it;
for (it = First(namespaces); it.item; it = Next(it)) {
Hash *entry = it.item;
String *name = Getattr(entry, NAME);
String *name_mangled = Getattr(entry, NAME_MANGLED);
String *parent_mangled = Getattr(entry, PARENT_MANGLED);
String *functions = Getattr(entry, "functions");
String *variables = Getattr(entry, "values");
Template namespace_definition(getTemplate("jsc_nspace_declaration"));
namespace_definition.replace("$jsglobalvariables", variables)
.replace("$jsglobalfunctions", functions)
.replace("$jsnspace", name_mangled)
.replace("$jsmangledname", name_mangled)
.pretty_print(f_wrap_cpp);
Template t_createNamespace(getTemplate("jsc_nspace_definition"));
t_createNamespace.replace("$jsmangledname", name_mangled);
Append(state.globals(CREATE_NAMESPACES), t_createNamespace.str());
if (!Equal("exports", name)) {
Template t_registerNamespace(getTemplate("jsc_nspace_registration"));
t_registerNamespace.replace("$jsmangledname", name_mangled)
.replace("$jsname", name)
.replace("$jsparent", parent_mangled);
Append(state.globals(REGISTER_NAMESPACES), t_registerNamespace.str());
}
}
return SWIG_OK;
}
JSEmitter *swig_javascript_create_JSCEmitter() {
return new JSCEmitter();
}
* V8: JSEmitter implementation for V8 engine
**********************************************************************/
class V8Emitter:public JSEmitter {
public:
V8Emitter();
virtual ~ V8Emitter();
virtual int initialize(Node *n);
virtual int dump(Node *n);
virtual int close();
virtual int enterClass(Node *n);
virtual int exitClass(Node *n);
virtual int enterVariable(Node *n);
virtual int exitVariable(Node *n);
virtual int exitFunction(Node *n);
protected:
virtual void marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static);
virtual int emitNamespaces();
protected:
String *f_runtime;
String *f_header;
String *f_init;
String *f_post_init;
String *f_class_templates;
String *f_init_namespaces;
String *f_init_class_templates;
String *f_init_wrappers;
String *f_init_inheritance;
String *f_init_class_instances;
String *f_init_static_wrappers;
String *f_init_register_classes;
String *f_init_register_namespaces;
File *f_wrap_cpp;
String *NULL_STR;
String *VETO_SET;
String *moduleName;
};
V8Emitter::V8Emitter()
: JSEmitter(JSEmitter::V8), NULL_STR(NewString("0")), VETO_SET(NewString("JS_veto_set_variable")) {
}
V8Emitter::~V8Emitter() {
Delete(NULL_STR);
Delete(VETO_SET);
}
int V8Emitter::initialize(Node *n) {
JSEmitter::initialize(n);
moduleName = Getattr(n, "name");
String *outfile = Getattr(n, "outfile");
f_wrap_cpp = NewFile(outfile, "w", SWIG_output_files());
if (!f_wrap_cpp) {
FileErrorDisplay(outfile);
Exit(EXIT_FAILURE);
}
f_runtime = NewString("");
f_header = NewString("");
f_class_templates = NewString("");
f_init = NewString("");
f_post_init = NewString("");
f_init_namespaces = NewString("");
f_init_class_templates = NewString("");
f_init_wrappers = NewString("");
f_init_inheritance = NewString("");
f_init_class_instances = NewString("");
f_init_static_wrappers = NewString("");
f_init_register_classes = NewString("");
f_init_register_namespaces = NewString("");
Swig_register_filebyname("begin", f_wrap_cpp);
Swig_register_filebyname("runtime", f_runtime);
Swig_register_filebyname("header", f_header);
Swig_register_filebyname("wrapper", f_wrappers);
Swig_register_filebyname("init", f_init);
Swig_register_filebyname("post-init", f_post_init);
state.globals(FORCE_CPP, NewString("1"));
Swig_banner(f_wrap_cpp);
Swig_obligatory_macros(f_runtime, "JAVASCRIPT");
return SWIG_OK;
}
int V8Emitter::dump(Node *n) {
String *module = Getattr(n, "name");
Template initializer_define(getTemplate("js_initializer_define"));
initializer_define.replace("$jsname", module).pretty_print(f_header);
SwigType_emit_type_table(f_runtime, f_wrappers);
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_wrappers, "\n", 0);
emitNamespaces();
Template initializer(getTemplate("js_initializer"));
initializer.replace("$jsname", moduleName)
.replace("$jsv8nspaces", f_init_namespaces)
.replace("$jsv8classtemplates", f_init_class_templates)
.replace("$jsv8wrappers", f_init_wrappers)
.replace("$jsv8inheritance", f_init_inheritance)
.replace("$jsv8classinstances", f_init_class_instances)
.replace("$jsv8staticwrappers", f_init_static_wrappers)
.replace("$jsv8registerclasses", f_init_register_classes)
.replace("$jsv8registernspaces", f_init_register_namespaces);
Printv(f_init, initializer.str(), 0);
Printv(f_wrap_cpp, f_init, 0);
Printv(f_wrap_cpp, f_post_init, 0);
return SWIG_OK;
}
int V8Emitter::close() {
Delete(f_runtime);
Delete(f_header);
Delete(f_class_templates);
Delete(f_init_namespaces);
Delete(f_init_class_templates);
Delete(f_init_wrappers);
Delete(f_init_inheritance);
Delete(f_init_class_instances);
Delete(f_init_static_wrappers);
Delete(f_init_register_classes);
Delete(f_init_register_namespaces);
Delete(f_init);
Delete(f_post_init);
Delete(f_wrap_cpp);
return SWIG_OK;
}
int V8Emitter::enterClass(Node *n) {
JSEmitter::enterClass(n);
Template t_decl_class(getTemplate("jsv8_declare_class_template"));
t_decl_class.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.trim()
.pretty_print(f_class_templates);
return SWIG_OK;
}
int V8Emitter::exitClass(Node *n) {
if (GetFlag(state.clazz(), IS_ABSTRACT)) {
Template t_veto_ctor(getTemplate("js_veto_ctor"));
t_veto_ctor.replace("$jswrapper", state.clazz(CTOR))
.replace("$jsname", state.clazz(NAME))
.pretty_print(f_wrappers);
}
String *clientData = NewString("");
Printf(clientData, "&%s_clientData", state.clazz(NAME_MANGLED));
SwigType_remember_clientdata(state.clazz(TYPE_MANGLED), NewString("0"));
Template t_def_class = getTemplate("jsv8_define_class_template");
t_def_class.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsdtor", state.clazz(DTOR))
.trim()
.pretty_print(f_init_class_templates);
Template t_class_instance = getTemplate("jsv8_create_class_instance");
t_class_instance.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsctor", state.clazz(CTOR))
.trim()
.pretty_print(f_init_class_instances);
Node *baseClass = getBaseClass(n);
if (baseClass) {
String *base_name = Getattr(baseClass, "name");
Template t_inherit = getTemplate("jsv8_inherit");
String *base_name_mangled = SwigType_manglestr(base_name);
t_inherit.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsbaseclass", base_name_mangled)
.trim()
.pretty_print(f_init_inheritance);
Delete(base_name_mangled);
}
Template t_register = getTemplate("jsv8_register_class");
t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.clazz(NAME))
.replace("$jsparent", Getattr(state.clazz("nspace"), NAME_MANGLED))
.trim()
.pretty_print(f_init_register_classes);
return SWIG_OK;
}
int V8Emitter::enterVariable(Node *n) {
JSEmitter::enterVariable(n);
state.variable(GETTER, NULL_STR);
state.variable(SETTER, VETO_SET);
return SWIG_OK;
}
int V8Emitter::exitVariable(Node *n) {
if (GetFlag(n, "ismember")) {
if (GetFlag(state.variable(), IS_STATIC) || Equal(Getattr(n, "nodeType"), "enumitem")) {
Template t_register = getTemplate("jsv8_register_static_variable");
t_register.replace("$jsparent", state.clazz(NAME_MANGLED))
.replace("$jsname", state.variable(NAME))
.replace("$jsgetter", state.variable(GETTER))
.replace("$jssetter", state.variable(SETTER))
.trim()
.pretty_print(f_init_static_wrappers);
} else {
Template t_register = getTemplate("jsv8_register_member_variable");
t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.variable(NAME))
.replace("$jsgetter", state.variable(GETTER))
.replace("$jssetter", state.variable(SETTER))
.trim()
.pretty_print(f_init_wrappers);
}
} else {
Template t_register = getTemplate("jsv8_register_static_variable");
t_register.replace("$jsparent", Getattr(current_namespace, NAME_MANGLED))
.replace("$jsname", state.variable(NAME))
.replace("$jsgetter", state.variable(GETTER))
.replace("$jssetter", state.variable(SETTER))
.trim()
.pretty_print(f_init_wrappers);
}
return SWIG_OK;
}
int V8Emitter::exitFunction(Node *n) {
bool is_member = GetFlag(n, "ismember") != 0 || GetFlag(n, "feature:extend") != 0;
bool is_overloaded = GetFlag(n, "sym:overloaded") != 0;
if (is_overloaded) {
if (!Getattr(n, "sym:nextSibling")) {
emitFunctionDispatcher(n, is_member);
} else {
return SWIG_OK;
}
}
if (is_member) {
if (GetFlag(state.function(), IS_STATIC)) {
Template t_register = getTemplate("jsv8_register_static_function");
t_register.replace("$jsparent", state.clazz(NAME_MANGLED))
.replace("$jsname", state.function(NAME))
.replace("$jswrapper", state.function(WRAPPER_NAME))
.trim()
.pretty_print(f_init_static_wrappers);
} else {
Template t_register = getTemplate("jsv8_register_member_function");
t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.function(NAME))
.replace("$jswrapper", state.function(WRAPPER_NAME))
.trim()
.pretty_print(f_init_wrappers);
}
} else {
Template t_register = getTemplate("jsv8_register_static_function");
t_register.replace("$jsparent", Getattr(current_namespace, NAME_MANGLED))
.replace("$jsname", state.function(NAME))
.replace("$jswrapper", state.function(WRAPPER_NAME))
.trim()
.pretty_print(f_init_static_wrappers);
}
return SWIG_OK;
}
void V8Emitter::marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static) {
Parm *p;
String *tm = NULL;
int startIdx = 0;
if (is_member && !is_static && mode != Ctor) {
startIdx = 1;
}
int num_args = emit_num_arguments(parms) - startIdx;
String *argcount = NewString("");
Printf(argcount, "%d", num_args);
Setattr(n, ARGCOUNT, argcount);
int num_required = emit_num_required(parms) - startIdx;
SetInt(n, ARGREQUIRED, num_required);
int i = 0;
for (p = parms; p;) {
String *arg = NewString("");
String *type = Getattr(p, "type");
if (SwigType_isvarargs(type))
break;
switch (mode) {
case Getter:
if (is_member && !is_static && i == 0) {
Printv(arg, "info.Holder()", 0);
i++;
} else {
Printf(arg, "args[%d]", i - startIdx);
SetInt(p, INDEX, i - startIdx);
i += GetInt(p, "tmap:in:numinputs");
}
break;
case Function:
if (is_member && !is_static && i == 0) {
Printv(arg, "args.Holder()", 0);
i++;
} else {
Printf(arg, "args[%d]", i - startIdx);
SetInt(p, INDEX, i - startIdx);
i += GetInt(p, "tmap:in:numinputs");
}
break;
case Setter:
if (is_member && !is_static && i == 0) {
Printv(arg, "info.Holder()", 0);
i++;
} else {
Printv(arg, "value", 0);
i++;
}
break;
case Ctor:
Printf(arg, "args[%d]", i);
SetInt(p, INDEX, i);
i += GetInt(p, "tmap:in:numinputs");
break;
default:
Printf(stderr, "Illegal MarshallingMode.");
Exit(EXIT_FAILURE);
}
tm = emitInputTypemap(n, p, wrapper, arg);
Delete(arg);
if (tm) {
p = Getattr(p, "tmap:in:next");
} else {
p = nextSibling(p);
}
}
for (p = parms; p;) {
tm = emitCheckTypemap(n, p, wrapper, Getattr(p, "emit:input"));
if (tm) {
p = Getattr(p, "tmap:check:next");
} else {
p = nextSibling(p);
}
}
}
int V8Emitter::emitNamespaces() {
Iterator it;
for (it = First(namespaces); it.item; it = Next(it)) {
Hash *entry = it.item;
String *name = Getattr(entry, NAME);
String *name_mangled = Getattr(entry, NAME_MANGLED);
String *parent = Getattr(entry, PARENT);
String *parent_mangled = Getattr(entry, PARENT_MANGLED);
bool do_create = true;
bool do_register = true;
if (Equal(parent, "")) {
do_register = false;
}
if (Equal(name, "exports")) {
do_create = false;
}
if (do_create) {
Template t_create_ns = getTemplate("jsv8_create_namespace");
t_create_ns.replace("$jsmangledname", name_mangled)
.trim()
.pretty_print(f_init_namespaces);
}
if (do_register) {
Template t_register_ns = getTemplate("jsv8_register_namespace");
t_register_ns.replace("$jsmangledname", name_mangled)
.replace("$jsname", name)
.replace("$jsparent", parent_mangled)
.trim();
String *tmp_register_stmt = NewString("");
t_register_ns.pretty_print(tmp_register_stmt);
Insert(f_init_register_namespaces, 0, tmp_register_stmt);
Delete(tmp_register_stmt);
}
}
return SWIG_OK;
}
* NAPI: JSEmitter implementation for N-API
**********************************************************************/
class NAPIEmitter:public JSEmitter {
public:
NAPIEmitter();
virtual ~NAPIEmitter();
virtual int initialize(Node *n);
virtual int dump(Node *n);
virtual int close();
virtual int enterClass(Node *n);
virtual int exitClass(Node *n);
virtual int enterVariable(Node *n);
virtual int exitVariable(Node *n);
virtual int exitFunction(Node *n);
protected:
virtual void marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static);
virtual int emitNamespaces();
virtual int emitCtor(Node *);
virtual int emitDtor(Node *);
virtual int emitClassMethodDeclaration(Node *);
virtual const char *getFunctionTemplate(bool is_member);
virtual const char *getFunctionDispatcherTemplate(bool is_member);
virtual const char *getOverloadedFunctionTemplate(bool is_member);
virtual const char *getSetterTemplate(bool is_member);
virtual const char *getGetterTemplate(bool is_member);
protected:
String *f_runtime;
String *f_header;
String *f_init;
String *f_post_init;
String *f_class_declarations;
String *f_init_namespaces;
String *f_init_wrappers;
String *f_init_inheritance;
String *f_init_static_wrappers;
String *f_init_register_classes;
String *f_init_register_namespaces;
File *f_wrap_cpp;
String *NULL_STR;
String *VETO_SET;
String *moduleName;
size_t class_idx;
};
NAPIEmitter::NAPIEmitter()
: JSEmitter(JSEmitter::NAPI), NULL_STR(NewString("0")), VETO_SET(NewString("JS_veto_set_variable")), class_idx(0) {
}
NAPIEmitter::~NAPIEmitter() {
Delete(NULL_STR);
Delete(VETO_SET);
}
int NAPIEmitter::initialize(Node *n) {
JSEmitter::initialize(n);
moduleName = Getattr(n, "name");
String *outfile = Getattr(n, "outfile");
f_wrap_cpp = NewFile(outfile, "w", SWIG_output_files());
if (!f_wrap_cpp) {
FileErrorDisplay(outfile);
Exit(EXIT_FAILURE);
}
f_runtime = NewString("");
f_header = NewString("");
f_init = NewString("");
f_post_init = NewString("");
f_class_declarations = NewString("");
f_init_namespaces = NewString("");
f_init_wrappers = NewString("");
f_init_inheritance = NewString("");
f_init_static_wrappers = NewString("");
f_init_register_classes = NewString("");
f_init_register_namespaces = NewString("");
Swig_register_filebyname("begin", f_wrap_cpp);
Swig_register_filebyname("runtime", f_runtime);
Swig_register_filebyname("header", f_header);
Swig_register_filebyname("wrapper", f_wrappers);
Swig_register_filebyname("init", f_init);
Swig_register_filebyname("post-init", f_post_init);
state.globals(FORCE_CPP, NewString("1"));
Swig_banner(f_wrap_cpp);
Swig_obligatory_macros(f_runtime, "JAVASCRIPT");
return SWIG_OK;
}
int NAPIEmitter::dump(Node *n) {
String *module = Getattr(n, "name");
Template initializer_define(getTemplate("js_initializer_define"));
initializer_define.replace("$jsname", module).pretty_print(f_header);
SwigType_emit_type_table(f_runtime, f_wrappers);
Printv(f_wrap_cpp, f_runtime, "\n", 0);
Printv(f_wrap_cpp, f_header, "\n", 0);
Printv(f_wrap_cpp, f_class_declarations, "\n", 0);
Printv(f_wrap_cpp, f_wrappers, "\n", 0);
emitNamespaces();
String *inheritance = NewStringEmpty();
if (Len(f_init_inheritance) > 0) {
Template t_inheritance(getTemplate("js_init_inheritance"));
t_inheritance.pretty_print(inheritance);
}
Template initializer(getTemplate("js_initializer"));
initializer.replace("$jsname", moduleName)
.replace("$jsnapinspaces", f_init_namespaces)
.replace("$jsnapipreinheritance", inheritance)
.replace("$jsnapiinitinheritance", f_init_inheritance)
.replace("$jsnapiregisterclasses", f_init_register_classes)
.replace("$jsnapiregisternspaces", f_init_register_namespaces);
Printv(f_init, initializer.str(), 0);
Printv(f_wrap_cpp, f_init, 0);
Printv(f_wrap_cpp, f_post_init, 0);
Delete(inheritance);
return SWIG_OK;
}
int NAPIEmitter::close() {
Delete(f_runtime);
Delete(f_header);
Delete(f_class_declarations);
Delete(f_init_namespaces);
Delete(f_init_wrappers);
Delete(f_init_inheritance);
Delete(f_init_static_wrappers);
Delete(f_init_register_classes);
Delete(f_init_register_namespaces);
Delete(f_init);
Delete(f_post_init);
Delete(f_wrap_cpp);
return SWIG_OK;
}
const char *NAPIEmitter::getFunctionTemplate(bool is_member) {
return is_member ? "js_function" : "js_global_function";
}
const char *NAPIEmitter::getFunctionDispatcherTemplate(bool is_member) {
return is_member ? "js_function_dispatcher" : "js_global_function_dispatcher";
}
const char *NAPIEmitter::getOverloadedFunctionTemplate(bool is_member) {
return is_member ? "js_overloaded_function" : "js_global_overloaded_function";
}
const char *NAPIEmitter::getGetterTemplate(bool is_member) {
return is_member ? "js_getter" : "js_global_getter";
}
const char *NAPIEmitter::getSetterTemplate(bool is_member) {
return is_member ? "js_setter" : "js_global_setter";
}
int NAPIEmitter::enterClass(Node *n) {
JSEmitter::enterClass(n);
String *idx = NewString("");
Printf(idx, "%d", class_idx++);
Template t_register = getTemplate("jsnapi_registerclass");
t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.clazz(NAME))
.replace("$jsparent", Getattr(state.clazz("nspace"), NAME_MANGLED))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsclassidx", idx)
.trim()
.pretty_print(f_init_register_classes);
Delete(idx);
String *baseMangled;
Node *baseClass = getBaseClass(n);
SetFlag(n, IS_WRAPPED);
if (baseClass && GetFlag(baseClass, IS_WRAPPED)) {
String *jsName = NewString("");
String *nspace = Getattr(baseClass, "sym:nspace");
if (Len(nspace) == 0)
nspace = Getattr(current_namespace, NAME_MANGLED);
Printf(jsName, "%s_%s", nspace, Getattr(baseClass, "sym:name"));
baseMangled = SwigType_manglestr(jsName);
Delete(jsName);
f_init_wrappers = Copy(Getattr(baseClass, MEMBER_FUNCTIONS));
f_init_static_wrappers = Copy(Getattr(baseClass, STATIC_FUNCTIONS));
} else {
baseMangled = NewString("SWIG_NAPI_ObjectWrap");
f_init_wrappers = NewString("");
f_init_static_wrappers = NewString("");
}
state.clazz(PARENT_MANGLED, baseMangled);
Template t_setup_inheritance(getTemplate("jsnapi_setup_inheritance"));
t_setup_inheritance.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", state.clazz(CTOR))
.replace("$jsname", state.clazz(NAME))
.replace("$jsparent", baseMangled)
.pretty_print(f_init_inheritance);
Template t_decl_class(getTemplate("jsnapi_class_prologue_template"));
t_decl_class.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsparent", baseMangled)
.trim()
.pretty_print(f_class_declarations);
Delete(baseMangled);
return SWIG_OK;
}
int NAPIEmitter::exitClass(Node *n) {
if (GetFlag(state.clazz(), IS_ABSTRACT)) {
Template t_veto_ctor(getTemplate("js_veto_ctor"));
t_veto_ctor.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", state.clazz(CTOR))
.replace("$jsname", state.clazz(NAME))
.replace("$jsparent", state.clazz(PARENT_MANGLED))
.pretty_print(f_wrappers);
}
String *clientData = NewString("");
Printf(clientData, "&%s_clientData", state.clazz(NAME_MANGLED));
SwigType_remember_clientdata(state.clazz(TYPE_MANGLED), NewString("0"));
Template t_def_class = getTemplate("jsnapi_class_epilogue_template");
t_def_class.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsdtor", state.clazz(DTOR))
.trim()
.pretty_print(f_class_declarations);
Template t_class_instance = getTemplate("jsnapi_declare_class_instance");
t_class_instance.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.trim()
.pretty_print(f_class_declarations);
Template t_class_template = getTemplate("jsnapi_getclass");
t_class_template.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsnapiwrappers", f_init_wrappers)
.replace("$jsnapistaticwrappers", f_init_static_wrappers)
.replace("$jsparent", state.clazz(PARENT_MANGLED))
.trim()
.pretty_print(f_class_declarations);
Setattr(n, MEMBER_FUNCTIONS, f_init_wrappers);
Setattr(n, STATIC_FUNCTIONS, f_init_static_wrappers);
return SWIG_OK;
}
int NAPIEmitter::enterVariable(Node *n) {
UnsetFlag(n, "constant");
JSEmitter::enterVariable(n);
state.variable(GETTER, VETO_SET);
state.variable(SETTER, VETO_SET);
return SWIG_OK;
}
int NAPIEmitter::exitVariable(Node *n) {
if (GetFlag(n, "constant")) {
return SWIG_OK;
}
if (GetFlag(n, "ismember")) {
String *modifier = NewStringEmpty();
if (GetFlag(state.variable(), IS_STATIC) || Equal(Getattr(n, "nodeType"), "enumitem")) {
Template t_register = getTemplate("jsnapi_register_static_variable");
t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.variable(NAME))
.replace("$jsgetter", state.variable(GETTER))
.replace("$jssetter", state.variable(SETTER) != VETO_SET ? state.variable(SETTER)
: "JS_veto_set_static_variable")
.trim()
.pretty_print(f_init_static_wrappers);
Append(modifier, "static");
} else {
Template t_register = getTemplate("jsnapi_register_member_variable");
t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.variable(NAME))
.replace("$jsgetter", state.variable(GETTER))
.replace("$jssetter", state.variable(SETTER))
.trim()
.pretty_print(f_init_wrappers);
}
Template t_getter = getTemplate("jsnapi_class_method_declaration");
t_getter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsdtor", state.clazz(DTOR))
.replace("$jswrapper", state.variable(GETTER))
.replace("$jsstatic", modifier)
.trim()
.pretty_print(f_class_declarations);
if (state.variable(SETTER) != VETO_SET) {
Template t_setter = getTemplate("jsnapi_class_setter_declaration");
t_setter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsdtor", state.clazz(DTOR))
.replace("$jswrapper", state.variable(SETTER))
.replace("$jsstatic", modifier)
.trim()
.pretty_print(f_class_declarations);
}
Delete(modifier);
} else {
Template t_register = getTemplate("jsnapi_register_global_variable");
t_register.replace("$jsparent", Getattr(current_namespace, NAME_MANGLED))
.replace("$jsname", state.variable(NAME))
.replace("$jsgetter", state.variable(GETTER))
.replace("$jssetter", state.variable(SETTER))
.trim()
.pretty_print(f_init_register_namespaces);
}
return SWIG_OK;
}
int NAPIEmitter::emitClassMethodDeclaration(Node *) {
Template t_def_class = getTemplate("jsnapi_class_method_declaration");
t_def_class.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsdtor", state.clazz(DTOR))
.replace("$jswrapper", state.function(WRAPPER_NAME))
.replace("$jsstatic", GetFlag(state.function(), IS_STATIC) ? "static" : "")
.trim()
.pretty_print(f_class_declarations);
return SWIG_OK;
}
int NAPIEmitter::exitFunction(Node *n) {
bool is_member = GetFlag(n, "ismember") != 0 || GetFlag(n, "feature:extend") != 0;
bool is_overloaded = GetFlag(n, "sym:overloaded") != 0;
if (is_overloaded) {
emitClassMethodDeclaration(n);
if (!Getattr(n, "sym:nextSibling")) {
emitFunctionDispatcher(n, is_member);
} else {
return SWIG_OK;
}
}
if (is_member) {
if (GetFlag(state.function(), IS_STATIC)) {
Template t_register = getTemplate("jsnapi_register_static_function");
t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.function(NAME))
.replace("$jswrapper", state.function(WRAPPER_NAME))
.trim()
.pretty_print(f_init_static_wrappers);
} else {
Template t_register = getTemplate("jsnapi_register_member_function");
t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.function(NAME))
.replace("$jswrapper", state.function(WRAPPER_NAME))
.trim()
.pretty_print(f_init_wrappers);
}
emitClassMethodDeclaration(n);
} else {
Template t_register = getTemplate("jsnapi_register_global_function");
t_register.replace("$jsparent", Getattr(current_namespace, NAME_MANGLED))
.replace("$jsname", state.function(NAME))
.replace("$jswrapper", state.function(WRAPPER_NAME))
.trim()
.pretty_print(f_init_register_namespaces);
}
return SWIG_OK;
}
void NAPIEmitter::marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static) {
Parm *p;
String *tm;
int startIdx = 0;
if (is_member && !is_static && mode != Ctor) {
startIdx = 1;
}
int num_args = emit_num_arguments(parms) - startIdx;
String *argcount = NewString("");
Printf(argcount, "%d", num_args);
Setattr(n, ARGCOUNT, argcount);
int num_required = emit_num_required(parms) - startIdx;
SetInt(n, ARGREQUIRED, num_required);
int i = 0;
for (p = parms; p;) {
String *arg = NewString("");
String *type = Getattr(p, "type");
if (SwigType_isvarargs(type))
break;
switch (mode) {
case Getter:
if (is_member && !is_static && i == 0) {
Printv(arg, "info.This()", 0);
i++;
} else {
Printf(arg, "info[%d]", i - startIdx);
SetInt(p, INDEX, i - startIdx);
i += GetInt(p, "tmap:in:numinputs");
}
break;
case Function:
if (is_member && !is_static && i == 0) {
Printv(arg, "info.This()", 0);
i++;
} else {
Printf(arg, "info[%d]", i - startIdx);
SetInt(p, INDEX, i - startIdx);
i += GetInt(p, "tmap:in:numinputs");
}
break;
case Setter:
if (is_member && !is_static && i == 0) {
Printv(arg, "info.This()", 0);
i++;
} else {
Printv(arg, "value", 0);
i++;
}
break;
case Ctor:
Printf(arg, "info[%d]", i);
SetInt(p, INDEX, i - startIdx);
i += GetInt(p, "tmap:in:numinputs");
break;
default:
Printf(stderr, "Illegal MarshallingMode.");
Exit(EXIT_FAILURE);
}
tm = emitInputTypemap(n, p, wrapper, arg);
Delete(arg);
if (tm) {
p = Getattr(p, "tmap:in:next");
} else {
p = nextSibling(p);
}
}
for (p = parms; p;) {
tm = emitCheckTypemap(n, p, wrapper, Getattr(p, "emit:input"));
if (tm) {
p = Getattr(p, "tmap:in:next");
} else {
p = nextSibling(p);
}
}
}
int NAPIEmitter::emitNamespaces() {
Iterator it;
for (it = First(namespaces); it.item; it = Next(it)) {
Hash *entry = it.item;
String *name = Getattr(entry, NAME);
String *name_mangled = Getattr(entry, NAME_MANGLED);
String *parent = Getattr(entry, PARENT);
String *parent_mangled = Getattr(entry, PARENT_MANGLED);
bool do_create = true;
bool do_register = true;
if (Equal(parent, "")) {
do_register = false;
}
if (Equal(name, "exports")) {
do_create = false;
}
if (do_create) {
Template t_create_ns = getTemplate("jsnapi_create_namespace");
t_create_ns.replace("$jsmangledname", name_mangled)
.trim()
.pretty_print(f_init_namespaces);
}
if (do_register) {
Template t_register_ns = getTemplate("jsnapi_register_namespace");
t_register_ns.replace("$jsmangledname", name_mangled)
.replace("$jsname", name)
.replace("$jsparent", parent_mangled)
.trim();
String *tmp_register_stmt = NewString("");
t_register_ns.pretty_print(tmp_register_stmt);
Insert(f_init_register_namespaces, 0, tmp_register_stmt);
Delete(tmp_register_stmt);
}
}
return SWIG_OK;
}
int NAPIEmitter::emitCtor(Node *n) {
int r = JSEmitter::emitCtor(n);
if (r != SWIG_OK)
return r;
Template t_getter = getTemplate("jsnapi_class_method_declaration");
t_getter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", Getattr(n, "wrap:name"))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsstatic", "")
.trim()
.pretty_print(f_class_declarations);
return SWIG_OK;
}
int NAPIEmitter::emitDtor(Node *n) {
Template t_getter = getTemplate("jsnapi_class_dtor_declaration");
t_getter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.trim()
.pretty_print(f_class_declarations);
return JSEmitter::emitDtor(n);
}
JSEmitter *swig_javascript_create_V8Emitter() {
return new V8Emitter();
}
JSEmitter *swig_javascript_create_NAPIEmitter() {
return new NAPIEmitter();
}
* Helper implementations
**********************************************************************/
JSEmitterState::JSEmitterState()
: globalHash(NewHash()) {
Setattr(globalHash, "class", NewHash());
Setattr(globalHash, "function", NewHash());
Setattr(globalHash, "variable", NewHash());
}
JSEmitterState::~JSEmitterState() {
Delete(globalHash);
}
DOH *JSEmitterState::getState(const char *key, bool new_key) {
if (new_key) {
Hash *hash = NewHash();
Setattr(globalHash, key, hash);
}
return Getattr(globalHash, key);
}
DOH *JSEmitterState::globals() {
return globalHash;
}
DOH *JSEmitterState::globals(const char *key, DOH *initial) {
if (initial != 0) {
Setattr(globalHash, key, initial);
}
return Getattr(globalHash, key);
}
DOH *JSEmitterState::clazz(bool new_key) {
return getState("class", new_key);
}
DOH *JSEmitterState::clazz(const char *key, DOH *initial) {
DOH *c = clazz();
if (initial != 0) {
Setattr(c, key, initial);
}
return Getattr(c, key);
}
DOH *JSEmitterState::function(bool new_key) {
return getState("function", new_key);
}
DOH *JSEmitterState::function(const char *key, DOH *initial) {
DOH *f = function();
if (initial != 0) {
Setattr(f, key, initial);
}
return Getattr(f, key);
}
DOH *JSEmitterState::variable(bool new_key) {
return getState("variable", new_key);
}
DOH *JSEmitterState::variable(const char *key, DOH *initial) {
DOH *v = variable();
if (initial != 0) {
Setattr(v, key, initial);
}
return Getattr(v, key);
}
int JSEmitterState::IsSet(DOH *val) {
if (!val) {
return 0;
} else {
const char *cval = Char(val);
if (!cval)
return 0;
return (strcmp(cval, "0") != 0) ? 1 : 0;
}
}
* Template::Template() : creates a Template class for given template code
* ----------------------------------------------------------------------------- */
Template::Template(const String *code_) {
if (!code_) {
Printf(stdout, "Template code was null. Illegal input for template.");
Exit(EXIT_FAILURE);
}
code = NewString(code_);
templateName = NewString("");
}
Template::Template(const String *code_, const String *templateName_) {
if (!code_) {
Printf(stdout, "Template code was null. Illegal input for template.");
Exit(EXIT_FAILURE);
}
code = NewString(code_);
templateName = NewString(templateName_);
}
* Template::~Template() : cleans up of Template.
* ----------------------------------------------------------------------------- */
Template::~Template() {
Delete(code);
Delete(templateName);
}
* String* Template::str() : retrieves the current content of the template.
* ----------------------------------------------------------------------------- */
String *Template::str() {
if (js_template_enable_debug) {
String *pre_code = NewString("");
String *post_code = NewString("");
String *debug_code = NewString("");
Printf(pre_code, "/* begin fragment(\"%s\") */", templateName);
Printf(post_code, "/* end fragment(\"%s\") */", templateName);
Printf(debug_code, "%s\n%s\n%s\n", pre_code, code, post_code);
Delete(code);
Delete(pre_code);
Delete(post_code);
code = debug_code;
}
return code;
}
Template & Template::trim() {
const char *str = Char(code);
if (str == 0)
return *this;
int length = Len(code);
if (length == 0)
return *this;
int idx;
for (idx = 0; idx < length; ++idx) {
if (str[idx] != ' ' && str[idx] != '\t' && str[idx] != '\r' && str[idx] != '\n')
break;
}
int start_pos = idx;
for (idx = length - 1; idx >= start_pos; --idx) {
if (str[idx] != ' ' && str[idx] != '\t' && str[idx] != '\r' && str[idx] != '\n')
break;
}
int end_pos = idx;
int new_length = end_pos - start_pos + 1;
char *newstr = new char[new_length + 1];
memcpy(newstr, str + start_pos, new_length);
newstr[new_length] = 0;
Delete(code);
code = NewString(newstr);
delete[]newstr;
return *this;
}
* Template& Template::replace(const String* pattern, const String* repl) :
*
* replaces all occurrences of a given pattern with a given replacement.
*
* - pattern: the pattern to be replaced
* - repl: the replacement string
* - returns a reference to the Template to allow chaining of methods.
* ----------------------------------------------------------------------------- */
Template & Template::replace(const String *pattern, const String *repl) {
Replaceall(code, pattern, repl);
return *this;
}
Template & Template::print(DOH *doh) {
Printv(doh, str(), 0);
return *this;
}
Template & Template::pretty_print(DOH *doh) {
Wrapper_pretty_print(str(), doh);
return *this;
}
Template::Template(const Template & t) {
code = NewString(t.code);
templateName = NewString(t.templateName);
}
void Template::operator=(const Template & t) {
Delete(code);
Delete(templateName);
code = NewString(t.code);
templateName = NewString(t.templateName);
}