/* ----------------------------------------------------------------------------- * 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 http://www.swig.org/legal.html. * * pike.cxx * * Pike language module for SWIG. * ----------------------------------------------------------------------------- */ /* * Notes: * * - The current approach used for "out" typemaps is inconsistent with * how "out" typemaps are handled by other language modules. Instead * of converting the C/C++ type ($1) to a Pike object type (e.g. a * struct svalue), we're just calling the appropriate push_XXX * (e.g. push_int) to push the return value onto the stack. * * - Pike classes can't have static member functions or data, so we need * to find some other appropriate mapping for C++ static member functions * and data. * * - Pike doesn't seem to provide any default way to print the memory * address, etc. for extension objects. Should we do something here? * */ char cvsroot_pike_cxx[] = "$Id$"; #include "swigmod.h" #include // for isalnum() static const char *usage = (char *) "\ Pike Options (available with -pike)\n\ [None]\n\ \n"; class PIKE:public Language { private: File *f_begin; File *f_runtime; File *f_header; File *f_wrappers; File *f_init; File *f_classInit; String *PrefixPlusUnderscore; int current; // Wrap modes enum { NO_CPP, MEMBER_FUNC, CONSTRUCTOR, DESTRUCTOR, MEMBER_VAR, CLASS_CONST, STATIC_FUNC, STATIC_VAR }; public: /* --------------------------------------------------------------------- * PIKE() * * Initialize member data * --------------------------------------------------------------------- */ PIKE() { f_begin = 0; f_runtime = 0; f_header = 0; f_wrappers = 0; f_init = 0; f_classInit = 0; PrefixPlusUnderscore = 0; current = NO_CPP; } /* --------------------------------------------------------------------- * main() * * Parse command line options and initializes variables. * --------------------------------------------------------------------- */ virtual void main(int argc, char *argv[]) { /* Set location of SWIG library */ SWIG_library_directory("pike"); /* Look for certain command line options */ for (int i = 1; i < argc; i++) { if (argv[i]) { if (strcmp(argv[i], "-help") == 0) { fputs(usage, stdout); } } } /* Add a symbol to the parser for conditional compilation */ Preprocessor_define("SWIGPIKE 1", 0); /* Set language-specific configuration file */ SWIG_config_file("pike.swg"); /* Set typemap language */ SWIG_typemap_lang("pike"); /* Enable overloaded methods support */ allow_overloading(); } /* --------------------------------------------------------------------- * top() * --------------------------------------------------------------------- */ virtual int top(Node *n) { /* Get the module name */ String *module = Getattr(n, "name"); /* Get the output file name */ String *outfile = Getattr(n, "outfile"); /* Open the output file */ f_begin = NewFile(outfile, "w", SWIG_output_files()); if (!f_begin) { FileErrorDisplay(outfile); SWIG_exit(EXIT_FAILURE); } f_runtime = NewString(""); f_init = NewString(""); f_classInit = NewString(""); f_header = NewString(""); f_wrappers = 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("classInit", f_classInit); /* Standard stuff for the SWIG runtime section */ Swig_banner(f_begin); Printf(f_runtime, "\n"); Printf(f_runtime, "#define SWIGPIKE\n"); Printf(f_runtime, "\n"); Printf(f_header, "#define SWIG_init pike_module_init\n"); Printf(f_header, "#define SWIG_name \"%s\"\n\n", module); /* Change naming scheme for constructors and destructors */ Swig_name_register("construct", "%n%c_create"); Swig_name_register("destroy", "%n%c_destroy"); /* Current wrap type */ current = NO_CPP; /* Emit code for children */ Language::top(n); /* Close the initialization function */ Printf(f_init, "}\n"); SwigType_emit_type_table(f_runtime, f_wrappers); /* Close all of the files */ Dump(f_runtime, f_begin); Dump(f_header, f_begin); Dump(f_wrappers, f_begin); Wrapper_pretty_print(f_init, f_begin); Delete(f_header); Delete(f_wrappers); Delete(f_init); Delete(f_classInit); Close(f_begin); Delete(f_runtime); Delete(f_begin); /* Done */ return SWIG_OK; } /* ------------------------------------------------------------ * validIdentifier() * ------------------------------------------------------------ */ virtual int validIdentifier(String *s) { char *c = Char(s); const char *c0 = c; const char *c1 = c0 + 1; while (*c) { if (*c == '`' && c == c0) { c++; continue; } if ((*c == '+' || *c == '-' || *c == '*' || *c == '/') && c == c1) { c++; continue; } if (!(isalnum(*c) || (*c == '_'))) return 0; c++; } return 1; } /* ------------------------------------------------------------ * importDirective() * ------------------------------------------------------------ */ virtual int importDirective(Node *n) { String *modname = Getattr(n, "module"); if (modname) { Printf(f_init, "pike_require(\"%s\");\n", modname); } return Language::importDirective(n); } /* ------------------------------------------------------------ * strip() * * For names that begin with the current class prefix plus an * underscore (e.g. "Foo_enum_test"), return the base function * name (i.e. "enum_test"). * ------------------------------------------------------------ */ String *strip(const DOHconst_String_or_char_ptr name) { String *s = Copy(name); if (Strncmp(name, PrefixPlusUnderscore, Len(PrefixPlusUnderscore)) != 0) { return s; } Replaceall(s, PrefixPlusUnderscore, ""); return s; } /* ------------------------------------------------------------ * add_method() * ------------------------------------------------------------ */ void add_method(const DOHconst_String_or_char_ptr name, const DOHconst_String_or_char_ptr function, const DOHconst_String_or_char_ptr description) { String *rename = NULL; switch (current) { case NO_CPP: rename = NewString(name); Printf(f_init, "ADD_FUNCTION(\"%s\", %s, tFunc(%s), 0);\n", rename, function, description); break; case STATIC_FUNC: case STATIC_VAR: rename = NewString(name); Printf(f_init, "ADD_FUNCTION(\"%s\", %s, tFunc(%s), 0);\n", rename, function, description); break; case CONSTRUCTOR: case DESTRUCTOR: case MEMBER_FUNC: case MEMBER_VAR: rename = strip(name); Printf(f_classInit, "ADD_FUNCTION(\"%s\", %s, tFunc(%s), 0);\n", rename, function, description); break; case CLASS_CONST: assert(false); // shouldn't have gotten here for CLASS_CONST nodes default: assert(false); // what is this? } Delete(rename); } /* --------------------------------------------------------------------- * functionWrapper() * * Create a function declaration and register it with the interpreter. * --------------------------------------------------------------------- */ virtual int functionWrapper(Node *n) { String *name = Getattr(n, "name"); String *iname = Getattr(n, "sym:name"); SwigType *d = Getattr(n, "type"); ParmList *l = Getattr(n, "parms"); Parm *p; String *tm; int i; String *overname = 0; if (Getattr(n, "sym:overloaded")) { overname = Getattr(n, "sym:overname"); } else { if (!addSymbol(iname, n)) return SWIG_ERROR; } Wrapper *f = NewWrapper(); // Emit all of the local variables for holding arguments. emit_parameter_variables(l, f); /* Attach the standard typemaps */ emit_attach_parmmaps(l, f); Setattr(n, "wrap:parms", l); /* Get number of required and total arguments */ int num_arguments = emit_num_arguments(l); int varargs = emit_isvarargs(l); /* Which input argument to start with? */ int start = (current == MEMBER_FUNC || current == MEMBER_VAR || current == DESTRUCTOR) ? 1 : 0; /* Offset to skip over the attribute name */ // int offset = (current == MEMBER_VAR) ? 1 : 0; int offset = 0; String *wname = Swig_name_wrapper(iname); if (overname) { Append(wname, overname); } Setattr(n, "wrap:name", wname); Printv(f->def, "static void ", wname, "(INT32 args) {", NIL); /* Generate code for argument marshalling */ String *description = NewString(""); char source[64]; for (i = 0, p = l; i < num_arguments; i++) { while (checkAttribute(p, "tmap:in:numinputs", "0")) { p = Getattr(p, "tmap:in:next"); } SwigType *pt = Getattr(p, "type"); String *ln = Getattr(p, "lname"); if (i < start) { String *lstr = SwigType_lstr(pt, 0); Printf(f->code, "%s = (%s) THIS;\n", ln, lstr); Delete(lstr); } else { /* Look for an input typemap */ sprintf(source, "Pike_sp[%d-args]", i - start + offset); if ((tm = Getattr(p, "tmap:in"))) { Replaceall(tm, "$source", source); Replaceall(tm, "$target", ln); Replaceall(tm, "$input", source); Setattr(p, "emit:input", source); Printf(f->code, "%s\n", tm); String *pikedesc = Getattr(p, "tmap:in:pikedesc"); if (pikedesc) { Printv(description, pikedesc, " ", NIL); } p = Getattr(p, "tmap:in:next"); continue; } else { 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 = nextSibling(p); } /* Check for trailing varargs */ if (varargs) { if (p && (tm = Getattr(p, "tmap:in"))) { Replaceall(tm, "$input", "varargs"); Printv(f->code, tm, "\n", NIL); } } /* Insert constraint checking code */ for (p = l; p;) { if ((tm = Getattr(p, "tmap:check"))) { Replaceall(tm, "$target", Getattr(p, "lname")); Printv(f->code, tm, "\n", NIL); p = Getattr(p, "tmap:check:next"); } else { p = nextSibling(p); } } /* Insert cleanup code */ String *cleanup = NewString(""); for (p = l; p;) { if ((tm = Getattr(p, "tmap:freearg"))) { Replaceall(tm, "$source", Getattr(p, "lname")); Printv(cleanup, tm, "\n", NIL); p = Getattr(p, "tmap:freearg:next"); } else { p = nextSibling(p); } } /* Insert argument output code */ String *outarg = NewString(""); for (p = l; p;) { if ((tm = Getattr(p, "tmap:argout"))) { Replaceall(tm, "$source", Getattr(p, "lname")); Replaceall(tm, "$target", "resultobj"); 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); } } /* Emit the function call */ String *actioncode = emit_action(n); /* Clear the return stack */ Printf(actioncode, "pop_n_elems(args);\n"); /* Return the function value */ if (current == CONSTRUCTOR) { Printv(actioncode, "THIS = (void *) result;\n", NIL); Printv(description, ", tVoid", NIL); } else if (current == DESTRUCTOR) { Printv(description, ", tVoid", NIL); } else { Printv(description, ", ", NIL); if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { actioncode = 0; Replaceall(tm, "$source", "result"); Replaceall(tm, "$target", "resultobj"); Replaceall(tm, "$result", "resultobj"); if (GetFlag(n, "feature:new")) { Replaceall(tm, "$owner", "1"); } else { Replaceall(tm, "$owner", "0"); } String *pikedesc = Getattr(n, "tmap:out:pikedesc"); if (pikedesc) { Printv(description, pikedesc, NIL); } Printf(f->code, "%s\n", tm); } else { Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d, 0), name); } } if (actioncode) { Append(f->code, actioncode); Delete(actioncode); } emit_return_variable(n, d, f); /* Output argument output code */ Printv(f->code, outarg, NIL); /* Output cleanup code */ Printv(f->code, cleanup, NIL); /* Look to see if there is any newfree cleanup code */ if (GetFlag(n, "feature:new")) { if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { Replaceall(tm, "$source", "result"); Printf(f->code, "%s\n", tm); } } /* See if there is any return cleanup code */ if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { Replaceall(tm, "$source", "result"); Printf(f->code, "%s\n", tm); } /* Close the function */ Printf(f->code, "}\n"); /* Substitute the cleanup code */ Replaceall(f->code, "$cleanup", cleanup); /* Substitute the function name */ Replaceall(f->code, "$symname", iname); Replaceall(f->code, "$result", "resultobj"); /* Dump the function out */ Wrapper_print(f, f_wrappers); /* Now register the function with the interpreter. */ if (!Getattr(n, "sym:overloaded")) { add_method(iname, wname, description); } else { if (!Getattr(n, "sym:nextSibling")) { dispatchFunction(n); } } Delete(cleanup); Delete(outarg); Delete(description); Delete(wname); DelWrapper(f); return SWIG_OK; } /* ------------------------------------------------------------ * dispatchFunction() * * Emit overloading dispatch function * ------------------------------------------------------------ */ void dispatchFunction(Node *n) { /* Last node in overloaded chain */ int maxargs; String *tmp = NewString(""); String *dispatch = Swig_overload_dispatch(n, "%s(args); return;", &maxargs); /* Generate a dispatch wrapper for all overloaded functions */ Wrapper *f = NewWrapper(); String *symname = Getattr(n, "sym:name"); String *wname = Swig_name_wrapper(symname); Printf(f->def, "static void %s(INT32 args) {", wname); Wrapper_add_local(f, "argc", "INT32 argc"); Printf(tmp, "struct svalue argv[%d]", maxargs); Wrapper_add_local(f, "argv", tmp); Wrapper_add_local(f, "ii", "INT32 ii"); Printf(f->code, "argc = args;\n"); Printf(f->code, "for (ii = 0; (ii < argc) && (ii < %d); ii++) {\n", maxargs); Printf(f->code, "argv[ii] = Pike_sp[ii-args];\n"); Printf(f->code, "}\n"); Replaceall(dispatch, "$args", "self, args"); Printv(f->code, dispatch, "\n", NIL); Printf(f->code, "Pike_error(\"No matching function for overloaded '%s'.\");\n", symname); Printv(f->code, "}\n", NIL); Wrapper_print(f, f_wrappers); String *description = NewString(""); Printf(description, "tAny,"); if (current == CONSTRUCTOR || current == DESTRUCTOR) { Printf(description, " tVoid"); } else { String *pd = Getattr(n, "tmap:out:pikedesc"); if (pd) Printf(description, " %s", pd); } add_method(symname, wname, description); Delete(description); DelWrapper(f); Delete(dispatch); Delete(tmp); Delete(wname); } /* ------------------------------------------------------------ * variableWrapper() * ------------------------------------------------------------ */ virtual int variableWrapper(Node *n) { return Language::variableWrapper(n); } /* ------------------------------------------------------------ * constantWrapper() * ------------------------------------------------------------ */ virtual int constantWrapper(Node *n) { Swig_require("constantWrapper", n, "*sym:name", "type", "value", NIL); String *symname = Getattr(n, "sym:name"); SwigType *type = Getattr(n, "type"); String *value = Getattr(n, "value"); /* Special hook for member pointer */ if (SwigType_type(type) == T_MPOINTER) { String *wname = Swig_name_wrapper(symname); Printf(f_header, "static %s = %s;\n", SwigType_str(type, wname), value); value = wname; } /* Perform constant typemap substitution */ String *tm = Swig_typemap_lookup("constant", n, value, 0); if (tm) { Replaceall(tm, "$source", value); Replaceall(tm, "$target", symname); Replaceall(tm, "$symname", symname); Replaceall(tm, "$value", value); Printf(f_init, "%s\n", tm); } else { Swig_warning(WARN_TYPEMAP_CONST_UNDEF, input_file, line_number, "Unsupported constant value %s = %s\n", SwigType_str(type, 0), value); } Swig_restore(n); return SWIG_OK; } /* ------------------------------------------------------------ * nativeWrapper() * ------------------------------------------------------------ */ virtual int nativeWrapper(Node *n) { // return Language::nativeWrapper(n); String *name = Getattr(n, "sym:name"); String *wrapname = Getattr(n, "wrap:name"); if (!addSymbol(wrapname, n)) return SWIG_ERROR; add_method(name, wrapname, 0); return SWIG_OK; } /* ------------------------------------------------------------ * enumDeclaration() * ------------------------------------------------------------ */ virtual int enumDeclaration(Node *n) { return Language::enumDeclaration(n); } /* ------------------------------------------------------------ * enumvalueDeclaration() * ------------------------------------------------------------ */ virtual int enumvalueDeclaration(Node *n) { return Language::enumvalueDeclaration(n); } /* ------------------------------------------------------------ * classDeclaration() * ------------------------------------------------------------ */ virtual int classDeclaration(Node *n) { return Language::classDeclaration(n); } /* ------------------------------------------------------------ * classHandler() * ------------------------------------------------------------ */ virtual int classHandler(Node *n) { String *symname = Getattr(n, "sym:name"); if (!addSymbol(symname, n)) return SWIG_ERROR; PrefixPlusUnderscore = NewStringf("%s_", getClassPrefix()); Printf(f_classInit, "start_new_program();\n"); /* Handle inheritance */ List *baselist = Getattr(n, "bases"); if (baselist && Len(baselist) > 0) { Iterator base = First(baselist); while (base.item) { String *basename = Getattr(base.item, "name"); SwigType *basetype = NewString(basename); SwigType_add_pointer(basetype); SwigType_remember(basetype); String *basemangle = SwigType_manglestr(basetype); Printf(f_classInit, "low_inherit((struct program *) SWIGTYPE%s->clientdata, 0, 0, 0, 0, 0);\n", basemangle); Delete(basemangle); Delete(basetype); base = Next(base); } } else { Printf(f_classInit, "ADD_STORAGE(swig_object_wrapper);\n"); } Language::classHandler(n); /* Accessors for member variables */ /* List *membervariables = Getattr(n,"membervariables"); if (membervariables && Len(membervariables) > 0) { membervariableAccessors(membervariables); } */ /* Done, close the class and dump its definition to the init function */ Printf(f_classInit, "add_program_constant(\"%s\", pr = end_program(), 0);\n", symname); Dump(f_classInit, f_init); Clear(f_classInit); SwigType *tt = NewString(symname); SwigType_add_pointer(tt); SwigType_remember(tt); String *tm = SwigType_manglestr(tt); Printf(f_init, "SWIG_TypeClientData(SWIGTYPE%s, (void *) pr);\n", tm); Delete(tm); Delete(tt); Delete(PrefixPlusUnderscore); PrefixPlusUnderscore = 0; return SWIG_OK; } /* ------------------------------------------------------------ * memberfunctionHandler() * * Method for adding C++ member function * ------------------------------------------------------------ */ virtual int memberfunctionHandler(Node *n) { current = MEMBER_FUNC; Language::memberfunctionHandler(n); current = NO_CPP; return SWIG_OK; } /* ------------------------------------------------------------ * constructorHandler() * * Method for adding C++ member constructor * ------------------------------------------------------------ */ virtual int constructorHandler(Node *n) { current = CONSTRUCTOR; Language::constructorHandler(n); current = NO_CPP; return SWIG_OK; } /* ------------------------------------------------------------ * destructorHandler() * ------------------------------------------------------------ */ virtual int destructorHandler(Node *n) { current = DESTRUCTOR; Language::destructorHandler(n); current = NO_CPP; return SWIG_OK; } /* ------------------------------------------------------------ * membervariableAccessors() * ------------------------------------------------------------ */ void membervariableAccessors(List *membervariables) { String *name; Iterator i; bool need_setter; String *funcname; /* If at least one of them is mutable, we need a setter */ need_setter = false; i = First(membervariables); while (i.item) { if (!GetFlag(i.item, "feature:immutable")) { need_setter = true; break; } i = Next(i); } /* Create a function to set the values of the (mutable) variables */ if (need_setter) { Wrapper *wrapper = NewWrapper(); String *setter = Swig_name_member(NSPACE_TODO, getClassPrefix(), "`->="); String *wname = Swig_name_wrapper(setter); Printv(wrapper->def, "static void ", wname, "(INT32 args) {", NIL); Printf(wrapper->locals, "char *name = (char *) STR0(Pike_sp[0-args].u.string);\n"); i = First(membervariables); while (i.item) { if (!GetFlag(i.item, "feature:immutable")) { name = Getattr(i.item, "name"); funcname = Swig_name_wrapper(Swig_name_set(NSPACE_TODO, Swig_name_member(NSPACE_TODO, getClassPrefix(), name))); Printf(wrapper->code, "if (!strcmp(name, \"%s\")) {\n", name); Printf(wrapper->code, "%s(args);\n", funcname); Printf(wrapper->code, "return;\n"); Printf(wrapper->code, "}\n"); Delete(funcname); } i = Next(i); } /* Close the function */ Printf(wrapper->code, "pop_n_elems(args);\n"); Printf(wrapper->code, "}\n"); /* Dump wrapper code to the output file */ Wrapper_print(wrapper, f_wrappers); /* Register it with Pike */ String *description = NewString("tStr tFloat, tVoid"); add_method("`->=", wname, description); Delete(description); /* Clean up */ Delete(wname); Delete(setter); DelWrapper(wrapper); } /* Create a function to get the values of the (mutable) variables */ Wrapper *wrapper = NewWrapper(); String *getter = Swig_name_member(NSPACE_TODO, getClassPrefix(), "`->"); String *wname = Swig_name_wrapper(getter); Printv(wrapper->def, "static void ", wname, "(INT32 args) {", NIL); Printf(wrapper->locals, "char *name = (char *) STR0(Pike_sp[0-args].u.string);\n"); i = First(membervariables); while (i.item) { name = Getattr(i.item, "name"); funcname = Swig_name_wrapper(Swig_name_get(NSPACE_TODO, Swig_name_member(NSPACE_TODO, getClassPrefix(), name))); Printf(wrapper->code, "if (!strcmp(name, \"%s\")) {\n", name); Printf(wrapper->code, "%s(args);\n", funcname); Printf(wrapper->code, "return;\n"); Printf(wrapper->code, "}\n"); Delete(funcname); i = Next(i); } /* Close the function */ Printf(wrapper->code, "pop_n_elems(args);\n"); Printf(wrapper->code, "}\n"); /* Dump wrapper code to the output file */ Wrapper_print(wrapper, f_wrappers); /* Register it with Pike */ String *description = NewString("tStr, tMix"); add_method("`->", wname, description); Delete(description); /* Clean up */ Delete(wname); Delete(getter); DelWrapper(wrapper); } /* ------------------------------------------------------------ * membervariableHandler() * ------------------------------------------------------------ */ virtual int membervariableHandler(Node *n) { List *membervariables = Getattr(getCurrentClass(), "membervariables"); if (!membervariables) { membervariables = NewList(); Setattr(getCurrentClass(), "membervariables", membervariables); } Append(membervariables, n); current = MEMBER_VAR; Language::membervariableHandler(n); current = NO_CPP; return SWIG_OK; } /* ----------------------------------------------------------------------- * staticmemberfunctionHandler() * * Wrap a static C++ function * ---------------------------------------------------------------------- */ virtual int staticmemberfunctionHandler(Node *n) { current = STATIC_FUNC; Language::staticmemberfunctionHandler(n); current = NO_CPP; return SWIG_OK; } /* ------------------------------------------------------------ * memberconstantHandler() * * Create a C++ constant * ------------------------------------------------------------ */ virtual int memberconstantHandler(Node *n) { current = CLASS_CONST; constantWrapper(n); current = NO_CPP; return SWIG_OK; } /* --------------------------------------------------------------------- * staticmembervariableHandler() * --------------------------------------------------------------------- */ virtual int staticmembervariableHandler(Node *n) { current = STATIC_VAR; Language::staticmembervariableHandler(n); current = NO_CPP; return SWIG_OK; } }; /* ----------------------------------------------------------------------------- * swig_pike() - Instantiate module * ----------------------------------------------------------------------------- */ static Language *new_swig_pike() { return new PIKE(); } extern "C" Language *swig_pike(void) { return new_swig_pike(); }