| /* ----------------------------------------------------------------------------- | |
| * 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. | |
| * | |
| * 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) | |
| * ver010 | |
| Added support for embedded Lua. Try swig -lua -help for more information | |
| */ | |
| #include "swigmod.h" | |
| #include "cparse.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 it's 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 (Iterator it = First(d); it.item; it = Next(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); | |
| } | |
| } | |
| extern "C" { | |
| static int compareByLen(const DOH *f, const DOH *s) { | |
| return Len(s) - Len(f); | |
| } | |
| } | |
| /* 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 = "\ | |
| Lua Options (available with -lua)\n\ | |
| -elua - Generates LTR compatible wrappers for smaller devices running elua\n\ | |
| -eluac - LTR compatible wrappers in \"crass compress\" mode for elua\n\ | |
| -elua-emulate - Emulates behaviour of eLua. Useful only for testing.\n\ | |
| Incompatible with -elua/-eluac options.\n\ | |
| -nomoduleglobal - Do not register the module name as a global variable \n\ | |
| but return the module table from calls to require.\n\ | |
| \n"; | |
| static int nomoduleglobal = 0; | |
| static int elua_ltr = 0; | |
| static int eluac_ltr = 0; | |
| static int elua_emulate = 0; | |
| // Toggle for generating backward-compatible ClassName_member style names alongside the | |
| // scoped form. Always 1 at module scope: classHandler() and enumDeclaration() locally | |
| // save/restore around 0 when descending into an %nspace context, suppressing the | |
| // duplicate names for static members, constants and enum values nested in that scope. | |
| static int old_compatible_names = 1; | |
| /* 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; | |
| File *f_directors; | |
| File *f_directors_h; | |
| String *s_luacode; // luacode to be called during init | |
| String *module; // name of the module | |
| // Parameters for current class. NIL if not parsing class | |
| int have_constructor; | |
| int have_destructor; | |
| String *destructor_action; | |
| // This variable holds the name of the current class in Lua. Usually it is | |
| // the same as C++ class name, but rename directives can change it. | |
| String *proxy_class_name; | |
| // This is a so called fully qualified symname - the above proxy class name | |
| // prepended with class namespace. If class Lua name is the same as class C++ name, | |
| // then it is basically C++ fully qualified name with colons replaced with dots. | |
| String *full_proxy_class_name; | |
| // All static methods and/or variables are treated as if they were in the | |
| // special C++ namespace $(classname).SwigStatic. This is internal mechanism only | |
| // and is not visible to user in any manner. This variable holds the name | |
| // of such pseudo-namespace a.k.a the result of above expression evaluation | |
| String *class_static_nspace; | |
| // This variable holds the name of generated C function that acts as a constructor | |
| // for the currently parsed class. | |
| String *constructor_name; | |
| // Many wrappers forward calls to each other, for example staticmembervariableHandler | |
| // forwards calls to variableHandler, which, in turn, makes to call to functionWrapper. | |
| // In order to access information about whether it is a static member of class or just | |
| // a plain old variable, the current array is kept and used as a 'log' of the call stack. | |
| enum TState { | |
| NO_CPP, | |
| VARIABLE, | |
| GLOBAL_FUNC, | |
| GLOBAL_VAR, | |
| MEMBER_FUNC, | |
| CONSTRUCTOR, | |
| DESTRUCTOR, | |
| MEMBER_VAR, | |
| STATIC_FUNC, | |
| STATIC_VAR, | |
| STATIC_CONST, // enums and things like static const int x = 5; | |
| ENUM_CONST, // This is only needed for backward compatibility in C mode | |
| STATES_COUNT | |
| }; | |
| bool current[STATES_COUNT]; | |
| public: | |
| /* --------------------------------------------------------------------- | |
| * LUA() | |
| * | |
| * Initialize member data | |
| * --------------------------------------------------------------------- */ | |
| LUA() : | |
| f_begin(0), | |
| f_runtime(0), | |
| f_header(0), | |
| f_wrappers(0), | |
| f_init(0), | |
| f_initbeforefunc(0), | |
| f_directors(0), | |
| f_directors_h(0), | |
| s_luacode(0), | |
| module(0), | |
| have_constructor(0), | |
| have_destructor(0), | |
| destructor_action(0), | |
| proxy_class_name(0), | |
| full_proxy_class_name(0), | |
| class_static_nspace(0), | |
| constructor_name(0) { | |
| for (int i = 0; i < STATES_COUNT; i++) | |
| current[i] = false; | |
| /* Enable director support */ | |
| director_multiple_inheritance = 1; | |
| directorLanguage(1); | |
| } | |
| /* NEW LANGUAGE NOTE:*********************************************** | |
| This is called to initialise 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, stdout); | |
| } else if (strcmp(argv[i], "-nomoduleglobal") == 0) { | |
| nomoduleglobal = 1; | |
| Swig_mark_arg(i); | |
| } else if (strcmp(argv[i], "-elua") == 0) { | |
| elua_ltr = 1; | |
| Swig_mark_arg(i); | |
| } else if (strcmp(argv[i], "-eluac") == 0) { | |
| eluac_ltr = 1; | |
| Swig_mark_arg(i); | |
| } else if (strcmp(argv[i], "-elua-emulate") == 0) { | |
| Swig_mark_arg(i); | |
| elua_emulate = 1; | |
| } | |
| } | |
| } | |
| if (elua_emulate && (eluac_ltr || elua_ltr)) { | |
| Printf(stderr, "Cannot have -elua-emulate with either -eluac or -elua\n"); | |
| Swig_arg_error(); | |
| } | |
| // Set elua_ltr if elua_emulate is requested | |
| if (elua_emulate) | |
| elua_ltr = 1; | |
| /* 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"); | |
| /* 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 */ | |
| 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); | |
| Exit(EXIT_FAILURE); | |
| } | |
| f_runtime = NewString(""); | |
| f_init = NewString(""); | |
| f_header = NewString(""); | |
| f_wrappers = NewString(""); | |
| f_initbeforefunc = NewString(""); | |
| f_directors = NewString(""); | |
| f_directors_h = 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); | |
| Swig_register_filebyname("director", f_directors); | |
| Swig_register_filebyname("director_h", f_directors_h); | |
| s_luacode = NewString(""); | |
| Swig_register_filebyname("luacode", s_luacode); | |
| current[NO_CPP] = true; | |
| /* Standard stuff for the SWIG runtime section */ | |
| Swig_banner(f_begin); | |
| Swig_obligatory_macros(f_runtime, "LUA"); | |
| emitLuaFlavor(f_runtime); | |
| if (nomoduleglobal) { | |
| Printf(f_runtime, "#define SWIG_LUA_NO_MODULE_GLOBAL\n"); | |
| } else { | |
| Printf(f_runtime, "#define SWIG_LUA_MODULE_GLOBAL\n"); | |
| } | |
| /* Check if directors are enabled for this module */ | |
| Node *mod = Getattr(n, "module"); | |
| if (mod) { | |
| Node *options = Getattr(mod, "options"); | |
| if (options && Getattr(options, "directors")) { | |
| allow_directors(); | |
| if (Getattr(options, "dirprot")) { | |
| allow_dirprot(); | |
| } | |
| } | |
| } | |
| // 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", module); | |
| 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); | |
| /* Insert director runtime into the f_runtime file if directors are enabled */ | |
| if (Swig_directors_enabled()) { | |
| Printf(f_runtime, "#define SWIG_DIRECTORS\n"); | |
| Swig_insert_file("director_common.swg", f_runtime); | |
| Swig_insert_file("director.swg", f_runtime); | |
| } | |
| Printf(f_init, "/* exec Lua code if applicable */\nSWIG_Lua_dostring(L,SWIG_LUACODE);\n"); | |
| Printf(f_init, "}\n"); | |
| // Done. Close up the module & write to the wrappers | |
| closeNamespaces(f_wrappers); | |
| Printf(f_wrappers, "#ifdef __cplusplus\n}\n#endif\n"); | |
| 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); | |
| /* Emit director header declarations */ | |
| if (Swig_directors_enabled()) { | |
| Dump(f_directors_h, f_begin); | |
| } | |
| Dump(f_wrappers, f_begin); | |
| if (Swig_directors_enabled()) { | |
| Dump(f_directors, f_begin); | |
| } | |
| Dump(f_initbeforefunc, f_begin); | |
| /* for the Lua code it needs to be properly escaped 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(f_header); | |
| Delete(f_wrappers); | |
| Delete(f_init); | |
| Delete(f_initbeforefunc); | |
| Delete(f_directors); | |
| Delete(f_directors_h); | |
| Delete(f_runtime); | |
| Delete(f_begin); | |
| /* Done */ | |
| return SWIG_OK; | |
| } | |
| /* ------------------------------------------------------------ | |
| * importDirective() | |
| * ------------------------------------------------------------ */ | |
| virtual int importDirective(Node *n) { | |
| return Language::importDirective(n); | |
| } | |
| /* ------------------------------------------------------------ | |
| * cDeclaration() | |
| * It copies sym:name to lua:name to preserve its original value | |
| * ------------------------------------------------------------ */ | |
| virtual int cDeclaration(Node *n) { | |
| // class 'Language' is messing with symname in a really heavy way. | |
| // Although documentation states that sym:name is a name in | |
| // the target language space, it is not true. sym:name and | |
| // its derivatives are used in various places, including | |
| // behind-the-scene C code generation. The best way is not to | |
| // touch it at all. | |
| // But we need to know what was the name of function/variable | |
| // etc that user desired, that's why we store correct symname | |
| // as lua:name | |
| String *symname = Getattr(n, "sym:name"); | |
| if (symname) | |
| Setattr(n, "lua:name", symname); | |
| return Language::cDeclaration(n); | |
| } | |
| virtual int constructorDeclaration(Node *n) { | |
| Setattr(n, "lua:name", Getattr(n, "sym:name")); | |
| return Language::constructorDeclaration(n); | |
| } | |
| virtual int destructorDeclaration(Node *n) { | |
| Setattr(n, "lua:name", Getattr(n, "sym:name")); | |
| return Language::destructorDeclaration(n); | |
| } | |
| /* NEW LANGUAGE NOTE:*********************************************** | |
| This is it! | |
| you get this one right, and most of your work is done | |
| but it's going to take some file to get it working right | |
| quite a bit of this is generally boilerplate code | |
| (or stuff I don't understand) | |
| that which matters will have extra added comments | |
| NEW LANGUAGE NOTE:END *********************************************** */ | |
| /* --------------------------------------------------------------------- | |
| * functionWrapper() | |
| * | |
| * Create a function declaration and register it with the interpreter. | |
| * --------------------------------------------------------------------- */ | |
| /* ----------------------------------------------------------------------- | |
| * registerMethod() | |
| * | |
| * Determines wrap name of a method, its scope etc and calls | |
| * registerMethod overload with correct arguments | |
| * Overloaded variant adds method to the "methods" array of specified lua scope/class | |
| * ---------------------------------------------------------------------- */ | |
| void registerMethod(Node *n, bool overwrite = false, String *overwriteLuaScope = 0) { | |
| String *symname = Getattr(n, "sym:name"); | |
| assert(symname); | |
| if (Getattr(n, "sym:nextSibling")) | |
| return; | |
| // Lua scope. It is not symbol NSpace, it is the actual key to retrieve getCArraysHash. | |
| String *luaScope = luaCurrentSymbolNSpace(); | |
| if (overwrite) | |
| luaScope = overwriteLuaScope; | |
| String *wrapname = 0; | |
| String *mrename; | |
| if (current[NO_CPP] || !getCurrentClass()) { | |
| mrename = symname; | |
| } else { | |
| assert(!current[NO_CPP]); | |
| if (current[STATIC_FUNC] || current[MEMBER_FUNC]) { | |
| mrename = Swig_name_member(getNSpace(), getClassPrefix(), symname); | |
| } else { | |
| mrename = symname; | |
| } | |
| } | |
| wrapname = Swig_name_wrapper(mrename); | |
| registerMethod(n, wrapname, luaScope); | |
| } | |
| /* ----------------------------------------------------------------------- | |
| * registerMethod() | |
| * | |
| * Add method to the "methods" C array of given namespace/class | |
| * ---------------------------------------------------------------------- */ | |
| void registerMethod(Node *n, String *wname, String *luaScope) { | |
| assert(n); | |
| Hash *nspaceHash = getCArraysHash(luaScope); | |
| String *s_ns_methods_tab = Getattr(nspaceHash, "methods"); | |
| String *lua_name = Getattr(n, "lua:name"); | |
| if (elua_ltr || eluac_ltr) | |
| Printv(s_ns_methods_tab, tab4, "{LSTRKEY(\"", lua_name, "\")", ", LFUNCVAL(", wname, ")", "},\n", NIL); | |
| else | |
| Printv(s_ns_methods_tab, tab4, "{ \"", lua_name, "\", ", wname, "},\n", NIL); | |
| // Add to the metatable if method starts with '__' | |
| const char *tn = Char(lua_name); | |
| if (tn[0] == '_' && tn[1] == '_' && !eluac_ltr) { | |
| String *metatable_tab = Getattr(nspaceHash, "metatable"); | |
| assert(metatable_tab); | |
| if (elua_ltr) | |
| Printv(metatable_tab, tab4, "{LSTRKEY(\"", lua_name, "\")", ", LFUNCVAL(", wname, ")", "},\n", NIL); | |
| else | |
| Printv(metatable_tab, tab4, "{ \"", lua_name, "\", ", wname, "},\n", NIL); | |
| } | |
| } | |
| virtual int functionWrapper(Node *n) { | |
| REPORT("functionWrapper", n); | |
| String *name = Getattr(n, "name"); | |
| String *iname = Getattr(n, "sym:name"); | |
| String *lua_name = Getattr(n, "lua:name"); | |
| assert(lua_name); | |
| SwigType *returntype = Getattr(n, "type"); | |
| ParmList *l = Getattr(n, "parms"); | |
| Parm *p; | |
| String *tm; | |
| int i; | |
| // Printf(stdout,"functionWrapper %s %s %d\n",name,iname,current); | |
| String *overname = 0; | |
| if (Getattr(n, "sym:overloaded")) { | |
| overname = Getattr(n, "sym:overname"); | |
| } else { | |
| if (!luaAddSymbol(lua_name, n)) { | |
| return SWIG_ERROR; | |
| } | |
| // Check if this is a duplicate friend function that should be skipped | |
| if (GetFlag(n, "lua:duplicate_friend")) { | |
| return SWIG_OK; | |
| } | |
| } | |
| /* NEW LANGUAGE NOTE:*********************************************** | |
| the wrapper object holds all the wrapper 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); | |
| } | |
| if (current[CONSTRUCTOR]) { | |
| if (constructor_name != 0) | |
| Delete(constructor_name); | |
| constructor_name = Copy(wname); | |
| } | |
| /* NEW LANGUAGE NOTE:*********************************************** | |
| the format of a lua fn is: | |
| static int wrap_XXX(lua_State* L){...} | |
| this line adds this into the wrapper code | |
| NEW LANGUAGE NOTE:END *********************************************** */ | |
| Printv(f->def, "static int ", wname, "(lua_State* L) {", NIL); | |
| // SWIG_fail in lua leads to a call to lua_error() which calls longjmp() | |
| // which means the destructors of any live function-local C++ objects won't | |
| // get run. To avoid this happening, we wrap almost everything in the | |
| // function in a block, and end that right before lua_error() at which | |
| // point those destructors will get called. | |
| if (CPlusPlus) | |
| Append(f->def, "\n{"); | |
| /* 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_parm_typemaps(l, f); | |
| /* Director upcall check - for director classes, we need to detect if we're | |
| being called from within a director method callback (upcall). This is used to decide | |
| whether to call the parent class method directly or use virtual dispatch. | |
| When upcall is true, we call the parent class method to avoid infinite recursion. | |
| NOTE: The actual check is done after arguments are parsed (below). */ | |
| String *nodeType = Getattr(n, "nodeType"); | |
| int destructor = (nodeType && !Cmp(nodeType, "destructor")); | |
| int director_method = is_member_director(n) && !is_smart_pointer() && !destructor; | |
| if (director_method) { | |
| Wrapper_add_local(f, "director", "Swig::Director *director = 0"); | |
| Wrapper_add_local(f, "upcall", "bool upcall = false"); | |
| } | |
| 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"); | |
| } | |
| /* 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 in 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; | |
| char source[64]; | |
| Printf(argument_check, "SWIG_check_num_args(\"%s\",%d,%d)\n", Swig_name_str(n), num_required + args_to_ignore, num_arguments + args_to_ignore); | |
| for (i = 0, p = l; i < num_arguments; i++) { | |
| p = emit_ignored_in_typemaps(p, argument_parse); | |
| SwigType *pt = Getattr(p, "type"); | |
| /* Look for an input typemap */ | |
| snprintf(source, sizeof(source), "%d", i + 1); | |
| if ((tm = Getattr(p, "tmap:in"))) { | |
| 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,\"%(escape)s\");\n", Swig_name_str(n), 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 don't 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; | |
| } | |
| } | |
| p = emit_ignored_in_typemaps(p, argument_parse); | |
| // add all argcheck code | |
| Printv(f->code, argument_check, argument_parse, NIL); | |
| /* Add director upcall check after arguments are parsed */ | |
| if (director_method) { | |
| Append(f->code, "try {\n"); | |
| Append(f->code, "director = SWIG_DIRECTOR_CAST(arg1);\n"); | |
| Append(f->code, "upcall = (director && director->swig_is_upcall_active());\n"); | |
| } | |
| /* 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"))) { | |
| 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"))) { | |
| 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, "$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); | |
| } | |
| } | |
| // Remember C name of the wrapping function | |
| Setattr(n, "wrap:name", wname); | |
| /* Emit director dynamic cast for protected/non-public member access */ | |
| if (Swig_director_emit_dynamic_cast(n, f)) { | |
| /* Add protection */ | |
| Append(f->code, "if (!darg) {\n"); | |
| Append(f->code, " Swig::DirectorMethodException::raise(\"'self' is not a director\");\n"); | |
| Append(f->code, "}\n"); | |
| } | |
| /* Emit the function call */ | |
| String *actioncode = emit_action(n); | |
| if (director_method) { | |
| Append(actioncode, "} catch (Swig::DirectorException &e) {\n"); | |
| Append(actioncode, " SWIG_Lua_pusherrstring(L, e.what());\n"); | |
| Append(actioncode, " SWIG_fail;\n"); | |
| Append(actioncode, "}\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, Swig_cresult_name(), 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++; | |
| 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(returntype, 0), name); | |
| } | |
| emit_return_variable(n, returntype, f); | |
| /* For director constructors, connect the director to the Lua object */ | |
| if (current[CONSTRUCTOR] && Swig_directorclass(n)) { | |
| Printf(f->code, "{\n"); | |
| Printf(f->code, " Swig::Director *director = SWIG_DIRECTOR_CAST(%s);\n", Swig_cresult_name()); | |
| /* Use lua_gettop(L) instead of SWIG_arg because SWIG_arg is the return count (1), | |
| * but the userdata is at the top of the stack which may be at a different position | |
| * if there were constructor arguments on the stack */ | |
| Printf(f->code, " if (director) director->swig_connect_director(L, lua_gettop(L));\n"); | |
| Printf(f->code, "}\n"); | |
| } | |
| /* 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, Swig_cresult_name(), 0))) { | |
| Printf(f->code, "%s\n", tm); | |
| } | |
| } | |
| /* See if there is any return cleanup code */ | |
| if ((tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0))) { | |
| 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, "\nfail: SWIGUNUSED;\n", "$cleanup", NIL); | |
| if (CPlusPlus) | |
| Append(f->code, "}\n"); | |
| Printv(f->code, "lua_error(L);\n", NIL); | |
| // lua_error() calls longjmp() but we need a dummy return to avoid compiler | |
| // warnings. | |
| Printv(f->code, "return 0;\n", NIL); | |
| Printf(f->code, "}\n"); | |
| /* Substitute the cleanup code */ | |
| Replaceall(f->code, "$cleanup", cleanup); | |
| bool isvoid = !Cmp(returntype, "void"); | |
| emit_isvoid_special_variables(n, f->code, isvoid); | |
| /* Substitute the function name */ | |
| Replaceall(f->code, "$symname", iname); | |
| Replaceall(f->code, "$result", Swig_cresult_name()); | |
| /* Dump the function out */ | |
| /* in Lua we will not emit the destructor as a wrapper 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. */ | |
| int result = SWIG_OK; | |
| if (Getattr(n, "sym:overloaded")) { | |
| if (!Getattr(n, "sym:nextSibling")) { | |
| result = dispatchFunction(n); | |
| } | |
| } | |
| Delete(argument_check); | |
| Delete(argument_parse); | |
| Delete(cleanup); | |
| Delete(outarg); | |
| // Delete(description); | |
| DelWrapper(f); | |
| return result; | |
| } | |
| /* ------------------------------------------------------------ | |
| * 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 | |
| most of the real work in again typemaps: | |
| look for %typecheck(SWIG_TYPECHECK_*) in the .swg file | |
| NEW LANGUAGE NOTE:END *********************************************** */ | |
| int dispatchFunction(Node *n) { | |
| // REPORT("dispatchFunction", n); | |
| /* Last node in overloaded chain */ | |
| int maxargs; | |
| bool check_emitted = false; | |
| String *tmp = NewString(""); | |
| String *dispatch = Swig_overload_dispatch(n, "return %s(L);", &maxargs, &check_emitted); | |
| /* Generate a dispatch wrapper for all overloaded functions */ | |
| Wrapper *f = NewWrapper(); | |
| String *symname = Getattr(n, "sym:name"); | |
| String *lua_name = Getattr(n, "lua:name"); | |
| assert(lua_name); | |
| String *wname = Swig_name_wrapper(symname); | |
| // Printf(stdout,"Swig_overload_dispatch %s %s '%s' %d\n",symname,wname,dispatch,maxargs); | |
| if (!luaAddSymbol(lua_name, n)) { | |
| DelWrapper(f); | |
| Delete(dispatch); | |
| Delete(tmp); | |
| return SWIG_ERROR; | |
| } | |
| Printv(f->def, "static int ", wname, "(lua_State* L) {", NIL); | |
| Wrapper_add_local(f, "argc", "int argc"); | |
| if (maxargs > 0 && check_emitted) { | |
| 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 { | |
| String *fulldecl = Swig_name_decl(sibl); | |
| Printf(protoTypes, "\n\" %(escape)s\\n\"", fulldecl); | |
| Delete(fulldecl); | |
| } while ((sibl = Getattr(sibl, "sym:nextSibling"))); | |
| Printf(f->code, | |
| "SWIG_Lua_pusherrstring(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); | |
| // Remember C name of the wrapping function | |
| Setattr(n, "wrap:name", wname); | |
| if (current[CONSTRUCTOR]) { | |
| if (constructor_name != 0) | |
| Delete(constructor_name); | |
| constructor_name = Copy(wname); | |
| } | |
| DelWrapper(f); | |
| Delete(dispatch); | |
| Delete(tmp); | |
| return SWIG_OK; | |
| } | |
| /* ------------------------------------------------------------ | |
| * Add variable to "attributes" C arrays of given namespace or class. | |
| * Input is node. Based on the state of "current" array it determines | |
| * the name of the getter function, setter function etc and calls | |
| * registerVariable overload with necessary params. | |
| * Lua scope could be overwritten. (Used only for backward compatibility) | |
| * ------------------------------------------------------------ */ | |
| void registerVariable(Node *n, bool overwrite = false, String *overwriteLuaScope = 0) { | |
| int assignable = !is_immutable(n); | |
| String *symname = Getattr(n, "sym:name"); | |
| assert(symname); | |
| // Lua scope. It is not symbol NSpace, it is the actual key to retrieve getCArraysHash. | |
| String *luaScope = luaCurrentSymbolNSpace(); | |
| if (overwrite) | |
| luaScope = overwriteLuaScope; | |
| // Getter and setter | |
| String *getName = 0; | |
| String *setName = 0; | |
| String *mrename = 0; | |
| if (current[NO_CPP] || !getCurrentClass()) { | |
| // Global variable | |
| getName = Swig_name_get(getNSpace(), symname); | |
| if (assignable) | |
| setName = Swig_name_set(getNSpace(), symname); | |
| } else { | |
| assert(!current[NO_CPP]); | |
| if (current[STATIC_VAR]) { | |
| mrename = Swig_name_member(getNSpace(), getClassPrefix(), symname); | |
| getName = Swig_name_get(0, mrename); | |
| if (assignable) | |
| setName = Swig_name_set(0, mrename); | |
| } else if (current[MEMBER_VAR]) { | |
| mrename = Swig_name_member(0, getClassPrefix(), symname); | |
| getName = Swig_name_get(getNSpace(), mrename); | |
| if (assignable) | |
| setName = Swig_name_set(getNSpace(), mrename); | |
| } else { | |
| assert(false); | |
| } | |
| } | |
| getName = Swig_name_wrapper(getName); | |
| if (setName) | |
| setName = Swig_name_wrapper(setName); | |
| registerVariable(luaScope, n, getName, setName); | |
| } | |
| /* ------------------------------------------------------------ | |
| * registerVariable() | |
| * | |
| * Add variable to the "attributes" (or "get"/"set" in | |
| * case of elua_ltr) C arrays of given namespace or class | |
| * ------------------------------------------------------------ */ | |
| void registerVariable(String *lua_nspace_or_class_name, Node *n, String *getName, String *setName) { | |
| String *unassignable = NewString("SWIG_Lua_set_immutable"); | |
| if (setName == 0 || GetFlag(n, "feature:immutable")) { | |
| setName = unassignable; | |
| } | |
| Hash *nspaceHash = getCArraysHash(lua_nspace_or_class_name); | |
| String *s_ns_methods_tab = Getattr(nspaceHash, "methods"); | |
| String *s_ns_var_tab = Getattr(nspaceHash, "attributes"); | |
| String *lua_name = Getattr(n, "lua:name"); | |
| if (elua_ltr) { | |
| String *s_ns_dot_get = Getattr(nspaceHash, "get"); | |
| String *s_ns_dot_set = Getattr(nspaceHash, "set"); | |
| Printf(s_ns_dot_get, "%s{LSTRKEY(\"%s\"), LFUNCVAL(%s)},\n", tab4, lua_name, getName); | |
| Printf(s_ns_dot_set, "%s{LSTRKEY(\"%s\"), LFUNCVAL(%s)},\n", tab4, lua_name, setName); | |
| } else if (eluac_ltr) { | |
| Printv(s_ns_methods_tab, tab4, "{LSTRKEY(\"", lua_name, "_get", "\")", ", LFUNCVAL(", getName, ")", "},\n", NIL); | |
| Printv(s_ns_methods_tab, tab4, "{LSTRKEY(\"", lua_name, "_set", "\")", ", LFUNCVAL(", setName, ")", "},\n", NIL); | |
| } else { | |
| Printf(s_ns_var_tab, "%s{ \"%s\", %s, %s },\n", tab4, lua_name, getName, setName); | |
| } | |
| } | |
| /* ------------------------------------------------------------ | |
| * 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 *lua_name = Getattr(n, "lua:name"); | |
| assert(lua_name); | |
| (void)lua_name; | |
| current[VARIABLE] = true; | |
| // let SWIG generate the wrappers | |
| int result = Language::variableWrapper(n); | |
| // It is impossible to use registerVariable, because sym:name of the Node is currently | |
| // in an undefined state - the callees of this function may have modified it. | |
| // registerVariable should be used from respective callees.* | |
| current[VARIABLE] = false; | |
| return result; | |
| } | |
| /* ------------------------------------------------------------ | |
| * Add constant to appropriate C array. constantRecord is an array record. | |
| * Actually, in current implementation it is resolved consttab typemap | |
| * ------------------------------------------------------------ */ | |
| void registerConstant(String *nspace, String *constantRecord) { | |
| Hash *nspaceHash = getCArraysHash(nspace); | |
| String *s_const_tab = 0; | |
| if (eluac_ltr || elua_ltr) | |
| // In elua everything goes to "methods" tab | |
| s_const_tab = Getattr(nspaceHash, "methods"); | |
| else | |
| s_const_tab = Getattr(nspaceHash, "constants"); | |
| assert(s_const_tab); | |
| Printf(s_const_tab, " %s,\n", constantRecord); | |
| if (eluac_ltr || elua_ltr) { | |
| s_const_tab = Getattr(nspaceHash, "constants"); | |
| assert(s_const_tab); | |
| Printf(s_const_tab, " %s,\n", constantRecord); | |
| } | |
| } | |
| /* ------------------------------------------------------------ | |
| * constantWrapper() | |
| * ------------------------------------------------------------ */ | |
| virtual int constantWrapper(Node *n) { | |
| REPORT("constantWrapper", n); | |
| String *name = Getattr(n, "name"); | |
| String *iname = Getattr(n, "sym:name"); | |
| String *lua_name = Getattr(n, "lua:name"); | |
| if (lua_name == 0) | |
| lua_name = iname; | |
| String *nsname = Copy(iname); | |
| SwigType *type = Getattr(n, "type"); | |
| String *value = Getattr(n, "value"); | |
| String *tm; | |
| String *lua_name_v2 = 0; | |
| String *tm_v2 = 0; | |
| String *iname_v2 = 0; | |
| Node *n_v2 = 0; | |
| if (!luaAddSymbol(lua_name, n)) | |
| return SWIG_ERROR; | |
| Swig_save("lua_constantMember", n, "sym:name", NIL); | |
| Setattr(n, "sym:name", lua_name); | |
| /* 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, "$value", value); | |
| Replaceall(tm, "$nsname", nsname); | |
| registerConstant(luaCurrentSymbolNSpace(), tm); | |
| } else if ((tm = Swig_typemap_lookup("constcode", n, name, 0))) { | |
| Replaceall(tm, "$value", value); | |
| Replaceall(tm, "$nsname", nsname); | |
| Printf(f_init, "%s\n", tm); | |
| } else { | |
| Delete(nsname); | |
| nsname = 0; | |
| Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value.\n"); | |
| Swig_restore(n); | |
| return SWIG_NOWRAP; | |
| } | |
| // v2 compatibility mode: add symbols with class prefix to NSpace | |
| // Skip this for nested classes to avoid duplicate symbol errors | |
| // (nested classes from different outer classes would have the same symbol name) | |
| bool make_v2_compatible = getCurrentClass() && old_compatible_names; | |
| bool in_nested_class = getCurrentClass() && Getattr(getCurrentClass(), "nested:outer") != 0; | |
| if (make_v2_compatible && !in_nested_class) { | |
| // Don't do anything for enums in C mode - they are already | |
| // wrapped correctly | |
| if (CPlusPlus || !current[ENUM_CONST]) { | |
| lua_name_v2 = Swig_name_member(0, proxy_class_name, lua_name); | |
| iname_v2 = Swig_name_member(0, proxy_class_name, iname); | |
| n_v2 = Copy(n); | |
| // For v2 compatibility, use NSpace for symbol registration | |
| // This ensures proper scoping even for nested classes | |
| String *v2_scope = getNSpace(); | |
| if (!luaAddSymbol(iname_v2, n, v2_scope)) { | |
| Swig_restore(n); | |
| return SWIG_ERROR; | |
| } | |
| Setattr(n_v2, "sym:name", lua_name_v2); | |
| tm_v2 = Swig_typemap_lookup("consttab", n_v2, name, 0); | |
| if (tm_v2) { | |
| Replaceall(tm_v2, "$value", value); | |
| Replaceall(tm_v2, "$nsname", nsname); | |
| registerConstant(getNSpace(), tm_v2); | |
| } else { | |
| tm_v2 = Swig_typemap_lookup("constcode", n_v2, name, 0); | |
| if (!tm_v2) { | |
| // This can't be. | |
| assert(false); | |
| Swig_restore(n); | |
| return SWIG_ERROR; | |
| } | |
| Replaceall(tm_v2, "$value", value); | |
| Replaceall(tm_v2, "$nsname", nsname); | |
| Printf(f_init, "%s\n", tm_v2); | |
| } | |
| Delete(n_v2); | |
| } | |
| } | |
| Swig_restore(n); | |
| 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 (!luaAddSymbol(wrapname, n)) | |
| return SWIG_ERROR; | |
| Hash *nspaceHash = getCArraysHash(getNSpace()); | |
| String *s_ns_methods_tab = Getattr(nspaceHash, "methods"); | |
| Printv(s_ns_methods_tab, tab4, "{ \"", symname, "\",", wrapname, "},\n", NIL); | |
| // return Language::nativeWrapper(n); // this does nothing... | |
| return SWIG_OK; | |
| } | |
| /* ------------------------------------------------------------ | |
| * enumDeclaration() | |
| * ------------------------------------------------------------ */ | |
| virtual int enumDeclaration(Node *n) { | |
| if (getCurrentClass() && (cplus_mode != PUBLIC)) | |
| return SWIG_NOWRAP; | |
| current[STATIC_CONST] = true; | |
| current[ENUM_CONST] = true; | |
| // There is some slightly specific behaviour with enums. Basically, | |
| // their NSpace may be tracked separately. The code below tries to work around | |
| // this issue to some degree. | |
| // The idea is the same as in classHandler - to drop old names generation if | |
| // enum is in class in namespace. | |
| const int old_compatible_names_saved = old_compatible_names; | |
| if (getNSpace() || (Getattr(n, "sym:nspace") != 0 && Len(Getattr(n, "sym:nspace")) > 0)) { | |
| old_compatible_names = 0; | |
| } | |
| int result = Language::enumDeclaration(n); | |
| current[STATIC_CONST] = false; | |
| current[ENUM_CONST] = false; | |
| old_compatible_names = old_compatible_names_saved; | |
| return result; | |
| } | |
| /* ------------------------------------------------------------ | |
| * enumvalueDeclaration() | |
| * ------------------------------------------------------------ */ | |
| virtual int enumvalueDeclaration(Node *n) { | |
| if (getCurrentClass() && (cplus_mode != PUBLIC)) | |
| return SWIG_NOWRAP; | |
| Swig_require("enumvalueDeclaration", n, "*name", "?value", "*sym:name", NIL); | |
| String *symname = Getattr(n, "sym:name"); | |
| String *value = Getattr(n, "value"); | |
| String *name = Getattr(n, "name"); | |
| String *tmpValue; | |
| Node *parent = parentNode(n); | |
| if (value) | |
| tmpValue = NewString(value); | |
| else | |
| tmpValue = NewString(name); | |
| Setattr(n, "value", tmpValue); | |
| Setattr(n, "name", tmpValue); /* for wrapping of enums in a namespace when emit_action is used */ | |
| if (GetFlag(parent, "scopedenum")) { | |
| symname = Swig_name_member(0, Getattr(parent, "sym:name"), symname); | |
| Setattr(n, "sym:name", symname); | |
| Delete(symname); | |
| } | |
| int result = constantWrapper(n); | |
| Delete(tmpValue); | |
| Swig_restore(n); | |
| return result; | |
| } | |
| /* ------------------------------------------------------------ | |
| * classDeclaration() | |
| * ------------------------------------------------------------ */ | |
| virtual int classDeclaration(Node *n) { | |
| return Language::classDeclaration(n); | |
| } | |
| /* ------------------------------------------------------------ | |
| * Helper function that adds record to appropriate C arrays | |
| * ------------------------------------------------------------ */ | |
| void registerClass(String *scope, String *wrap_class) { | |
| assert(wrap_class); | |
| Hash *nspaceHash = getCArraysHash(scope); | |
| String *ns_classes = Getattr(nspaceHash, "classes"); | |
| Printv(ns_classes, "&", wrap_class, ",\n", NIL); | |
| if (elua_ltr || eluac_ltr) { | |
| String *ns_methods = Getattr(nspaceHash, "methods"); | |
| Hash *class_hash = getCArraysHash(class_static_nspace); | |
| assert(class_hash); | |
| String *cls_methods = Getattr(class_hash, "methods:name"); | |
| assert(cls_methods); | |
| Printv(ns_methods, tab4, "{LSTRKEY(\"", proxy_class_name, "\")", ", LROVAL(", cls_methods, ")", "},\n", NIL); | |
| } | |
| } | |
| /* ------------------------------------------------------------ | |
| * classHandler() | |
| * ------------------------------------------------------------ */ | |
| virtual int classHandler(Node *n) { | |
| // REPORT("classHandler", n); | |
| String *mangled_full_proxy_class_name = 0; | |
| String *destructor_name = 0; | |
| String *nspace = getNSpace(); | |
| // Check if this is a nested class | |
| bool has_outerclass = Getattr(n, "nested:outer") != 0 && !GetFlag(n, "feature:flatnested"); | |
| // Save class local variables for nested classes support | |
| String *old_proxy_class_name = proxy_class_name; | |
| String *old_full_proxy_class_name = full_proxy_class_name; | |
| String *old_class_static_nspace = class_static_nspace; | |
| String *old_destructor_action = destructor_action; | |
| String *old_constructor_name = constructor_name; | |
| int old_have_constructor = have_constructor; | |
| int old_have_destructor = have_destructor; | |
| bool old_current_NO_CPP = current[NO_CPP]; | |
| constructor_name = 0; | |
| have_constructor = 0; | |
| have_destructor = 0; | |
| destructor_action = 0; | |
| class_static_nspace = 0; | |
| full_proxy_class_name = 0; | |
| proxy_class_name = 0; | |
| current[NO_CPP] = false; | |
| proxy_class_name = Getattr(n, "sym:name"); | |
| // For nested classes, we need to build the scope including outer classes | |
| String *registration_scope = 0; // Scope for registering the class in C arrays (with SwigStatic) | |
| String *symbol_scope = 0; // Scope for symbol registration (without SwigStatic) | |
| if (has_outerclass) { | |
| // Build the full path including outer classes | |
| String *outer_classes_prefix = NewString(""); | |
| for (Node *outer = Getattr(n, "nested:outer"); outer != 0; outer = Getattr(outer, "nested:outer")) { | |
| String *outer_name = Getattr(outer, "sym:name"); | |
| if (outer_name) { | |
| if (Len(outer_classes_prefix) > 0) { | |
| Push(outer_classes_prefix, NSPACE_SEPARATOR); | |
| } | |
| Push(outer_classes_prefix, outer_name); | |
| } | |
| } | |
| // Build full path to outer class | |
| String *outer_full_path = NewString(""); | |
| if (nspace && Len(nspace) > 0) { | |
| Printv(outer_full_path, nspace, NSPACE_SEPARATOR, NIL); | |
| } | |
| Printv(outer_full_path, outer_classes_prefix, NIL); | |
| // Symbol scope is the full path to the outer class (for duplicate detection) | |
| symbol_scope = Copy(outer_full_path); | |
| // Registration scope is the SwigStatic part of the outer class (for C array registration) | |
| registration_scope = NewStringf("%s%sSwigStatic", outer_full_path, NSPACE_SEPARATOR); | |
| // Build full_proxy_class_name including outer classes | |
| if (nspace == 0 || Len(nspace) == 0) { | |
| full_proxy_class_name = NewStringf("%s%s%s", outer_classes_prefix, NSPACE_SEPARATOR, proxy_class_name); | |
| } else { | |
| full_proxy_class_name = NewStringf("%s%s%s%s%s", nspace, NSPACE_SEPARATOR, outer_classes_prefix, NSPACE_SEPARATOR, proxy_class_name); | |
| } | |
| Delete(outer_classes_prefix); | |
| Delete(outer_full_path); | |
| } else { | |
| // Normal class (not nested) | |
| symbol_scope = nspace ? Copy(nspace) : 0; | |
| registration_scope = nspace ? Copy(nspace) : 0; | |
| if (nspace == 0) | |
| full_proxy_class_name = NewStringf("%s", proxy_class_name); | |
| else | |
| full_proxy_class_name = NewStringf("%s%s%s", nspace, NSPACE_SEPARATOR, proxy_class_name); | |
| } | |
| // We have to enforce nspace here, because technically we are already | |
| // inside class parsing (getCurrentClass != 0), but we should register | |
| // class in its parent namespace (or outer class for nested classes) | |
| if (!luaAddSymbol(proxy_class_name, n, symbol_scope)) { | |
| if (symbol_scope) | |
| Delete(symbol_scope); | |
| if (registration_scope) | |
| Delete(registration_scope); | |
| // Restore class local variables before returning error | |
| proxy_class_name = old_proxy_class_name; | |
| full_proxy_class_name = old_full_proxy_class_name; | |
| class_static_nspace = old_class_static_nspace; | |
| destructor_action = old_destructor_action; | |
| constructor_name = old_constructor_name; | |
| have_constructor = old_have_constructor; | |
| have_destructor = old_have_destructor; | |
| current[NO_CPP] = old_current_NO_CPP; | |
| return SWIG_ERROR; | |
| } | |
| if (symbol_scope) | |
| Delete(symbol_scope); | |
| assert(full_proxy_class_name); | |
| mangled_full_proxy_class_name = Swig_name_mangle_string(full_proxy_class_name); | |
| SwigType *t = Copy(Getattr(n, "name")); | |
| SwigType *fr_t = SwigType_typedef_resolve_all(t); /* Create fully resolved type */ | |
| SwigType *t_tmp = 0; | |
| t_tmp = SwigType_typedef_qualified(fr_t); // Temporary variable | |
| Delete(fr_t); | |
| fr_t = SwigType_strip_qualifiers(t_tmp); | |
| String *mangled_fr_t = 0; | |
| mangled_fr_t = SwigType_manglestr(fr_t); | |
| // not sure exactly how 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 (GetFlag(emitted, mangled_fr_t)) { | |
| full_proxy_class_name = 0; | |
| proxy_class_name = 0; | |
| if (registration_scope) | |
| Delete(registration_scope); | |
| // Restore class local variables before returning | |
| proxy_class_name = old_proxy_class_name; | |
| full_proxy_class_name = old_full_proxy_class_name; | |
| class_static_nspace = old_class_static_nspace; | |
| destructor_action = old_destructor_action; | |
| constructor_name = old_constructor_name; | |
| have_constructor = old_have_constructor; | |
| have_destructor = old_have_destructor; | |
| current[NO_CPP] = old_current_NO_CPP; | |
| return SWIG_NOWRAP; | |
| } | |
| SetFlag(emitted, mangled_fr_t); | |
| // We treat class T as both 'class' and 'namespace'. All static members, attributes | |
| // and constants are considered part of namespace T, all members - part of the 'class' | |
| // Now, here is a trick. Static methods, attributes and non-static methods and attributes | |
| // are described with same structures - swig_lua_attribute/swig_lua_method. Instead of calling | |
| // getCArraysHash(class name) to initialize things for static methods/attributes and then | |
| // manually doing same initialization for non-static methods, we call getCArraysHash 2 times: | |
| // 1) With name "class name" + "." + "SwigStatic" to initialize static things | |
| // 2) With "class name" to initialize non-static things | |
| Hash *instance_cls = getCArraysHash(full_proxy_class_name, false); | |
| assert(instance_cls); | |
| String *s_attr_tab_name = Getattr(instance_cls, "attributes:name"); | |
| String *s_methods_tab_name = Getattr(instance_cls, "methods:name"); | |
| SetFlag(instance_cls, "lua:no_namespaces"); | |
| SetFlag(instance_cls, "lua:no_classes"); | |
| SetFlag(instance_cls, "lua:class_instance"); | |
| /* There is no use for "constants", "classes" and "namespaces" arrays. | |
| * All constants are considered part of static part of class. | |
| */ | |
| class_static_nspace = NewStringf("%s%sSwigStatic", full_proxy_class_name, NSPACE_SEPARATOR); | |
| Hash *static_cls = getCArraysHash(class_static_nspace, false); | |
| assert(static_cls); | |
| SetFlag(static_cls, "lua:no_namespaces"); | |
| SetFlag(static_cls, "lua:class_static"); | |
| // Notifying instance_cls and static_cls hashes about each other | |
| Setattr(instance_cls, "lua:class_instance:static_hash", static_cls); | |
| Setattr(static_cls, "lua:class_static:instance_hash", instance_cls); | |
| const int old_compatible_names_saved = old_compatible_names; | |
| // If class has %nspace enabled, then generation of backward compatible names | |
| // should be disabled | |
| if (getNSpace()) { | |
| old_compatible_names = 0; | |
| } | |
| /* There is no use for "classes" and "namespaces" arrays. Subclasses are not supported | |
| * by SWIG and namespaces couldn't be nested inside classes (C++ Standard) | |
| */ | |
| // Generate normal wrappers | |
| Language::classHandler(n); | |
| old_compatible_names = old_compatible_names_saved; | |
| SwigType_add_pointer(t); | |
| // Catch all: eg. a class with only static functions and/or variables will not have 'remembered' | |
| String *wrap_class_name = Swig_name_wrapper(NewStringf("class_%s", mangled_full_proxy_class_name)); | |
| String *wrap_class = NewStringf("&%s", wrap_class_name); | |
| // Replace storing a pointer to underlying class with a smart pointer (intended for use with non-intrusive smart pointers) | |
| SwigType *smart = Getattr(n, "smart"); | |
| if (smart) { | |
| SwigType *psmart = Copy(smart); | |
| SwigType_add_pointer(psmart); | |
| SwigType_remember_clientdata(psmart, wrap_class); | |
| Delete(psmart); | |
| } | |
| SwigType_remember_clientdata(t, wrap_class); | |
| String *rt = Copy(getClassType()); | |
| SwigType_add_pointer(rt); | |
| // Adding class to appropriate namespace (or outer class's static part for nested classes) | |
| registerClass(registration_scope, wrap_class_name); | |
| Hash *nspaceHash = getCArraysHash(registration_scope); | |
| // Register the class structure with the type checker | |
| // Printf(f_init,"SWIG_TypeClientData(SWIGTYPE%s, (void *) &_wrap_class_%s);\n", SwigType_manglestr(t), mangled_full_proxy_class_name); | |
| // emit a function to be called to delete the object | |
| if (have_destructor) { | |
| destructor_name = NewStringf("swig_delete_%s", mangled_full_proxy_class_name); | |
| Printv(f_wrappers, "static void ", destructor_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"); | |
| } | |
| // Wrap constructor wrapper into one more proxy function. It will be used as class namespace __call method, thus | |
| // allowing both | |
| // Module.ClassName.StaticMethod to access static method/variable/constant | |
| // Module.ClassName() to create new object | |
| if (have_constructor) { | |
| assert(constructor_name); | |
| String *constructor_proxy_name = NewStringf("_proxy_%s", constructor_name); | |
| Printv(f_wrappers, "static int ", constructor_proxy_name, "(lua_State *L) {\n", NIL); | |
| Printv(f_wrappers, " assert(lua_istable(L,1));\n", NIL); | |
| Printv(f_wrappers, " lua_pushcfunction(L,", constructor_name, ");\n", NIL); | |
| Printv(f_wrappers, " assert(!lua_isnil(L,-1));\n", NIL); | |
| Printv(f_wrappers, " lua_replace(L,1); /* replace our table with real constructor */\n", NIL); | |
| Printv(f_wrappers, " lua_call(L,lua_gettop(L)-1,1);\n", NIL); | |
| Printv(f_wrappers, " return 1;\n}\n", NIL); | |
| Delete(constructor_name); | |
| constructor_name = constructor_proxy_name; | |
| if (elua_ltr) { | |
| String *static_cls_metatable_tab = Getattr(static_cls, "metatable"); | |
| assert(static_cls_metatable_tab); | |
| Printf(static_cls_metatable_tab, " {LSTRKEY(\"__call\"), LFUNCVAL(%s)},\n", constructor_name); | |
| } else if (eluac_ltr) { | |
| String *ns_methods_tab = Getattr(nspaceHash, "methods"); | |
| assert(ns_methods_tab); | |
| Printv(ns_methods_tab, tab4, "{LSTRKEY(\"", "new_", proxy_class_name, "\")", ", LFUNCVAL(", constructor_name, ")", "},\n", NIL); | |
| } | |
| } | |
| if (have_destructor) { | |
| if (eluac_ltr) { | |
| String *ns_methods_tab = Getattr(nspaceHash, "methods"); | |
| assert(ns_methods_tab); | |
| Printv(ns_methods_tab, tab4, "{LSTRKEY(\"", "free_", mangled_full_proxy_class_name, "\")", ", LFUNCVAL(", destructor_name, ")", "},\n", NIL); | |
| } | |
| } | |
| closeCArraysHash(full_proxy_class_name, f_wrappers); | |
| closeCArraysHash(class_static_nspace, f_wrappers); | |
| // Handle inheritance | |
| // note: with the idea of class hierarchies 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; | |
| 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; | |
| } | |
| // stores a null pointer & the name | |
| Printf(base_class, "0,"); | |
| Printf(base_class_names, "\"%s *\",", SwigType_namestr(bname)); | |
| b = Next(b); | |
| } | |
| } | |
| // First, print class static part | |
| printCArraysDefinition(class_static_nspace, proxy_class_name, f_wrappers); | |
| assert(mangled_full_proxy_class_name); | |
| assert(base_class); | |
| assert(base_class_names); | |
| assert(proxy_class_name); | |
| assert(full_proxy_class_name); | |
| // Then print class instance part | |
| Printv(f_wrappers, "static swig_lua_class *swig_", mangled_full_proxy_class_name, "_bases[] = {", base_class, "0};\n", NIL); | |
| Delete(base_class); | |
| Printv(f_wrappers, "static const char *swig_", mangled_full_proxy_class_name, "_base_names[] = {", base_class_names, "0};\n", NIL); | |
| Delete(base_class_names); | |
| Printv(f_wrappers, | |
| "static swig_lua_class _wrap_class_", | |
| mangled_full_proxy_class_name, | |
| " = { \"", | |
| proxy_class_name, | |
| "\", \"", | |
| full_proxy_class_name, | |
| "\", &SWIGTYPE", | |
| SwigType_manglestr(t), | |
| ",", | |
| NIL); | |
| if (have_constructor) { | |
| Printv(f_wrappers, constructor_name, NIL); | |
| Delete(constructor_name); | |
| constructor_name = 0; | |
| } else { | |
| Printf(f_wrappers, "0"); | |
| } | |
| if (have_destructor) { | |
| Printv(f_wrappers, ", ", destructor_name, NIL); | |
| } else { | |
| Printf(f_wrappers, ",0"); | |
| } | |
| Printf(f_wrappers, ", %s, %s, &%s", s_methods_tab_name, s_attr_tab_name, Getattr(static_cls, "cname")); | |
| if (!eluac_ltr) { | |
| Printf(f_wrappers, ", %s", Getattr(instance_cls, "metatable:name")); | |
| } else { | |
| Printf(f_wrappers, ", 0"); | |
| } | |
| Printf(f_wrappers, ", swig_%s_bases, swig_%s_base_names };\n\n", mangled_full_proxy_class_name, mangled_full_proxy_class_name); | |
| current[NO_CPP] = true; | |
| Delete(class_static_nspace); | |
| class_static_nspace = 0; | |
| Delete(mangled_full_proxy_class_name); | |
| mangled_full_proxy_class_name = 0; | |
| Delete(destructor_name); | |
| destructor_name = 0; | |
| Delete(full_proxy_class_name); | |
| full_proxy_class_name = 0; | |
| proxy_class_name = 0; | |
| if (registration_scope) | |
| Delete(registration_scope); | |
| // Restore class local variables for nested classes support | |
| proxy_class_name = old_proxy_class_name; | |
| full_proxy_class_name = old_full_proxy_class_name; | |
| class_static_nspace = old_class_static_nspace; | |
| destructor_action = old_destructor_action; | |
| constructor_name = old_constructor_name; | |
| have_constructor = old_have_constructor; | |
| have_destructor = old_have_destructor; | |
| current[NO_CPP] = old_current_NO_CPP; | |
| return SWIG_OK; | |
| } | |
| /* ------------------------------------------------------------ | |
| * memberfunctionHandler() | |
| * ------------------------------------------------------------ */ | |
| virtual int memberfunctionHandler(Node *n) { | |
| String *symname = 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(symname, "__unm") == 0) { | |
| // Printf(stdout, "unary minus: ignore one argument\n"); | |
| SetInt(n, "lua:ignore_args", 1); | |
| } | |
| current[MEMBER_FUNC] = true; | |
| Language::memberfunctionHandler(n); | |
| registerMethod(n); | |
| current[MEMBER_FUNC] = false; | |
| return SWIG_OK; | |
| } | |
| /* ------------------------------------------------------------ | |
| * membervariableHandler() | |
| * ------------------------------------------------------------ */ | |
| virtual int membervariableHandler(Node *n) { | |
| // REPORT("membervariableHandler",n); | |
| current[MEMBER_VAR] = true; | |
| Language::membervariableHandler(n); | |
| registerVariable(n); | |
| current[MEMBER_VAR] = false; | |
| return SWIG_OK; | |
| } | |
| /* ------------------------------------------------------------ | |
| * constructorHandler() | |
| * | |
| * Method for adding C++ member constructor | |
| * ------------------------------------------------------------ */ | |
| virtual int constructorHandler(Node *n) { | |
| // REPORT("constructorHandler", n); | |
| current[CONSTRUCTOR] = true; | |
| Language::constructorHandler(n); | |
| current[CONSTRUCTOR] = false; | |
| // constructor_name = NewString(Getattr(n, "sym:name")); | |
| have_constructor = 1; | |
| return SWIG_OK; | |
| } | |
| /* ------------------------------------------------------------ | |
| * destructorHandler() | |
| * ------------------------------------------------------------ */ | |
| virtual int destructorHandler(Node *n) { | |
| REPORT("destructorHandler", n); | |
| current[DESTRUCTOR] = true; | |
| Language::destructorHandler(n); | |
| current[DESTRUCTOR] = false; | |
| have_destructor = 1; | |
| destructor_action = Getattr(n, "wrap:action"); | |
| return SWIG_OK; | |
| } | |
| /* ---------------------------------------------------------------------- | |
| * globalfunctionHandler() | |
| * | |
| * It can be called: | |
| * 1. Usual C/C++ global function. | |
| * 2. During class parsing for functions declared/defined as friend | |
| * 3. During class parsing from staticmemberfunctionHandler | |
| * ---------------------------------------------------------------------- */ | |
| virtual int globalfunctionHandler(Node *n) { | |
| bool oldVal = current[NO_CPP]; | |
| if (!current[STATIC_FUNC]) // If static function, don't switch to NO_CPP | |
| current[NO_CPP] = true; | |
| const int result = Language::globalfunctionHandler(n); | |
| if (!current[STATIC_FUNC]) // Register only if not called from static function handler | |
| registerMethod(n); | |
| current[NO_CPP] = oldVal; | |
| return result; | |
| } | |
| /* ---------------------------------------------------------------------- | |
| * globalvariableHandler() | |
| * | |
| * Sets "current" array correctly | |
| * ---------------------------------------------------------------------- */ | |
| virtual int globalvariableHandler(Node *n) { | |
| bool oldVal = current[NO_CPP]; | |
| current[GLOBAL_VAR] = true; | |
| current[NO_CPP] = true; | |
| const int result = Language::globalvariableHandler(n); | |
| registerVariable(n); | |
| current[GLOBAL_VAR] = false; | |
| current[NO_CPP] = oldVal; | |
| return result; | |
| } | |
| /* ----------------------------------------------------------------------- | |
| * staticmemberfunctionHandler() | |
| * | |
| * Wrap a static C++ function | |
| * ---------------------------------------------------------------------- */ | |
| virtual int staticmemberfunctionHandler(Node *n) { | |
| REPORT("staticmemberfunctionHandler", n); | |
| current[STATIC_FUNC] = true; | |
| const int result = Language::staticmemberfunctionHandler(n); | |
| registerMethod(n); | |
| if (result == SWIG_OK && old_compatible_names) { | |
| Swig_require("lua_staticmemberfunctionHandler", n, "*lua:name", NIL); | |
| String *lua_name = Getattr(n, "lua:name"); | |
| // Although this function uses Swig_name_member, it actually generates the Lua name, | |
| // not the C++ name. This is because an earlier version used such a scheme for static function | |
| // name generation and we have to maintain backward compatibility. | |
| String *compat_name = Swig_name_member(0, proxy_class_name, lua_name); | |
| Setattr(n, "lua:name", compat_name); | |
| registerMethod(n, true, getNSpace()); | |
| Delete(compat_name); | |
| Swig_restore(n); | |
| } | |
| current[STATIC_FUNC] = false; | |
| return result; | |
| } | |
| /* ------------------------------------------------------------ | |
| * memberconstantHandler() | |
| * | |
| * Create a C++ constant | |
| * ------------------------------------------------------------ */ | |
| virtual int memberconstantHandler(Node *n) { | |
| REPORT("memberconstantHandler", n); | |
| int result = Language::memberconstantHandler(n); | |
| return result; | |
| } | |
| /* --------------------------------------------------------------------- | |
| * staticmembervariableHandler() | |
| * --------------------------------------------------------------------- */ | |
| virtual int staticmembervariableHandler(Node *n) { | |
| REPORT("staticmembervariableHandler", n); | |
| current[STATIC_VAR] = true; | |
| // String *symname = Getattr(n, "sym:name"); | |
| int result = Language::staticmembervariableHandler(n); | |
| if (!GetFlag(n, "wrappedasconstant")) { | |
| registerVariable(n); | |
| } | |
| if (result == SWIG_OK) { | |
| // This will add static member variable to the class namespace with name ClassName_VarName | |
| if (old_compatible_names) { | |
| Swig_save("lua_staticmembervariableHandler", n, "lua:name", NIL); | |
| String *lua_name = Getattr(n, "lua:name"); | |
| // Although this function uses Swig_name_member, it actually generates the Lua name, | |
| // not the C++ name. This is because an earlier version used such a scheme for static function | |
| // name generation and we have to maintain backward compatibility. | |
| String *v2_name = Swig_name_member(NIL, proxy_class_name, lua_name); | |
| if (!GetFlag(n, "wrappedasconstant")) { | |
| Setattr(n, "lua:name", v2_name); | |
| // Registering static var in the class parent nspace | |
| registerVariable(n, true, getNSpace()); | |
| } | |
| // If static member variable was wrapped as a constant, then | |
| // constant wrapper has already performed all actions necessary | |
| Delete(v2_name); | |
| Swig_restore(n); | |
| } | |
| } | |
| current[STATIC_VAR] = false; | |
| return result; | |
| } | |
| /* --------------------------------------------------------------------- | |
| * 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 terminated | |
| emitLuaFlavor(s); | |
| String *sfile = 0; | |
| 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 | |
| * --------------------------------------------------------------------- */ | |
| void emitLuaFlavor(String *s) { | |
| if (elua_emulate) { | |
| Printf(s, "/*This is only emulation!*/\n"); | |
| Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_ELUA\n"); | |
| Printf(s, "#define SWIG_LUA_ELUA_EMULATE\n"); | |
| } else if (elua_ltr) | |
| Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_ELUA\n"); | |
| else if (eluac_ltr) | |
| Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_ELUAC\n"); | |
| else | |
| Printf(s, "#define SWIG_LUA_TARGET SWIG_LUA_FLAVOR_LUA\n"); | |
| } | |
| /* ----------------------------------------------------------------------------- | |
| * escapeCode() | |
| * | |
| * This is to convert the string of Lua code into a proper string, which can then be | |
| * emitted into the C/C++ code. | |
| * Basically it 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); | |
| } | |
| /* ----------------------------------------------------------------------------- | |
| * rawGetCArraysHash(String *name) | |
| * | |
| * A small helper to hide implementation of how CArrays hashes are stored | |
| * ---------------------------------------------------------------------------- */ | |
| Hash *rawGetCArraysHash(const_String_or_char_ptr name) { | |
| Hash *scope = symbolScopeLookup(name ? name : ""); | |
| if (!scope) | |
| return 0; | |
| Hash *carrays_hash = Getattr(scope, "lua:cdata"); | |
| return carrays_hash; | |
| } | |
| /* ----------------------------------------------------------------------------- | |
| * getCArraysHash() | |
| * | |
| * Each namespace can be described with a hash that stores C arrays | |
| * where members of the namespace should be added. All these hashes are stored | |
| * inside the symbols table, in pseudo-symbol for every namespace. | |
| * nspace could be NULL (NSPACE_TODO), that means functions and variables and classes | |
| * that are not in any namespace (this is default for SWIG unless %nspace feature is used). | |
| * You can later set some attributes that will affect behaviour of functions that use this hash: | |
| * "lua:no_namespaces" will disable "namespaces" array. | |
| * "lua:no_classes" will disable "classes" array. | |
| * For every component ("attributes", "methods", etc) there are subcomponents: | |
| * XXX:name - name of the C array that stores data for component | |
| * XXX:decl - statement with forward declaration of this array; | |
| * Namespace could be automatically registered to its parent if 'reg' == true. This can only be | |
| * done during the first call (a.k.a when nspace is created). | |
| * ---------------------------------------------------------------------------- */ | |
| Hash *getCArraysHash(String *nspace, bool reg = true) { | |
| Hash *scope = symbolScopeLookup(nspace ? nspace : ""); | |
| if (!scope) { | |
| symbolAddScope(nspace ? nspace : ""); | |
| scope = symbolScopeLookup(nspace ? nspace : ""); | |
| assert(scope); | |
| } | |
| Hash *carrays_hash = Getattr(scope, "lua:cdata"); | |
| if (carrays_hash != 0) | |
| return carrays_hash; | |
| carrays_hash = NewHash(); | |
| String *mangled_name = 0; | |
| if (nspace == 0 || Len(nspace) == 0) | |
| mangled_name = NewString("SwigModule"); | |
| else | |
| mangled_name = Swig_name_mangle_string(nspace); | |
| String *cname = NewStringf("swig_%s", mangled_name); | |
| Setattr(carrays_hash, "cname", cname); | |
| String *attr_tab = NewString(""); | |
| String *attr_tab_name = NewStringf("swig_%s_attributes", mangled_name); | |
| String *attr_tab_decl = NewString(""); | |
| Printv(attr_tab, "static swig_lua_attribute ", NIL); | |
| Printv(attr_tab, attr_tab_name, "[]", NIL); | |
| Printv(attr_tab_decl, attr_tab, ";\n", NIL); | |
| Printv(attr_tab, " = {\n", NIL); | |
| Setattr(carrays_hash, "attributes", attr_tab); | |
| Setattr(carrays_hash, "attributes:name", attr_tab_name); | |
| Setattr(carrays_hash, "attributes:decl", attr_tab_decl); | |
| String *methods_tab = NewString(""); | |
| String *methods_tab_name = NewStringf("swig_%s_methods", mangled_name); | |
| String *methods_tab_decl = NewString(""); | |
| if (elua_ltr || eluac_ltr) // In this case methods array also acts as namespace rotable | |
| Printf(methods_tab, "const LUA_REG_TYPE "); | |
| else | |
| Printf(methods_tab, "static swig_lua_method "); | |
| Printv(methods_tab, methods_tab_name, "[]", NIL); | |
| Printv(methods_tab_decl, methods_tab, ";\n", NIL); | |
| Printv(methods_tab, "= {\n", NIL); | |
| Setattr(carrays_hash, "methods", methods_tab); | |
| Setattr(carrays_hash, "methods:name", methods_tab_name); | |
| Setattr(carrays_hash, "methods:decl", methods_tab_decl); | |
| String *const_tab = NewString(""); | |
| String *const_tab_name = NewStringf("swig_%s_constants", mangled_name); | |
| String *const_tab_decl = NewString(""); | |
| if (elua_ltr || eluac_ltr) // In this case const array holds rotable with namespace constants | |
| Printf(const_tab, "const LUA_REG_TYPE "); | |
| else | |
| Printf(const_tab, "static swig_lua_const_info "); | |
| Printv(const_tab, const_tab_name, "[]", NIL); | |
| Printv(const_tab_decl, const_tab, ";", NIL); | |
| Printv(const_tab, "= {\n", NIL); | |
| Setattr(carrays_hash, "constants", const_tab); | |
| Setattr(carrays_hash, "constants:name", const_tab_name); | |
| Setattr(carrays_hash, "constants:decl", const_tab_decl); | |
| String *classes_tab = NewString(""); | |
| String *classes_tab_name = NewStringf("swig_%s_classes", mangled_name); | |
| String *classes_tab_decl = NewString(""); | |
| Printf(classes_tab, "static swig_lua_class* "); | |
| Printv(classes_tab, classes_tab_name, "[]", NIL); | |
| Printv(classes_tab_decl, classes_tab, ";", NIL); | |
| Printv(classes_tab, "= {\n", NIL); | |
| Setattr(carrays_hash, "classes", classes_tab); | |
| Setattr(carrays_hash, "classes:name", classes_tab_name); | |
| Setattr(carrays_hash, "classes:decl", classes_tab_decl); | |
| String *namespaces_tab = NewString(""); | |
| String *namespaces_tab_name = NewStringf("swig_%s_namespaces", mangled_name); | |
| String *namespaces_tab_decl = NewString(""); | |
| Printf(namespaces_tab, "static swig_lua_namespace* "); | |
| Printv(namespaces_tab, namespaces_tab_name, "[]", NIL); | |
| Printv(namespaces_tab_decl, namespaces_tab, ";", NIL); | |
| Printv(namespaces_tab, " = {\n", NIL); | |
| Setattr(carrays_hash, "namespaces", namespaces_tab); | |
| Setattr(carrays_hash, "namespaces:name", namespaces_tab_name); | |
| Setattr(carrays_hash, "namespaces:decl", namespaces_tab_decl); | |
| if (elua_ltr) { | |
| String *get_tab = NewString(""); | |
| String *get_tab_name = NewStringf("swig_%s_get", mangled_name); | |
| String *get_tab_decl = NewString(""); | |
| Printv(get_tab, "const LUA_REG_TYPE ", get_tab_name, "[]", NIL); | |
| Printv(get_tab_decl, get_tab, ";", NIL); | |
| Printv(get_tab, " = {\n", NIL); | |
| Setattr(carrays_hash, "get", get_tab); | |
| Setattr(carrays_hash, "get:name", get_tab_name); | |
| Setattr(carrays_hash, "get:decl", get_tab_decl); | |
| String *set_tab = NewString(""); | |
| String *set_tab_name = NewStringf("swig_%s_set", mangled_name); | |
| String *set_tab_decl = NewString(""); | |
| Printv(set_tab, "const LUA_REG_TYPE ", set_tab_name, "[]", NIL); | |
| Printv(set_tab_decl, set_tab, ";", NIL); | |
| Printv(set_tab, " = {\n", NIL); | |
| Setattr(carrays_hash, "set", set_tab); | |
| Setattr(carrays_hash, "set:name", set_tab_name); | |
| Setattr(carrays_hash, "set:decl", set_tab_decl); | |
| } | |
| if (!eluac_ltr) { | |
| String *metatable_tab = NewString(""); | |
| String *metatable_tab_name = NewStringf("swig_%s_meta", mangled_name); | |
| String *metatable_tab_decl = NewString(""); | |
| if (elua_ltr) // In this case const array holds rotable with namespace constants | |
| Printf(metatable_tab, "const LUA_REG_TYPE "); | |
| else | |
| Printf(metatable_tab, "static swig_lua_method "); | |
| Printv(metatable_tab, metatable_tab_name, "[]", NIL); | |
| Printv(metatable_tab_decl, metatable_tab, ";", NIL); | |
| Printv(metatable_tab, " = {\n", NIL); | |
| Setattr(carrays_hash, "metatable", metatable_tab); | |
| Setattr(carrays_hash, "metatable:name", metatable_tab_name); | |
| Setattr(carrays_hash, "metatable:decl", metatable_tab_decl); | |
| } | |
| Setattr(scope, "lua:cdata", carrays_hash); | |
| assert(rawGetCArraysHash(nspace)); | |
| if (reg && nspace != 0 && Len(nspace) != 0 && GetFlag(carrays_hash, "lua:no_reg") == 0) { | |
| // Split names into components | |
| List *components = Split(nspace, '.', -1); | |
| String *parent_path = NewString(""); | |
| int len = Len(components); | |
| String *name = Copy(Getitem(components, len - 1)); | |
| for (int i = 0; i < len - 1; i++) { | |
| if (i > 0) | |
| Printv(parent_path, NSPACE_SEPARATOR, NIL); | |
| String *item = Getitem(components, i); | |
| Printv(parent_path, item, NIL); | |
| } | |
| Hash *parent = getCArraysHash(parent_path, true); | |
| String *namespaces_tab = Getattr(parent, "namespaces"); | |
| Printv(namespaces_tab, "&", cname, ",\n", NIL); | |
| if (elua_ltr || eluac_ltr) { | |
| String *methods_tab = Getattr(parent, "methods"); | |
| Printv(methods_tab, tab4, "{LSTRKEY(\"", name, "\")", ", LROVAL(", methods_tab_name, ")", "},\n", NIL); | |
| } | |
| Setattr(carrays_hash, "name", name); | |
| Delete(components); | |
| Delete(parent_path); | |
| } else if (!reg) // This namespace shouldn't be registered. Lets remember it. | |
| SetFlag(carrays_hash, "lua:no_reg"); | |
| Delete(mangled_name); | |
| mangled_name = 0; | |
| return carrays_hash; | |
| } | |
| /* ----------------------------------------------------------------------------- | |
| * closeCArraysHash() | |
| * | |
| * Functions add end markers {0,0,...,0} to all arrays, prints them to | |
| * output and marks hash as closed (lua:closed). Consequent attempts to | |
| * close the same hash will result in an error. | |
| * closeCArraysHash DOES NOT print structure that describes namespace, it only | |
| * prints array. You can use printCArraysDefinition to print structure. | |
| * if "lua:no_namespaces" is set, then array for "namespaces" won't be printed | |
| * if "lua:no_classes" is set, then array for "classes" won't be printed | |
| * ----------------------------------------------------------------------------- */ | |
| void closeCArraysHash(String *nspace, File *output) { | |
| Hash *carrays_hash = rawGetCArraysHash(nspace); | |
| assert(carrays_hash); | |
| assert(GetFlag(carrays_hash, "lua:closed") == 0); | |
| SetFlag(carrays_hash, "lua:closed"); | |
| // Do arrays describe class instance part or class static part | |
| const int is_instance = GetFlag(carrays_hash, "lua:class_instance"); | |
| String *attr_tab = Getattr(carrays_hash, "attributes"); | |
| Printf(attr_tab, " {0,0,0}\n};\n"); | |
| Printv(output, attr_tab, NIL); | |
| String *const_tab = Getattr(carrays_hash, "constants"); | |
| String *const_tab_name = Getattr(carrays_hash, "constants:name"); | |
| if (elua_ltr || eluac_ltr) | |
| Printv(const_tab, " {LNILKEY, LNILVAL}\n", "};\n", NIL); | |
| else | |
| Printf(const_tab, " {0,0,0,0,0,0}\n};\n"); | |
| // For the sake of compiling with -Wall -Werror we print constants | |
| // only when necessary | |
| int need_constants = 0; | |
| if (elua_ltr || eluac_ltr) | |
| need_constants = 1; | |
| else if (!is_instance) // static part need constants tab | |
| need_constants = 1; | |
| if (need_constants) | |
| Printv(output, const_tab, NIL); | |
| if (elua_ltr) { | |
| // Put forward declaration of metatable array | |
| Printv(output, "extern ", Getattr(carrays_hash, "metatable:decl"), "\n", NIL); | |
| } | |
| String *methods_tab = Getattr(carrays_hash, "methods"); | |
| String *metatable_tab_name = Getattr(carrays_hash, "metatable:name"); | |
| if (elua_ltr || eluac_ltr) { | |
| Printv(methods_tab, tab4, "{LSTRKEY(\"const\"), LROVAL(", const_tab_name, ")},\n", NIL); | |
| if (elua_ltr) { | |
| Printv(methods_tab, tab4, "{LSTRKEY(\"__metatable\"), LROVAL(", metatable_tab_name, ")},\n", NIL); | |
| } | |
| Printv(methods_tab, tab4, "{LSTRKEY(\"__disown\"), LFUNCVAL(SWIG_Lua_class_disown)},\n", NIL); | |
| Printv(methods_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); | |
| } else | |
| Printf(methods_tab, " {0,0}\n};\n"); | |
| Printv(output, methods_tab, NIL); | |
| if (!GetFlag(carrays_hash, "lua:no_classes")) { | |
| String *classes_tab = Getattr(carrays_hash, "classes"); | |
| Printf(classes_tab, " 0\n};\n"); | |
| Printv(output, classes_tab, NIL); | |
| } | |
| if (!GetFlag(carrays_hash, "lua:no_namespaces")) { | |
| String *namespaces_tab = Getattr(carrays_hash, "namespaces"); | |
| Printf(namespaces_tab, " 0\n};\n"); | |
| Printv(output, namespaces_tab, NIL); | |
| } | |
| if (elua_ltr) { | |
| String *get_tab = Getattr(carrays_hash, "get"); | |
| String *set_tab = Getattr(carrays_hash, "set"); | |
| Printv(get_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); | |
| Printv(set_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); | |
| Printv(output, get_tab, NIL); | |
| Printv(output, set_tab, NIL); | |
| } | |
| // Heuristic whether we need to print metatable or not. | |
| // For the sake of compiling with -Wall -Werror we don't print | |
| // metatable for static part. | |
| int need_metatable = 0; | |
| if (eluac_ltr) | |
| need_metatable = 0; | |
| else if (!is_instance) | |
| need_metatable = 0; | |
| else | |
| need_metatable = 1; | |
| if (need_metatable) { | |
| String *metatable_tab = Getattr(carrays_hash, "metatable"); | |
| assert(metatable_tab); | |
| if (elua_ltr) { | |
| String *get_tab_name = Getattr(carrays_hash, "get:name"); | |
| String *set_tab_name = Getattr(carrays_hash, "set:name"); | |
| if (GetFlag(carrays_hash, "lua:class_instance")) { | |
| Printv(metatable_tab, tab4, "{LSTRKEY(\"__index\"), LFUNCVAL(SWIG_Lua_class_get)},\n", NIL); | |
| Printv(metatable_tab, tab4, "{LSTRKEY(\"__newindex\"), LFUNCVAL(SWIG_Lua_class_set)},\n", NIL); | |
| } else { | |
| Printv(metatable_tab, tab4, "{LSTRKEY(\"__index\"), LFUNCVAL(SWIG_Lua_namespace_get)},\n", NIL); | |
| Printv(metatable_tab, tab4, "{LSTRKEY(\"__newindex\"), LFUNCVAL(SWIG_Lua_namespace_set)},\n", NIL); | |
| } | |
| Printv(metatable_tab, tab4, "{LSTRKEY(\"__gc\"), LFUNCVAL(SWIG_Lua_class_destruct)},\n", NIL); | |
| Printv(metatable_tab, tab4, "{LSTRKEY(\".get\"), LROVAL(", get_tab_name, ")},\n", NIL); | |
| Printv(metatable_tab, tab4, "{LSTRKEY(\".set\"), LROVAL(", set_tab_name, ")},\n", NIL); | |
| Printv(metatable_tab, tab4, "{LSTRKEY(\".fn\"), LROVAL(", Getattr(carrays_hash, "methods:name"), ")},\n", NIL); | |
| if (GetFlag(carrays_hash, "lua:class_instance")) { | |
| String *static_cls = Getattr(carrays_hash, "lua:class_instance:static_hash"); | |
| assert(static_cls); | |
| // static_cls is swig_lua_namespace. This structure can't be used with eLua(LTR) | |
| // Instead a structure describing its methods is used | |
| String *static_cls_cname = Getattr(static_cls, "methods:name"); | |
| assert(static_cls_cname); | |
| Printv(metatable_tab, tab4, "{LSTRKEY(\".static\"), LROVAL(", static_cls_cname, ")},\n", NIL); | |
| // Put forward declaration of this array | |
| Printv(output, "extern ", Getattr(static_cls, "methods:decl"), "\n", NIL); | |
| } else if (GetFlag(carrays_hash, "lua:class_static")) { | |
| Hash *instance_cls = Getattr(carrays_hash, "lua:class_static:instance_hash"); | |
| assert(instance_cls); | |
| String *instance_cls_metatable_name = Getattr(instance_cls, "metatable:name"); | |
| assert(instance_cls_metatable_name); | |
| Printv(metatable_tab, tab4, "{LSTRKEY(\".instance\"), LROVAL(", instance_cls_metatable_name, ")},\n", NIL); | |
| } | |
| Printv(metatable_tab, tab4, "{LNILKEY, LNILVAL}\n};\n", NIL); | |
| } else { | |
| Printf(metatable_tab, " {0,0}\n};\n"); | |
| } | |
| Printv(output, metatable_tab, NIL); | |
| } | |
| Printv(output, "\n", NIL); | |
| } | |
| /* ----------------------------------------------------------------------------- | |
| * closeNamespaces() | |
| * | |
| * Recursively close all non-closed namespaces. Prints data to dataOutput. | |
| * ----------------------------------------------------------------------------- */ | |
| void closeNamespaces(File *dataOutput) { | |
| // Special handling for empty module. | |
| if (symbolScopeLookup("") == 0 || rawGetCArraysHash("") == 0) { | |
| // Module is empty. Create hash for global scope in order to have swig_SwigModule | |
| // variable in resulting file | |
| getCArraysHash(0); | |
| } | |
| // Because we can't directly access 'symtabs', instead we access | |
| // top-level scope and look on all scope pseudo-symbols in it. | |
| Hash *top_scope = symbolScopeLookup(""); | |
| assert(top_scope); | |
| Iterator ki = First(top_scope); | |
| List *to_close = NewList(); | |
| while (ki.key) { | |
| assert(ki.item); | |
| if (Getattr(ki.item, "sym:scope")) { | |
| // We have a pseudo symbol. Lets get actual scope for this pseudo symbol | |
| Hash *carrays_hash = rawGetCArraysHash(ki.key); | |
| assert(carrays_hash); | |
| if (GetFlag(carrays_hash, "lua:closed") == 0) | |
| Append(to_close, ki.key); | |
| } | |
| ki = Next(ki); | |
| } | |
| SortList(to_close, &compareByLen); | |
| int len = Len(to_close); | |
| for (int i = 0; i < len; i++) { | |
| String *key = Getitem(to_close, i); | |
| closeCArraysHash(key, dataOutput); | |
| Hash *carrays_hash = rawGetCArraysHash(key); | |
| String *name = 0; // name - name of the namespace as it should be visible in Lua | |
| if (Len(key) == 0) // This is global module | |
| name = module; | |
| else | |
| name = Getattr(carrays_hash, "name"); | |
| assert(name); | |
| printCArraysDefinition(key, name, dataOutput); | |
| } | |
| Delete(to_close); | |
| } | |
| /* ----------------------------------------------------------------------------- | |
| * printCArraysDefinition() | |
| * | |
| * This function prints to output a definition of namespace in form | |
| * swig_lua_namespace $cname = { attr_array, methods_array, ... , namespaces_array }; | |
| * You can call this function as many times as is necessary. | |
| * 'name' is a user-visible name that this namespace will have in Lua. It shouldn't | |
| * be a fully qualified name, just its own name. | |
| * ----------------------------------------------------------------------------- */ | |
| void printCArraysDefinition(String *nspace, String *name, File *output) { | |
| Hash *carrays_hash = getCArraysHash(nspace, false); | |
| String *cname = Getattr(carrays_hash, "cname"); // cname - name of the C structure that describes namespace | |
| assert(cname); | |
| Printv(output, "static swig_lua_namespace ", cname, " = ", NIL); | |
| String *null_string = NewString("0"); | |
| String *attr_tab_name = Getattr(carrays_hash, "attributes:name"); | |
| String *methods_tab_name = Getattr(carrays_hash, "methods:name"); | |
| String *const_tab_name = Getattr(carrays_hash, "constants:name"); | |
| String *classes_tab_name = Getattr(carrays_hash, "classes:name"); | |
| String *namespaces_tab_name = Getattr(carrays_hash, "namespaces:name"); | |
| bool has_classes = GetFlag(carrays_hash, "lua:no_classes") == 0; | |
| bool has_namespaces = GetFlag(carrays_hash, "lua:no_namespaces") == 0; | |
| Printv(output, | |
| "{\n", | |
| tab4, | |
| "\"", | |
| name, | |
| "\",\n", | |
| tab4, | |
| methods_tab_name, | |
| ",\n", | |
| tab4, | |
| attr_tab_name, | |
| ",\n", | |
| tab4, | |
| const_tab_name, | |
| ",\n", | |
| tab4, | |
| (has_classes) ? classes_tab_name : null_string, | |
| ",\n", | |
| tab4, | |
| (has_namespaces) ? namespaces_tab_name : null_string, | |
| "\n};\n", | |
| NIL); | |
| Delete(null_string); | |
| } | |
| /* ----------------------------------------------------------------------------- | |
| * luaCurrentSymbolNSpace() | |
| * | |
| * This function determines actual namespace/scope where any symbol at the | |
| * current moment should be placed. It looks at the 'current' array | |
| * and depending on where are we - static class member/function, | |
| * instance class member/function or just global functions decides | |
| * where symbol should be put. | |
| * The namespace/scope doesn't depend from symbol, only from 'current' | |
| * ----------------------------------------------------------------------------- */ | |
| String *luaCurrentSymbolNSpace() { | |
| String *scope = 0; | |
| // If outside class, than NSpace is used. | |
| // If inside class, but current[NO_CPP], then this is friend function. It belongs to NSpace | |
| if (!getCurrentClass() || current[NO_CPP]) { | |
| scope = getNSpace(); | |
| } else if (current[ENUM_CONST] && !CPlusPlus) { | |
| // Enums in C mode go to NSpace | |
| scope = getNSpace(); | |
| } else { | |
| // If inside class, then either class static namespace or class fully qualified name is used | |
| assert(!current[NO_CPP]); | |
| if (current[STATIC_FUNC] || current[STATIC_VAR] || current[STATIC_CONST]) { | |
| scope = class_static_nspace; | |
| } else if (current[MEMBER_VAR] || current[CONSTRUCTOR] || current[DESTRUCTOR] || current[MEMBER_FUNC]) { | |
| scope = full_proxy_class_name; | |
| } else { // Friend functions are handled this way | |
| scope = class_static_nspace; | |
| } | |
| assert(scope); | |
| } | |
| return scope; | |
| } | |
| /* ----------------------------------------------------------------------------- | |
| * luaAddSymbol() | |
| * | |
| * Our implementation of addSymbol. Determines scope correctly, then | |
| * forwards to Language::addSymbol. | |
| * | |
| * For friend functions, we allow duplicate symbols in the same Lua scope | |
| * if they come from different C++ namespaces (they will be overloaded). | |
| * ----------------------------------------------------------------------------- */ | |
| int luaAddSymbol(const String *s, const Node *n) { | |
| String *scope = luaCurrentSymbolNSpace(); | |
| return luaAddSymbol(s, n, scope); | |
| } | |
| /* ----------------------------------------------------------------------------- | |
| * luaAddSymbol() | |
| * | |
| * Overload. Enforces given scope. | |
| * | |
| * Special handling for friend functions: when a friend function from one | |
| * C++ namespace/class is being added to the Lua global scope and a symbol | |
| * with the same name already exists (from a different C++ namespace/class), | |
| * we don't report an error. Instead, we mark the node as "lua:duplicate" | |
| * so that functionWrapper can skip generating the wrapper. | |
| * ----------------------------------------------------------------------------- */ | |
| int luaAddSymbol(const String *s, const Node *n, const_String_or_char_ptr scope) { | |
| // Check if this is a friend function (stored as "friend" in storage attribute) | |
| String *storage = Getattr(const_cast<Node *>(n), "storage"); | |
| bool is_friend = storage && Strcmp(storage, "friend") == 0; | |
| // If it's a friend function and we're in global scope (current[NO_CPP] is true), | |
| // check if symbol already exists | |
| if (is_friend && current[NO_CPP]) { | |
| Node *existing = symbolLookup(s, scope); | |
| if (existing && existing != n) { | |
| // Symbol already exists - this is a friend function from a different | |
| // C++ namespace that maps to the same Lua scope. Mark as duplicate | |
| // so functionWrapper can skip generating a wrapper. | |
| SetFlag(const_cast<Node *>(n), "lua:duplicate_friend"); | |
| return 1; // Return success to avoid error | |
| } | |
| } | |
| return Language::addSymbol(s, n, scope); | |
| } | |
| /* --------------------------------------------------------------- | |
| * Director support for Lua | |
| * --------------------------------------------------------------- */ | |
| /* ------------------------------------------------------------ | |
| * classDirectorInit() | |
| * | |
| * Initialize the director class declaration. | |
| * ------------------------------------------------------------ */ | |
| int classDirectorInit(Node *n) { | |
| String *declaration = Swig_director_declaration(n); | |
| Printf(f_directors_h, "\n"); | |
| Printf(f_directors_h, "%s\n", declaration); | |
| Printf(f_directors_h, "public:\n"); | |
| Delete(declaration); | |
| /* For Lua, we always create a director object if directors are enabled. | |
| * The Lua object will be connected later via swig_connect_director(). | |
| * We override none_comparison and director_ctor_code to always use the director constructor. */ | |
| Delete(none_comparison); | |
| none_comparison = NewString(""); /* Empty comparison - always use director */ | |
| Delete(director_ctor_code); | |
| director_ctor_code = NewString("$director_new"); | |
| return Language::classDirectorInit(n); | |
| } | |
| /* ------------------------------------------------------------ | |
| * classDirectorEnd() | |
| * | |
| * Complete the director class declaration. | |
| * ------------------------------------------------------------ */ | |
| int classDirectorEnd(Node *n) { | |
| String *classname = Swig_class_name(n); | |
| if (dirprot_mode()) { | |
| Printf(f_directors_h, "\n"); | |
| Printf(f_directors_h, "/* Internal director utilities */\n"); | |
| Printf(f_directors_h, "public:\n"); | |
| Printf(f_directors_h, " bool swig_get_inner(const char *swig_protected_method_name) const {\n"); | |
| Printf(f_directors_h, " std::map<std::string, bool>::const_iterator iv = swig_inner.find(swig_protected_method_name);\n"); | |
| Printf(f_directors_h, " return (iv != swig_inner.end() ? iv->second : false);\n"); | |
| Printf(f_directors_h, " }\n"); | |
| Printf(f_directors_h, " void swig_set_inner(const char *swig_protected_method_name, bool swig_val) const {\n"); | |
| Printf(f_directors_h, " swig_inner[swig_protected_method_name] = swig_val;\n"); | |
| Printf(f_directors_h, " }\n"); | |
| Printf(f_directors_h, "private:\n"); | |
| Printf(f_directors_h, " mutable std::map<std::string, bool> swig_inner;\n"); | |
| } | |
| Printf(f_directors_h, "};\n\n"); | |
| Delete(classname); | |
| return Language::classDirectorEnd(n); | |
| } | |
| /* ------------------------------------------------------------ | |
| * directorPrefixArgs() | |
| * | |
| * Set up director prefix arguments (lua_State *L). | |
| * ------------------------------------------------------------ */ | |
| void directorPrefixArgs(Node *n) { | |
| /* Need to prepend 'L' (lua_State*) to the director constructor's argument list */ | |
| String *type = NewString("lua_State"); | |
| SwigType_add_pointer(type); | |
| Parm *p = NewParm(type, NewString("L"), n); | |
| Setattr(p, "arg:byname", "1"); | |
| set_nextSibling(p, NULL); | |
| Setattr(n, "director:prefix_args", p); | |
| } | |
| /* ------------------------------------------------------------ | |
| * classDirectorConstructor() | |
| * | |
| * Emit a director constructor. | |
| * ------------------------------------------------------------ */ | |
| int classDirectorConstructor(Node *n) { | |
| Node *parent = Getattr(n, "parentNode"); | |
| String *sub = NewString(""); | |
| String *decl = Getattr(n, "decl"); | |
| String *classname = directorClassName(parent); | |
| /* Insert self parameter (lua_State*) */ | |
| Parm *p; | |
| ParmList *superparms = Getattr(n, "parms"); | |
| ParmList *parms = CopyParmList(superparms); | |
| String *type = NewString("lua_State"); | |
| SwigType_add_pointer(type); | |
| p = NewParm(type, NewString("L"), n); | |
| set_nextSibling(p, parms); | |
| parms = p; | |
| /* Set prefix args so that the wrapper code generator knows to add L */ | |
| directorPrefixArgs(n); | |
| if (!Getattr(n, "defaultargs")) { | |
| /* Constructor wrapper */ | |
| { | |
| Wrapper *w = NewWrapper(); | |
| String *call; | |
| String *basetype = Getattr(parent, "classtype"); | |
| String *target = Swig_method_decl(0, decl, classname, parms, 0); | |
| call = Swig_csuperclass_call(0, basetype, superparms); | |
| Printf(w->def, "%s::%s: %s, Swig::Director(L) {\n", classname, target, call); | |
| Append(w->def, "}\n"); | |
| Delete(target); | |
| Wrapper_print(w, f_directors); | |
| Delete(call); | |
| DelWrapper(w); | |
| } | |
| /* Constructor header declaration */ | |
| { | |
| String *target = Swig_method_decl(0, decl, classname, parms, 1); | |
| Printf(f_directors_h, " %s;\n", target); | |
| Delete(target); | |
| } | |
| } | |
| Delete(sub); | |
| Delete(classname); | |
| Delete(parms); | |
| return Language::classDirectorConstructor(n); | |
| } | |
| /* ------------------------------------------------------------ | |
| * classDirectorDefaultConstructor() | |
| * | |
| * Emit a director default constructor. | |
| * ------------------------------------------------------------ */ | |
| int classDirectorDefaultConstructor(Node *n) { | |
| Node *parent = Swig_methodclass(n); | |
| String *classname = directorClassName(parent); | |
| /* Set prefix args so that the wrapper code generator knows to add L */ | |
| directorPrefixArgs(n); | |
| { | |
| Wrapper *w = NewWrapper(); | |
| Printf(w->def, "%s::%s(lua_State *L) : Swig::Director(L) {\n", classname, classname); | |
| Append(w->def, "}\n"); | |
| Wrapper_print(w, f_directors); | |
| DelWrapper(w); | |
| } | |
| Printf(f_directors_h, " %s(lua_State *L);\n", classname); | |
| Delete(classname); | |
| return Language::classDirectorDefaultConstructor(n); | |
| } | |
| /* ------------------------------------------------------------ | |
| * classDirectorMethod() | |
| * | |
| * Emit a virtual director method to pass a method call on to the | |
| * underlying Lua object. | |
| * ------------------------------------------------------------ */ | |
| int classDirectorMethod(Node *n, Node *parent, String *super) { | |
| int is_void = 0; | |
| int is_pointer = 0; | |
| String *decl = Getattr(n, "decl"); | |
| String *name = Getattr(n, "name"); | |
| String *c_classname = Getattr(parent, "name"); | |
| String *symname = Getattr(n, "sym:name"); | |
| String *declaration = NewString(""); | |
| ParmList *l = Getattr(n, "parms"); | |
| Wrapper *w = NewWrapper(); | |
| String *tm; | |
| String *wrap_args = NewString(""); | |
| SwigType *returntype = Getattr(n, "type"); | |
| String *value = Getattr(n, "value"); | |
| String *storage = Getattr(n, "storage"); | |
| bool pure_virtual = false; | |
| int status = SWIG_OK; | |
| int idx; | |
| bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; | |
| if (Cmp(storage, "virtual") == 0) { | |
| if (Cmp(value, "0") == 0) { | |
| pure_virtual = true; | |
| } | |
| } | |
| /* determine if the method returns a pointer */ | |
| is_pointer = SwigType_ispointer_return(decl); | |
| is_void = (!Cmp(returntype, "void") && !is_pointer); | |
| /* virtual method definition */ | |
| String *target; | |
| String *pclassname = directorClassName(parent); | |
| String *qualified_name = NewStringf("%s::%s", pclassname, name); | |
| SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type"); | |
| target = Swig_method_decl(rtype, decl, qualified_name, l, 0); | |
| Printf(w->def, "%s", target); | |
| Delete(qualified_name); | |
| Delete(target); | |
| /* header declaration */ | |
| target = Swig_method_decl(rtype, decl, name, l, 1); | |
| Printf(declaration, " virtual %s", target); | |
| Delete(target); | |
| // Get any exception classes in the throws typemap | |
| if (Getattr(n, "noexcept")) { | |
| Append(w->def, " noexcept"); | |
| Append(declaration, " noexcept"); | |
| } | |
| ParmList *throw_parm_list = 0; | |
| if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { | |
| Parm *p; | |
| int gencomma = 0; | |
| Append(w->def, " throw("); | |
| Append(declaration, " throw("); | |
| if (throw_parm_list) | |
| Swig_typemap_attach_parms("throws", throw_parm_list, 0); | |
| for (p = throw_parm_list; p; p = nextSibling(p)) { | |
| if (Getattr(p, "tmap:throws")) { | |
| if (gencomma++) { | |
| Append(w->def, ", "); | |
| Append(declaration, ", "); | |
| } | |
| String *str = SwigType_str(Getattr(p, "type"), 0); | |
| Append(w->def, str); | |
| Append(declaration, str); | |
| Delete(str); | |
| } | |
| } | |
| Append(w->def, ")"); | |
| Append(declaration, ")"); | |
| } | |
| Append(w->def, " {"); | |
| Append(declaration, ";\n"); | |
| /* declare method return value */ | |
| if (!is_void && (!ignored_method || pure_virtual)) { | |
| if (!SwigType_isclass(returntype)) { | |
| if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { | |
| String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); | |
| Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); | |
| Delete(construct_result); | |
| } else { | |
| Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); | |
| } | |
| } else { | |
| String *cres = SwigType_lstr(returntype, "c_result"); | |
| Printf(w->code, "%s;\n", cres); | |
| Delete(cres); | |
| } | |
| } | |
| if (ignored_method) { | |
| if (!pure_virtual) { | |
| if (!is_void) | |
| Printf(w->code, "return "); | |
| String *super_call = Swig_method_call(super, l); | |
| Printf(w->code, "%s;\n", super_call); | |
| Delete(super_call); | |
| } else { | |
| Printf(w->code, | |
| "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", | |
| SwigType_namestr(c_classname), | |
| SwigType_namestr(name)); | |
| } | |
| } else { | |
| /* attach typemaps to arguments (C++ -> Lua) */ | |
| String *arglist = NewString(""); | |
| Swig_director_parms_fixup(l); | |
| Swig_typemap_attach_parms("in", l, 0); | |
| Swig_typemap_attach_parms("directorin", l, w); | |
| Swig_typemap_attach_parms("directorargout", l, w); | |
| Parm *p; | |
| char source[256]; | |
| /* Get lua state */ | |
| Printf(w->code, "lua_State *L = swig_get_lua_state();\n"); | |
| Printf(w->code, "if (!L) {\n"); | |
| Printf(w->code, " Swig::DirectorException::raise(\"'L' uninitialized, maybe you forgot to call swig_connect_director.\");\n"); | |
| Printf(w->code, "}\n"); | |
| Printf(w->code, "int top = lua_gettop(L);\n"); | |
| /* Get self onto stack */ | |
| Printf(w->code, "if (!swig_get_self(L)) {\n"); | |
| Printf(w->code, " Swig::DirectorException::raise(\"'self' uninitialized, maybe you forgot to call swig_connect_director.\");\n"); | |
| Printf(w->code, "}\n"); | |
| Printf(w->code, "int obj_idx = lua_gettop(L);\n"); | |
| /* Get the Lua method override for this object, or nil if there is none */ | |
| Printf(w->code, "SWIG_Lua_get_director_override(L, obj_idx, \"%s\");\n", symname); | |
| Printf(w->code, "if (!lua_isfunction(L, -1)) {\n"); | |
| Printf(w->code, " lua_pop(L, 1); /* pop placeholder */\n"); | |
| Printf(w->code, " lua_settop(L, top);\n"); | |
| if (pure_virtual) { | |
| Printf(w->code, | |
| " Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", | |
| SwigType_namestr(c_classname), | |
| SwigType_namestr(name)); | |
| } else { | |
| // Call parent method instead | |
| if (!is_void) { | |
| Printf(w->code, " return "); | |
| } | |
| String *super_call = Swig_method_call(super, l); | |
| Printf(w->code, "%s;\n", super_call); | |
| Delete(super_call); | |
| if (is_void) { | |
| Printf(w->code, " return;\n"); | |
| } | |
| } | |
| Printf(w->code, "}\n"); | |
| /* Push self as first argument */ | |
| Printf(w->code, "lua_pushvalue(L, obj_idx);\n"); | |
| /* build argument list and type conversion string */ | |
| idx = 0; | |
| int nargs = 0; | |
| p = l; | |
| while (p) { | |
| if (checkAttribute(p, "tmap:in:numinputs", "0")) { | |
| p = Getattr(p, "tmap:in:next"); | |
| continue; | |
| } | |
| String *ptype = Getattr(p, "type"); | |
| if ((tm = Getattr(p, "tmap:directorin")) != 0) { | |
| snprintf(source, sizeof(source), "obj%d", idx++); | |
| Replaceall(tm, "$input", source); | |
| Replaceall(tm, "$owner", "0"); | |
| Printv(wrap_args, tm, "\n", NIL); | |
| nargs++; | |
| p = Getattr(p, "tmap:directorin:next"); | |
| continue; | |
| } else if (Cmp(ptype, "void")) { | |
| Swig_warning(WARN_TYPEMAP_DIRECTORIN_UNDEF, | |
| input_file, | |
| line_number, | |
| "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", | |
| SwigType_str(ptype, 0), | |
| SwigType_namestr(c_classname), | |
| SwigType_namestr(name)); | |
| status = SWIG_NOWRAP; | |
| break; | |
| } | |
| p = nextSibling(p); | |
| } | |
| if (status == SWIG_OK) { | |
| /* wrap complex arguments to Lua objects */ | |
| Printv(w->code, wrap_args, NIL); | |
| /* Mark that we're entering an upcall to prevent infinite recursion */ | |
| Printf(w->code, "swig_begin_upcall();\n"); | |
| /* Call the Lua method */ | |
| Printf(w->code, "int pcall_result = lua_pcall(L, %d, %d, 0);\n", nargs + 1, is_void ? 0 : 1); | |
| Printf(w->code, "swig_end_upcall();\n"); | |
| Printf(w->code, "if (pcall_result != 0) {\n"); | |
| Printf(w->code, " std::string err = \"Error calling %s: \";\n", symname); | |
| Printf(w->code, " err += lua_tostring(L, -1);\n"); | |
| Printf(w->code, " lua_settop(L, top);\n"); | |
| Printf(w->code, " Swig::DirectorMethodException::raise(err.c_str());\n"); | |
| Printf(w->code, "}\n"); | |
| /* marshal return value */ | |
| if (!is_void) { | |
| /* Create a variable to hold the Lua stack index for $input */ | |
| Printf(w->code, "int SWIG_lua_result = lua_gettop(L);\n"); | |
| tm = Swig_typemap_lookup("directorout", n, Swig_cresult_name(), w); | |
| if (tm != 0) { | |
| Replaceall(tm, "$input", "SWIG_lua_result"); | |
| Replaceall(tm, "$result", "c_result"); | |
| Printf(w->code, "%s\n", tm); | |
| Delete(tm); | |
| } else { | |
| Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, | |
| input_file, | |
| line_number, | |
| "Unable to use return type %s in director method %s::%s (skipping method).\n", | |
| SwigType_str(returntype, 0), | |
| SwigType_namestr(c_classname), | |
| SwigType_namestr(name)); | |
| status = SWIG_ERROR; | |
| } | |
| } | |
| /* Clean up Lua stack */ | |
| Printf(w->code, "lua_settop(L, top);\n"); | |
| } | |
| Delete(arglist); | |
| } | |
| if (!is_void) { | |
| if (!(ignored_method && !pure_virtual)) { | |
| String *rettype = SwigType_str(returntype, 0); | |
| if (!SwigType_isreference(returntype)) { | |
| Printf(w->code, "return (%s) c_result;\n", rettype); | |
| } else { | |
| Printf(w->code, "return (%s) *c_result;\n", rettype); | |
| } | |
| Delete(rettype); | |
| } | |
| } | |
| Append(w->code, "}\n"); | |
| // We expose protected methods via an extra public inline method | |
| String *inline_extra_method = NewString(""); | |
| if (dirprot_mode() && !is_public(n) && !pure_virtual) { | |
| Printv(inline_extra_method, declaration, NIL); | |
| String *extra_method_name = NewStringf("%sSwigPublic", name); | |
| Replaceall(inline_extra_method, name, extra_method_name); | |
| Replaceall(inline_extra_method, ";\n", " {\n "); | |
| if (!is_void) | |
| Printf(inline_extra_method, "return "); | |
| String *methodcall = Swig_method_call(super, l); | |
| Printv(inline_extra_method, methodcall, ";\n }\n", NIL); | |
| Delete(methodcall); | |
| Delete(extra_method_name); | |
| } | |
| /* emit the director method */ | |
| if (status == SWIG_OK) { | |
| emit_isvoid_special_variables(0, w->code, is_void); | |
| if (!Getattr(n, "defaultargs")) { | |
| Replaceall(w->code, "$symname", symname); | |
| Wrapper_print(w, f_directors); | |
| Printv(f_directors_h, declaration, NIL); | |
| Printv(f_directors_h, inline_extra_method, NIL); | |
| } | |
| } | |
| /* clean up */ | |
| Delete(wrap_args); | |
| Delete(pclassname); | |
| Delete(declaration); | |
| Delete(inline_extra_method); | |
| DelWrapper(w); | |
| return status; | |
| } | |
| /* ------------------------------------------------------------ | |
| * classDirectorMethods() | |
| * ------------------------------------------------------------ */ | |
| int classDirectorMethods(Node *n) { | |
| return Language::classDirectorMethods(n); | |
| } | |
| /* ------------------------------------------------------------ | |
| * classDirectorDisown() | |
| * ------------------------------------------------------------ */ | |
| int classDirectorDisown(Node *n) { | |
| (void)n; | |
| return SWIG_OK; | |
| } | |
| /* ------------------------------------------------------------ | |
| * nestedClassesSupport() | |
| * ------------------------------------------------------------ */ | |
| NestedClassSupport nestedClassesSupport() const { | |
| return NCS_Full; | |
| } | |
| }; | |
| /* ----------------------------------------------------------------------------- | |
| * swig_lua() - Instantiate module | |
| * ----------------------------------------------------------------------------- */ | |
| extern "C" Language *swig_lua(void) { | |
| return new LUA(); | |
| } |