diff options
Diffstat (limited to 'Source/Modules/lua.cxx')
| -rw-r--r-- | Source/Modules/lua.cxx | 1226 |
1 files changed, 1226 insertions, 0 deletions
diff --git a/Source/Modules/lua.cxx b/Source/Modules/lua.cxx new file mode 100644 index 0000000..8835667 --- /dev/null +++ b/Source/Modules/lua.cxx @@ -0,0 +1,1226 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * lua.cxx + * + * Lua language module for SWIG. + * ----------------------------------------------------------------------------- */ + +/* NEW LANGUAGE NOTE: + * ver001 + this is simply a copy of tcl8.cxx, which has been renamed + * ver002 + all non essential code commented out, program now does virtually nothing + it prints to stderr the list of functions to wrap, but does not create + the XXX_wrap.c file + * ver003 + added back top(), still prints the list of fns to stderr + but now creates a rather empty XXX_wrap.c with some basic boilerplate code + * ver004 + very basic version of functionWrapper() + also uncommented usage_string() to keep compiler happy + this will start producing proper looking code soon (I hope) + produced the wrapper code, but without any type conversion (in or out) + generates a few warning because of no wrappering + does not generate SWIG_init() + reason for this is that lua.swg is empty + we will need to add code into this to make it work + * ver005/6 + massive rework, basing work on the pike module instead of tcl + (pike module it only 1/3 of the size)(though not as complete) + * ver007 + added simple type checking + * ver008 + INPUT, OUTPUT, INOUT typemaps handled (though not all types yet) + * ver009 + class support: ok for basic types, but methods still TDB + (code is VERY messed up & needs to be cleaned) + + +*/ + +char cvsroot_lua_cxx[] = "$Id: lua.cxx 11133 2009-02-20 07:52:24Z wsfulton $"; + +#include "swigmod.h" + +/**** Diagnostics: + With the #define REPORT(), you can change the amount of diagnostics given + This helps me search the parse tree & figure out what is going on inside SWIG + (because its not clear or documented) +*/ +#define REPORT(T,D) // no info: +//#define REPORT(T,D) {Printf(stdout,T"\n");} // only title +//#define REPORT(T,D) {Printf(stdout,T" %p\n",n);} // title & pointer +//#define REPORT(T,D) {Printf(stdout,T"\n");display_mapping(D);} // the works +//#define REPORT(T,D) {Printf(stdout,T"\n");if(D)Swig_print_node(D);} // the works + +void display_mapping(DOH *d) { + if (d == 0 || !DohIsMapping(d)) + return; + for (DohIterator it = DohFirst(d); it.item; it = DohNext(it)) { + if (DohIsString(it.item)) + Printf(stdout, " %s = %s\n", it.key, it.item); + else if (DohIsMapping(it.item)) + Printf(stdout, " %s = <mapping>\n", it.key); + else if (DohIsSequence(it.item)) + Printf(stdout, " %s = <sequence>\n", it.key); + else + Printf(stdout, " %s = <unknown>\n", it.key); + } +} + + + +/* NEW LANGUAGE NOTE:*********************************************** + most of the default options are handled by SWIG + you can add new ones here + (though for now I have not bothered) +NEW LANGUAGE NOTE:END ************************************************/ +static const char *usage = (char *) "\ + Lua Options (available with -lua)\n\ + (coming soon.)\n\n"; + + + +/* NEW LANGUAGE NOTE:*********************************************** + To add a new language, you need to derive your class from + Language and the overload various virtual functions + (more on this as I figure it out) +NEW LANGUAGE NOTE:END ************************************************/ + +class LUA:public Language { +private: + + File *f_begin; + File *f_runtime; + File *f_header; + File *f_wrappers; + File *f_init; + File *f_initbeforefunc; + String *PrefixPlusUnderscore; + String *s_cmd_tab; // table of command names + String *s_var_tab; // table of global variables + String *s_const_tab; // table of global constants + String *s_methods_tab; // table of class methods + String *s_attr_tab; // table of class atributes + String *s_luacode; // luacode to be called during init + + int have_constructor; + int have_destructor; + String *destructor_action; + String *class_name; + String *constructor_name; + + enum { + NO_CPP, + VARIABLE, + MEMBER_FUNC, + CONSTRUCTOR, + DESTRUCTOR, + MEMBER_VAR, + CLASS_CONST, + STATIC_FUNC, + STATIC_VAR + }current; + +public: + + /* --------------------------------------------------------------------- + * LUA() + * + * Initialize member data + * --------------------------------------------------------------------- */ + + LUA() { + f_begin = 0; + f_runtime = 0; + f_header = 0; + f_wrappers = 0; + f_init = 0; + f_initbeforefunc = 0; + PrefixPlusUnderscore = 0; + + s_cmd_tab = s_var_tab = s_const_tab = s_luacode = 0; + current=NO_CPP; + } + + /* NEW LANGUAGE NOTE:*********************************************** + This is called to initalise the system & read any command line args + most of this is boilerplate code, except the command line args + which depends upon what args your code supports + NEW LANGUAGE NOTE:END ************************************************/ + + /* --------------------------------------------------------------------- + * main() + * + * Parse command line options and initializes variables. + * --------------------------------------------------------------------- */ + + virtual void main(int argc, char *argv[]) { + + /* Set location of SWIG library */ + SWIG_library_directory("lua"); + + /* Look for certain command line options */ + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-help") == 0) { // usage flags + fputs(usage, stderr); + } + } + } + + /* NEW LANGUAGE NOTE:*********************************************** + This is the boilerplate code, setting a few #defines + and which lib directory to use + the SWIG_library_directory() is also boilerplate code + but it always seems to be the first line of code + NEW LANGUAGE NOTE:END ************************************************/ + /* Add a symbol to the parser for conditional compilation */ + Preprocessor_define("SWIGLUA 1", 0); + + /* Set language-specific configuration file */ + SWIG_config_file("lua.swg"); + + /* Set typemap language */ + SWIG_typemap_lang("lua"); + + /* Enable overloaded methods support */ + allow_overloading(); + } + + + + + /* NEW LANGUAGE NOTE:*********************************************** + After calling main, SWIG parses the code to wrap (I believe) + then calls top() + in this is more boilerplate code to set everything up + and a call to Language::top() + which begins the code generations by calling the member fns + after all that is more boilerplate code to close all down + (overall there is virtually nothing here that needs to be edited + just use as is) + NEW LANGUAGE NOTE:END ************************************************/ + /* --------------------------------------------------------------------- + * top() + * --------------------------------------------------------------------- */ + + virtual int top(Node *n) { + /* Get the module name */ + String *module = Getattr(n, "name"); + + /* Get the output file name */ + String *outfile = Getattr(n, "outfile"); + + /* Open the output file */ + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_initbeforefunc = NewString(""); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("initbeforefunc", f_initbeforefunc); + + /* NEW LANGUAGE NOTE:*********************************************** + s_cmd_tab,s_var_tab & s_const_tab hold the names of the fns for + registering with SWIG. + These will be filled in when the functions/variables are wrapped & + then added to the end of the wrappering code + just before it is written to file + NEW LANGUAGE NOTE:END ************************************************/ + // Initialize some variables for the object interface + s_cmd_tab = NewString(""); + s_var_tab = NewString(""); + // s_methods_tab = NewString(""); + s_const_tab = NewString(""); + + s_luacode = NewString(""); + Swig_register_filebyname("luacode", s_luacode); + + current=NO_CPP; + + /* Standard stuff for the SWIG runtime section */ + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGLUA\n"); + + // if (NoInclude) { + // Printf(f_runtime, "#define SWIG_NOINCLUDE\n"); + // } + + Printf(f_runtime, "\n"); + + //String *init_name = NewStringf("%(title)s_Init", module); + //Printf(f_header, "#define SWIG_init %s\n", init_name); + //Printf(f_header, "#define SWIG_name \"%s\"\n", module); + /* SWIG_import is a special function name for importing within Lua5.1 */ + //Printf(f_header, "#define SWIG_import luaopen_%s\n\n", module); + Printf(f_header, "#define SWIG_name \"%s\"\n", module); + Printf(f_header, "#define SWIG_init luaopen_%s\n", module); + Printf(f_header, "#define SWIG_init_user luaopen_%s_user\n\n", module); + Printf(f_header, "#define SWIG_LUACODE luaopen_%s_luacode\n\n", module); + + Printf(s_cmd_tab, "\nstatic const struct luaL_reg swig_commands[] = {\n"); + Printf(s_var_tab, "\nstatic swig_lua_var_info swig_variables[] = {\n"); + Printf(s_const_tab, "\nstatic swig_lua_const_info swig_constants[] = {\n"); + Printf(f_wrappers, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); + + /* %init code inclusion, effectively in the SWIG_init function */ + Printf(f_init, "void SWIG_init_user(lua_State* L)\n{\n"); + Language::top(n); + Printf(f_init,"/* exec Lua code if applicable */\nSWIG_Lua_dostring(L,SWIG_LUACODE);\n"); + Printf(f_init, "}\n"); + + Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); + + // Done. Close up the module & write to the wrappers + Printv(s_cmd_tab, tab4, "{0,0}\n", "};\n", NIL); + Printv(s_var_tab, tab4, "{0,0,0}\n", "};\n", NIL); + Printv(s_const_tab, tab4, "{0,0,0,0,0,0}\n", "};\n", NIL); + Printv(f_wrappers, s_cmd_tab, s_var_tab, s_const_tab, NIL); + SwigType_emit_type_table(f_runtime, f_wrappers); + + /* NEW LANGUAGE NOTE:*********************************************** + this basically combines several of the strings together + and then writes it all to a file + NEW LANGUAGE NOTE:END ************************************************/ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + Dump(f_wrappers, f_begin); + Dump(f_initbeforefunc, f_begin); + /* for the Lua code it needs to be properly excaped to be added into the C/C++ code */ + EscapeCode(s_luacode); + Printf(f_begin, "const char* SWIG_LUACODE=\n \"%s\";\n\n",s_luacode); + Wrapper_pretty_print(f_init, f_begin); + /* Close all of the files */ + Delete(s_luacode); + Delete(s_cmd_tab); + Delete(s_var_tab); + Delete(s_const_tab); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Delete(f_initbeforefunc); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + + /* Done */ + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * importDirective() + * ------------------------------------------------------------ */ + + virtual int importDirective(Node *n) { + return Language::importDirective(n); + } + + /* NEW LANGUAGE NOTE:*********************************************** + This is it! + you get this one right, and most of your work is done + but its going to take soem file to get it working right + quite a bit of this is generally boilerplate code + (or stuff I dont understand) + that which matters will have extra added comments + NEW LANGUAGE NOTE:END ************************************************/ + /* --------------------------------------------------------------------- + * functionWrapper() + * + * Create a function declaration and register it with the interpreter. + * --------------------------------------------------------------------- */ + + virtual int functionWrapper(Node *n) { + REPORT("functionWrapper",n); + + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + SwigType *d = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + //Printf(stdout,"functionWrapper %s %s\n",name,iname); + Parm *p; + String *tm; + int i; + //Printf(stdout,"functionWrapper %s %s %d\n",name,iname,current); + // int returnval=0; // number of arguments returned + + String *overname = 0; + if (Getattr(n, "sym:overloaded")) { + overname = Getattr(n, "sym:overname"); + } else { + if (!addSymbol(iname, n)) { + Printf(stderr,"addSymbol(%s) failed\n",iname); + return SWIG_ERROR; + } + } + + /* NEW LANGUAGE NOTE:*********************************************** + the wrapper object holds all the wrappering code + we need to add a couple of local variables + NEW LANGUAGE NOTE:END ************************************************/ + Wrapper *f = NewWrapper(); + Wrapper_add_local(f, "SWIG_arg", "int SWIG_arg = 0"); + + + String *wname = Swig_name_wrapper(iname); + if (overname) { + Append(wname, overname); + } + + /* NEW LANGUAGE NOTE:*********************************************** + the format of a lua fn is: + static int wrap_XXX(lua_State* L){...} + this line adds this into the wrappering code + NEW LANGUAGE NOTE:END ************************************************/ + Printv(f->def, "static int ", wname, "(lua_State* L) {", NIL); + + /* NEW LANGUAGE NOTE:*********************************************** + this prints the list of args, eg for a C fn + int gcd(int x,int y); + it will print + int arg1; + int arg2; + NEW LANGUAGE NOTE:END ************************************************/ + /* Write code to extract function parameters. */ + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + Setattr(n, "wrap:parms", l); + + /* Get number of required and total arguments */ + int num_arguments = emit_num_arguments(l); + int num_required = emit_num_required(l); + int varargs = emit_isvarargs(l); + + // Check if we have to ignore arguments that are passed by LUA. + // Needed for unary minus, where lua passes two arguments and + // we have to ignore the second. + + int args_to_ignore = 0; + if (Getattr(n, "lua:ignore_args")) { + args_to_ignore = GetInt(n, "lua:ignore_args"); + } + + + /* Which input argument to start with? */ + // int start = (current == MEMBER_FUNC || current == MEMBER_VAR || current == DESTRUCTOR) ? 1 : 0; + + /* Offset to skip over the attribute name */ + // int offset = (current == MEMBER_VAR) ? 1 : 0; + + /* NEW LANGUAGE NOTE:*********************************************** + from here on in, it gets rather hairy + this is the code to convert from the scripting language to C/C++ + some of the stuff will refer to the typemaps code written in your swig file + (lua.swg), and some is done in the code here + I suppose you could do all the conversion on C, but it would be a nightmare to do + NEW LANGUAGE NOTE:END ************************************************/ + /* Generate code for argument marshalling */ + // String *description = NewString(""); + /* NEW LANGUAGE NOTE:*********************************************** + argument_check is a new feature I added to check types of arguments: + eg for int gcd(int,int) + I want to check that arg1 & arg2 really are integers + NEW LANGUAGE NOTE:END ************************************************/ + String *argument_check = NewString(""); + String *argument_parse = NewString(""); + String *checkfn = NULL; + // String *numoutputs=NULL; + char source[64]; + //Printf(argument_check, "SWIG_check_num_args(\"%s\",%d,%d)\n",name,num_required,num_arguments); + Printf(argument_check, "SWIG_check_num_args(\"%s\",%d,%d)\n",name,num_required+args_to_ignore,num_arguments+args_to_ignore); + + for (i = 0, p = l; i < num_arguments; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + + /* Look for an input typemap */ + sprintf(source, "%d", i + 1); + if ((tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$source", source); + Replaceall(tm, "$target", ln); + Replaceall(tm, "$input", source); + Setattr(p, "emit:input", source); + if (Getattr(p, "wrap:disown") || (Getattr(p, "tmap:in:disown"))) { + Replaceall(tm, "$disown", "SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm, "$disown", "0"); + } + /* NEW LANGUAGE NOTE:*********************************************** + look for a 'checkfn' typemap + this an additional parameter added to the in typemap + if found the type will be tested for + this will result in code either in the + argument_check or argument_parse string + NEW LANGUAGE NOTE:END ************************************************/ + if ((checkfn = Getattr(p, "tmap:in:checkfn"))) { + if (i < num_required) { + Printf(argument_check, "if(!%s(L,%s))", checkfn, source); + } else { + Printf(argument_check, "if(lua_gettop(L)>=%s && !%s(L,%s))", source, checkfn, source); + } + Printf(argument_check, " SWIG_fail_arg(\"%s\",%s,\"%s\");\n", name, source, SwigType_str(pt, 0)); + } + /* NEW LANGUAGE NOTE:*********************************************** + lua states the number of arguments passed to a function using the fn + lua_gettop() + we can use this to deal with default arguments + NEW LANGUAGE NOTE:END ************************************************/ + if (i < num_required) { + Printf(argument_parse, "%s\n", tm); + } else { + Printf(argument_parse, "if(lua_gettop(L)>=%s){%s}\n", source, tm); + } + p = Getattr(p, "tmap:in:next"); + continue; + } else { + /* NEW LANGUAGE NOTE:*********************************************** + // why is this code not called when I dont have a typemap? + // instead of giving a warning, no code is generated + NEW LANGUAGE NOTE:END ************************************************/ + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + break; + } + } + + // add all argcheck code + Printv(f->code, argument_check, argument_parse, NIL); + + /* Check for trailing varargs */ + if (varargs) { + if (p && (tm = Getattr(p, "tmap:in"))) { + Replaceall(tm, "$input", "varargs"); + Printv(f->code, tm, "\n", NIL); + } + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + Replaceall(tm, "$target", Getattr(p, "lname")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + String *cleanup = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + Replaceall(tm, "$source", Getattr(p, "lname")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + String *outarg = NewString(""); + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + // // managing the number of returning variables + // if (numoutputs=Getattr(p,"tmap:argout:numoutputs")){ + // int i=GetInt(p,"tmap:argout:numoutputs"); + // printf("got argout:numoutputs of %d\n",i); + // returnval+=GetInt(p,"tmap:argout:numoutputs"); + // } + // else returnval++; + Replaceall(tm, "$source", Getattr(p, "lname")); + Replaceall(tm, "$target", "result"); + Replaceall(tm, "$arg", Getattr(p, "emit:input")); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + Setattr(n, "wrap:name", wname); + + /* Emit the function call */ + String *actioncode = emit_action(n); + + /* NEW LANGUAGE NOTE:*********************************************** + FIXME: + returns 1 if there is a void return type + this is because there is a typemap for void + NEW LANGUAGE NOTE:END ************************************************/ + // Return value if necessary + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + // managing the number of returning variables + // if (numoutputs=Getattr(tm,"numoutputs")){ + // int i=GetInt(tm,"numoutputs"); + // printf("return numoutputs %d\n",i); + // returnval+=GetInt(tm,"numoutputs"); + // } + // else returnval++; + Replaceall(tm, "$source", "result"); + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "1"); + } else { + Replaceall(tm, "$owner", "0"); + } + Printf(f->code, "%s\n", tm); + // returnval++; + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); + } + emit_return_variable(n, d, f); + + /* Output argument output code */ + Printv(f->code, outarg, NIL); + + /* Output cleanup code */ + Printv(f->code, cleanup, NIL); + + /* Look to see if there is any newfree cleanup code */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + Replaceall(tm, "$source", "result"); + Printf(f->code, "%s\n", tm); + } + + + /* Close the function */ + Printv(f->code, "return SWIG_arg;\n", NIL); + // add the failure cleanup code: + Printv(f->code, "\nif(0) SWIG_fail;\n", NIL); + Printv(f->code, "\nfail:\n", NIL); + Printv(f->code, "$cleanup", "lua_error(L);\n", NIL); + Printv(f->code, "return SWIG_arg;\n", NIL); + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", iname); + Replaceall(f->code, "$result", "result"); + + /* Dump the function out */ + /* in Lua we will not emit the destructor as a wrappered function, + Lua will automatically call the destructor when the object is free'd + However: you cannot just skip this function as it will not emit + any custom destructor (using %extend), as you need to call emit_action() + Therefore we go though the whole function, + but do not write the code into the wrapper + */ + if(current!=DESTRUCTOR) { + Wrapper_print(f, f_wrappers); + } + + /* NEW LANGUAGE NOTE:*********************************************** + register the function in SWIG + different language mappings seem to use different ideas + NEW LANGUAGE NOTE:END ************************************************/ + /* Now register the function with the interpreter. */ + if (!Getattr(n, "sym:overloaded")) { + // add_method(n, iname, wname, description); + if (current==NO_CPP || current==STATIC_FUNC) // emit normal fns & static fns + Printv(s_cmd_tab, tab4, "{ \"", iname, "\", ", Swig_name_wrapper(iname), "},\n", NIL); + // Printv(s_cmd_tab, tab4, "{ SWIG_prefix \"", iname, "\", (swig_wrapper_func) ", Swig_name_wrapper(iname), "},\n", NIL); + } else { + if (!Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + } + + Delete(argument_check); + Delete(argument_parse); + + Delete(cleanup); + Delete(outarg); + // Delete(description); + Delete(wname); + DelWrapper(f); + + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * dispatchFunction() + * + * Emit overloading dispatch function + * ------------------------------------------------------------ */ + + /* NEW LANGUAGE NOTE:*********************************************** + This is an extra function used for overloading of functions + it checks the args & then calls the relevant fn + nost of the real work in again typemaps: + look for %typecheck(SWIG_TYPECHECK_*) in the .swg file + NEW LANGUAGE NOTE:END ************************************************/ + void dispatchFunction(Node *n) { + /* Last node in overloaded chain */ + + int maxargs; + String *tmp = NewString(""); + String *dispatch = Swig_overload_dispatch(n, "return %s(L);", &maxargs); + + /* Generate a dispatch wrapper for all overloaded functions */ + + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *wname = Swig_name_wrapper(symname); + + //Printf(stdout,"Swig_overload_dispatch %s %s '%s' %d\n",symname,wname,dispatch,maxargs); + + Printv(f->def, "static int ", wname, "(lua_State* L) {", NIL); + Wrapper_add_local(f, "argc", "int argc"); + Printf(tmp, "int argv[%d]={1", maxargs + 1); + for (int i = 1; i <= maxargs; i++) { + Printf(tmp, ",%d", i + 1); + } + Printf(tmp, "}"); + Wrapper_add_local(f, "argv", tmp); + Printf(f->code, "argc = lua_gettop(L);\n"); + + Replaceall(dispatch, "$args", "self,args"); + Printv(f->code, dispatch, "\n", NIL); + + Node *sibl = n; + while (Getattr(sibl, "sym:previousSibling")) + sibl = Getattr(sibl, "sym:previousSibling"); // go all the way up + String *protoTypes = NewString(""); + do { + Printf(protoTypes, "\n\" %s(%s)\\n\"", SwigType_str(Getattr(sibl, "name"), 0), ParmList_protostr(Getattr(sibl, "wrap:parms"))); + } while ((sibl = Getattr(sibl, "sym:nextSibling"))); + Printf(f->code, "lua_pushstring(L,\"Wrong arguments for overloaded function '%s'\\n\"\n" + "\" Possible C/C++ prototypes are:\\n\"%s);\n",symname,protoTypes); + Delete(protoTypes); + + Printf(f->code, "lua_error(L);return 0;\n"); + Printv(f->code, "}\n", NIL); + Wrapper_print(f, f_wrappers); + //add_method(symname,wname,0); + if (current==NO_CPP || current==STATIC_FUNC) // emit normal fns & static fns + Printv(s_cmd_tab, tab4, "{ \"", symname, "\",", wname, "},\n", NIL); + + DelWrapper(f); + Delete(dispatch); + Delete(tmp); + Delete(wname); + } + + + /* ------------------------------------------------------------ + * variableWrapper() + * ------------------------------------------------------------ */ + + virtual int variableWrapper(Node *n) { + /* NEW LANGUAGE NOTE:*********************************************** + Language::variableWrapper(n) will generate two wrapper fns + Foo_get & Foo_set by calling functionWrapper() + so we will just add these into the variable lists + ideally we should not have registered these as functions, + only WRT this variable will look into this later. + NEW LANGUAGE NOTE:END ************************************************/ + // REPORT("variableWrapper", n); + String *iname = Getattr(n, "sym:name"); + current=VARIABLE; + // let SWIG generate the wrappers + int result = Language::variableWrapper(n); + current=NO_CPP; + // normally SWIG will generate 2 wrappers, a get and a set + // but in certain scenarios (immutable, or if its arrays), it will not + String *getName = Swig_name_wrapper(Swig_name_get(iname)); + String *setName = 0; + // checking whether it can be set to or not appears to be a very error prone issue + // I refered to the Language::variableWrapper() to find this out + bool assignable=is_assignable(n) ? true : false; + SwigType *type = Getattr(n, "type"); + String *tm = Swig_typemap_lookup("globalin", n, iname, 0); + if (!tm && SwigType_isarray(type)) + assignable=false; + Delete(tm); + + if (assignable) { + setName = Swig_name_wrapper(Swig_name_set(iname)); + } else { + // how about calling a 'this is not settable' error message? + setName = NewString("SWIG_Lua_set_immutable"); // error message + //setName = NewString("0"); + } + // register the variable + Printf(s_var_tab, "%s{ \"%s\", %s, %s },\n", tab4, iname, getName, setName); + Delete(getName); + Delete(setName); + return result; + } + + /* ------------------------------------------------------------ + * constantWrapper() + * ------------------------------------------------------------ */ + virtual int constantWrapper(Node *n) { + // REPORT("constantWrapper", n); + String *name = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + //String *nsname = !nspace ? Copy(iname) : NewStringf("%s::%s",ns_name,iname); + String *nsname = Copy(iname); + SwigType *type = Getattr(n, "type"); + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + String *tm; + + if (!addSymbol(iname, n)) + return SWIG_ERROR; + //if (nspace) Setattr(n,"sym:name",nsname); + + /* Special hook for member pointer */ + if (SwigType_type(type) == T_MPOINTER) { + String *wname = Swig_name_wrapper(iname); + Printf(f_wrappers, "static %s = %s;\n", SwigType_str(type, wname), value); + value = Char(wname); + } + + if ((tm = Swig_typemap_lookup("consttab", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Replaceall(tm, "$nsname", nsname); + Printf(s_const_tab, "%s,\n", tm); + } else if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { + Replaceall(tm, "$source", value); + Replaceall(tm, "$target", name); + Replaceall(tm, "$value", value); + Replaceall(tm, "$nsname", nsname); + Printf(f_init, "%s\n", tm); + } else { + Delete(nsname); + Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); + return SWIG_NOWRAP; + } + Delete(nsname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * nativeWrapper() + * ------------------------------------------------------------ */ + + virtual int nativeWrapper(Node *n) { + // REPORT("nativeWrapper", n); + String *symname = Getattr(n, "sym:name"); + String *wrapname = Getattr(n, "wrap:name"); + if (!addSymbol(wrapname, n)) + return SWIG_ERROR; + + Printv(s_cmd_tab, tab4, "{ \"", symname, "\",", wrapname, "},\n", NIL); + // return Language::nativeWrapper(n); // this does nothing... + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * enumDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumDeclaration(Node *n) { + return Language::enumDeclaration(n); + } + + /* ------------------------------------------------------------ + * enumvalueDeclaration() + * ------------------------------------------------------------ */ + + virtual int enumvalueDeclaration(Node *n) { + return Language::enumvalueDeclaration(n); + } + + /* ------------------------------------------------------------ + * classDeclaration() + * ------------------------------------------------------------ */ + + virtual int classDeclaration(Node *n) { + return Language::classDeclaration(n); + } + + /* ------------------------------------------------------------ + * classHandler() + * ------------------------------------------------------------ */ + + virtual int classHandler(Node *n) { + //REPORT("classHandler", n); + + String *mangled_classname = 0; + String *real_classname = 0; + + constructor_name = 0; + have_constructor = 0; + have_destructor = 0; + destructor_action = 0; + + class_name = Getattr(n, "sym:name"); + if (!addSymbol(class_name, n)) + return SWIG_ERROR; + + real_classname = Getattr(n, "name"); + mangled_classname = Swig_name_mangle(real_classname); + + // not sure exactly how this workswhat this works, + // but tcl has a static hashtable of all classes emitted and then only emits code for them once. + // this fixes issues in test suites: template_default2 & template_specialization + + // * if i understand correctly, this is a bug. + // * consider effect on template_specialization_defarg + + static Hash *emitted = NewHash(); + if (Getattr(emitted, mangled_classname)) + return SWIG_NOWRAP; + Setattr(emitted, mangled_classname, "1"); + + s_attr_tab = NewString(""); + Printf(s_attr_tab, "static swig_lua_attribute swig_"); + Printv(s_attr_tab, mangled_classname, "_attributes[] = {\n", NIL); + + s_methods_tab = NewString(""); + Printf(s_methods_tab, "static swig_lua_method swig_"); + Printv(s_methods_tab, mangled_classname, "_methods[] = {\n", NIL); + + // Generate normal wrappers + Language::classHandler(n); + + SwigType *t = Copy(Getattr(n, "name")); + SwigType_add_pointer(t); + + // Catch all: eg. a class with only static functions and/or variables will not have 'remembered' + String *wrap_class = NewStringf("&_wrap_class_%s", mangled_classname); + SwigType_remember_clientdata(t, wrap_class); + + String *rt = Copy(Getattr(n, "classtype")); + SwigType_add_pointer(rt); + + // Register the class structure with the type checker + // Printf(f_init,"SWIG_TypeClientData(SWIGTYPE%s, (void *) &_wrap_class_%s);\n", SwigType_manglestr(t), mangled_classname); + + // emit a function to be called to delete the object + if (have_destructor) { + Printv(f_wrappers, "static void swig_delete_", class_name, "(void *obj) {\n", NIL); + if (destructor_action) { + Printv(f_wrappers, SwigType_str(rt, "arg1"), " = (", SwigType_str(rt, 0), ") obj;\n", NIL); + Printv(f_wrappers, destructor_action, "\n", NIL); + } else { + if (CPlusPlus) { + Printv(f_wrappers, " delete (", SwigType_str(rt, 0), ") obj;\n", NIL); + } else { + Printv(f_wrappers, " free((char *) obj);\n", NIL); + } + } + Printf(f_wrappers, "}\n"); + } + + Printf(s_methods_tab, " {0,0}\n};\n"); + Printv(f_wrappers, s_methods_tab, NIL); + + Printf(s_attr_tab, " {0,0,0}\n};\n"); + Printv(f_wrappers, s_attr_tab, NIL); + + Delete(s_methods_tab); + Delete(s_attr_tab); + + // Handle inheritance + // note: with the idea of class hireachied spread over multiple modules + // cf test-suite: imports.i + // it is not possible to just add the pointers to the base classes to the code + // (as sometimes these classes are not present) + // therefore we instead hold the name of the base class and a null pointer + // at runtime: we can query the swig type manager & see if the class exists + // if so, we can get the pointer to the base class & replace the null pointer + // if the type does not exist, then we cannot... + String *base_class = NewString(""); + String *base_class_names = NewString(""); + + List *baselist = Getattr(n, "bases"); + if (baselist && Len(baselist)) { + Iterator b; + int index = 0; + b = First(baselist); + while (b.item) { + String *bname = Getattr(b.item, "name"); + if ((!bname) || GetFlag(b.item, "feature:ignore") || (!Getattr(b.item, "module"))) { + b = Next(b); + continue; + } + // old code: (used the pointer to the base class) + //String *bmangle = Swig_name_mangle(bname); + //Printf(base_class, "&_wrap_class_%s", bmangle); + //Putc(',', base_class); + //Delete(bmangle); + // new code: stores a null pointer & the name + Printf(base_class, "0,"); + Printf(base_class_names, "\"%s *\",", SwigType_namestr(bname)); + + b = Next(b); + index++; + } + } + + Printv(f_wrappers, "static swig_lua_class *swig_", mangled_classname, "_bases[] = {", base_class, "0};\n", NIL); + Delete(base_class); + Printv(f_wrappers, "static const char *swig_", mangled_classname, "_base_names[] = {", base_class_names, "0};\n", NIL); + Delete(base_class_names); + + Printv(f_wrappers, "static swig_lua_class _wrap_class_", mangled_classname, " = { \"", class_name, "\", &SWIGTYPE", SwigType_manglestr(t), ",", NIL); + + if (have_constructor) { + Printf(f_wrappers, "%s", Swig_name_wrapper(Swig_name_construct(constructor_name))); + Delete(constructor_name); + constructor_name = 0; + } else { + Printf(f_wrappers, "0"); + } + + if (have_destructor) { + Printv(f_wrappers, ", swig_delete_", class_name, NIL); + } else { + Printf(f_wrappers, ",0"); + } + Printf(f_wrappers, ", swig_%s_methods, swig_%s_attributes, swig_%s_bases, swig_%s_base_names };\n\n", mangled_classname, mangled_classname, mangled_classname, mangled_classname); + + // Printv(f_wrappers, ", swig_", mangled_classname, "_methods, swig_", mangled_classname, "_attributes, swig_", mangled_classname, "_bases };\n\n", NIL); + // Printv(s_cmd_tab, tab4, "{ SWIG_prefix \"", class_name, "\", (swig_wrapper_func) SWIG_ObjectConstructor, &_wrap_class_", mangled_classname, "},\n", NIL); + Delete(t); + Delete(mangled_classname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * memberfunctionHandler() + * ------------------------------------------------------------ */ + + virtual int memberfunctionHandler(Node *n) { + String *name = Getattr(n, "name"); + String *iname = GetChar(n, "sym:name"); + //Printf(stdout,"memberfunctionHandler %s %s\n",name,iname); + + // Special case unary minus: LUA passes two parameters for the + // wrapper function while we want only one. Tell our + // functionWrapper to ignore a parameter. + + if (Cmp(Getattr(n, "sym:name"), "__unm") == 0) { + //Printf(stdout, "unary minus: ignore one argument\n"); + SetInt(n, "lua:ignore_args", 1); + } + + String *realname, *rname; + + current = MEMBER_FUNC; + Language::memberfunctionHandler(n); + current = NO_CPP; + + realname = iname ? iname : name; + rname = Swig_name_wrapper(Swig_name_member(class_name, realname)); + if (!Getattr(n, "sym:nextSibling")) { + Printv(s_methods_tab, tab4, "{\"", realname, "\", ", rname, "}, \n", NIL); + } + Delete(rname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * membervariableHandler() + * ------------------------------------------------------------ */ + + virtual int membervariableHandler(Node *n) { + // REPORT("membervariableHandler",n); + String *symname = Getattr(n, "sym:name"); + String *gname, *sname; + + current = MEMBER_VAR; + Language::membervariableHandler(n); + current = NO_CPP; + gname = Swig_name_wrapper(Swig_name_get(Swig_name_member(class_name, symname))); + if (!GetFlag(n, "feature:immutable")) { + sname = Swig_name_wrapper(Swig_name_set(Swig_name_member(class_name, symname))); + } else { + //sname = NewString("0"); + sname = NewString("SWIG_Lua_set_immutable"); // error message + } + Printf(s_attr_tab,"%s{ \"%s\", %s, %s},\n",tab4,symname,gname,sname); + Delete(gname); + Delete(sname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * constructorHandler() + * + * Method for adding C++ member constructor + * ------------------------------------------------------------ */ + + virtual int constructorHandler(Node *n) { + // REPORT("constructorHandler", n); + current = CONSTRUCTOR; + Language::constructorHandler(n); + current = NO_CPP; + constructor_name = NewString(Getattr(n, "sym:name")); + have_constructor = 1; + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * destructorHandler() + * ------------------------------------------------------------ */ + + virtual int destructorHandler(Node *n) { + REPORT("destructorHandler", n); + current = DESTRUCTOR; + Language::destructorHandler(n); + current = NO_CPP; + have_destructor = 1; + destructor_action = Getattr(n, "wrap:action"); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * staticmemberfunctionHandler() + * + * Wrap a static C++ function + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + current = STATIC_FUNC; + return Language::staticmemberfunctionHandler(n); + } + + /* ------------------------------------------------------------ + * memberconstantHandler() + * + * Create a C++ constant + * ------------------------------------------------------------ */ + + virtual int memberconstantHandler(Node *n) { + // REPORT("memberconstantHandler",n); + return Language::memberconstantHandler(n); + } + + /* --------------------------------------------------------------------- + * staticmembervariableHandler() + * --------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + // REPORT("staticmembervariableHandler",n); + current = STATIC_VAR; + return Language::staticmembervariableHandler(n); + } + + /* --------------------------------------------------------------------- + * external runtime generation + * --------------------------------------------------------------------- */ + + /* This is to support the usage + SWIG -external-runtime <filename> + The code consists of two functions: + String *runtimeCode() // returns a large string with all the runtimes in + String *defaultExternalRuntimeFilename() // returns the default filename + I am writing a generic solution, even though SWIG-Lua only has one file right now... + */ + String *runtimeCode() { + String *s = NewString(""); + const char *filenames[] = { "luarun.swg", 0 + } + ; // must be 0 termiated + String *sfile; + for (int i = 0; filenames[i] != 0; i++) { + sfile = Swig_include_sys(filenames[i]); + if (!sfile) { + Printf(stderr, "*** Unable to open '%s'\n", filenames[i]); + } else { + Append(s, sfile); + Delete(sfile); + } + } + + return s; + } + + String *defaultExternalRuntimeFilename() { + return NewString("swigluarun.h"); + } + + /* --------------------------------------------------------------------- + * helpers + * --------------------------------------------------------------------- */ + + /* This is to convert the string of Lua code into a proper string, which can then be + emitted into the C/C++ code. + Basically is is a lot of search & replacing of odd sequences + */ + void EscapeCode(String* str) + { + //Printf(f_runtime,"/* original luacode:[[[\n%s\n]]]\n*/\n",str); + Chop(str); // trim + Replace(str,"\\","\\\\",DOH_REPLACE_ANY); // \ to \\ (this must be done first) + Replace(str,"\"","\\\"",DOH_REPLACE_ANY); // " to \" + Replace(str,"\n","\\n\"\n \"",DOH_REPLACE_ANY); // \n to \n"\n" (ie quoting every line) + //Printf(f_runtime,"/* hacked luacode:[[[\n%s\n]]]\n*/\n",str); + } +}; + +/* NEW LANGUAGE NOTE:*********************************************** + in order to add you language into swig, you need to make the following changes: + - write this file (obviously) + - add into the makefile (not 100% clear on how to do this) + - edit swigmain.cxx to add your module + +near the top of swigmain.cxx, look for this code & add you own codes +======= begin change ========== +extern "C" { + Language *swig_tcl(void); + Language *swig_python(void); + //etc,etc,etc... + Language *swig_lua(void); // this is my code +} + + //etc,etc,etc... + +swig_module modules[] = { + {"-guile", swig_guile, "Guile"}, + {"-java", swig_java, "Java"}, + //etc,etc,etc... + {"-lua", swig_lua, "Lua"}, // this is my code + {NULL, NULL, NULL} // this must come at the end of the list +}; +======= end change ========== + +This is all that is needed + +NEW LANGUAGE NOTE:END ************************************************/ + +/* ----------------------------------------------------------------------------- + * swig_lua() - Instantiate module + * ----------------------------------------------------------------------------- */ + +extern "C" Language *swig_lua(void) { + return new LUA(); +} |
