| /******************************************************************** |
| * Ruby module for SWIG |
| * |
| * $Header$ |
| * |
| * Copyright (C) 2000 Network Applied Communication Laboratory, Inc. |
| * Copyright (C) 2000 Information-technology Promotion Agency, Japan |
| * |
| * Masaki Fukushima |
| * |
| ********************************************************************/ |
| |
| char cvsroot_ruby_cxx[] = "$Header$"; |
| |
| #include "swigmod.h" |
| #define SWIG_PROTECTED_TARGET_METHODS 1 |
| |
| #include <ctype.h> |
| #include <string.h> |
| #include <limits.h> /* for INT_MAX */ |
| |
| class RClass { |
| private: |
| String *temp; |
| public: |
| String *name; /* class name (renamed) */ |
| String *cname; /* original C class/struct name */ |
| String *mname; /* Mangled name */ |
| |
| /** |
| * The C variable name used in the SWIG-generated wrapper code to refer to |
| * this class; usually it is of the form "cClassName.klass", where cClassName |
| * is a swig_class struct instance and klass is a member of that struct. |
| */ |
| String *vname; |
| |
| /** |
| * The C variable name used in the SWIG-generated wrapper code to refer to |
| * the module that implements this class's methods (when we're trying to |
| * support C++ multiple inheritance). Usually it is of the form |
| * "cClassName.mImpl", where cClassName is a swig_class struct instance |
| * and mImpl is a member of that struct. |
| */ |
| String *mImpl; |
| |
| String *type; |
| String *prefix; |
| String *init; |
| |
| int constructor_defined; |
| int destructor_defined; |
| |
| RClass() { |
| temp = NewString(""); |
| name = NewString(""); |
| cname = NewString(""); |
| mname = NewString(""); |
| vname = NewString(""); |
| mImpl = NewString(""); |
| type = NewString(""); |
| prefix = NewString(""); |
| init = NewString(""); |
| constructor_defined = 0; |
| destructor_defined = 0; |
| } |
| |
| ~RClass() { |
| Delete(name); |
| Delete(cname); |
| Delete(vname); |
| Delete(mImpl); |
| Delete(mname); |
| Delete(type); |
| Delete(prefix); |
| Delete(init); |
| Delete(temp); |
| } |
| |
| void set_name(const String_or_char *cn, const String_or_char *rn, const String_or_char *valn) { |
| /* Original C/C++ class (or struct) name */ |
| Clear(cname); |
| Append(cname,cn); |
| |
| /* Mangled name */ |
| Delete(mname); |
| mname = Swig_name_mangle(cname); |
| |
| /* Renamed class name */ |
| Clear(name); |
| Append(name,valn); |
| |
| /* Variable name for the VALUE that refers to the Ruby Class object */ |
| Clear(vname); |
| Printf(vname, "c%s.klass", name); |
| |
| /* Variable name for the VALUE that refers to the Ruby Class object */ |
| Clear(mImpl); |
| Printf(mImpl, "c%s.mImpl", name); |
| |
| /* Prefix */ |
| Clear(prefix); |
| Printv(prefix,(rn ? rn : cn), "_", NIL); |
| } |
| |
| char *strip(const String_or_char *s) { |
| Clear(temp); |
| Append(temp, s); |
| if (Strncmp(s, prefix, Len(prefix)) == 0) { |
| Replaceall(temp,prefix,""); |
| } |
| return Char(temp); |
| } |
| }; |
| |
| |
| static const char * |
| usage = "\ |
| Ruby Options (available with -ruby)\n\ |
| -globalmodule - Wrap everything into the global module\n\ |
| -minherit - Attempt to support multiple inheritance\n\ |
| -prefix <name> - Set a prefix <name> to be prepended to all names\n\ |
| -feature <name> - Set feature name to <name> (used by `require')\n"; |
| |
| |
| #define RCLASS(hash, name) (RClass*)(Getattr(hash, name) ? Data(Getattr(hash, name)) : 0) |
| #define SET_RCLASS(hash, name, klass) Setattr(hash, name, NewVoid(klass, 0)) |
| |
| class RUBY : public Language { |
| private: |
| |
| String *module; |
| String *modvar; |
| String *feature; |
| String *prefix; |
| int current; |
| Hash *classes; /* key=cname val=RClass */ |
| RClass *klass; /* Currently processing class */ |
| Hash *special_methods; /* Python style special method name table */ |
| |
| File *f_directors; |
| File *f_directors_h; |
| File *f_runtime; |
| File *f_runtime_h; |
| File *f_header; |
| File *f_wrappers; |
| File *f_init; |
| File *f_initbeforefunc; |
| |
| bool useGlobalModule; |
| bool multipleInheritance; |
| |
| // Wrap modes |
| enum { |
| NO_CPP, |
| MEMBER_FUNC, |
| CONSTRUCTOR_ALLOCATE, |
| CONSTRUCTOR_INITIALIZE, |
| DESTRUCTOR, |
| MEMBER_VAR, |
| CLASS_CONST, |
| STATIC_FUNC, |
| STATIC_VAR |
| }; |
| |
| public: |
| |
| /* --------------------------------------------------------------------- |
| * RUBY() |
| * |
| * Initialize member data |
| * --------------------------------------------------------------------- */ |
| |
| RUBY() { |
| module = 0; |
| modvar = 0; |
| feature = 0; |
| prefix = 0; |
| current = NO_CPP; |
| classes = 0; |
| klass = 0; |
| special_methods = 0; |
| f_runtime = 0; |
| f_header = 0; |
| f_wrappers = 0; |
| f_init = 0; |
| f_initbeforefunc = 0; |
| useGlobalModule = false; |
| multipleInheritance = false; |
| director_prot_ctor_code = NewString(""); |
| Printv(director_prot_ctor_code, |
| "if ( $comparison ) { /* subclassed */\n", |
| " $director_new \n", |
| "} else {\n", |
| " rb_raise(rb_eRuntimeError,\"accessing abstract class or protected constructor\"); \n", |
| " return Qnil;\n", |
| "}\n", NIL); |
| director_multiple_inheritance = 0; |
| director_language = 1; |
| } |
| |
| /* --------------------------------------------------------------------- |
| * main() |
| * |
| * Parse command line options and initializes variables. |
| * --------------------------------------------------------------------- */ |
| |
| virtual void main(int argc, char *argv[]) { |
| |
| /* Set location of SWIG library */ |
| SWIG_library_directory("ruby"); |
| |
| /* Look for certain command line options */ |
| for (int i = 1; i < argc; i++) { |
| if (argv[i]) { |
| if (strcmp(argv[i],"-feature") == 0) { |
| if (argv[i+1]) { |
| char *name = argv[i+1]; |
| feature = NewString(name); |
| Swig_mark_arg(i); |
| Swig_mark_arg(i+1); |
| i++; |
| } else { |
| Swig_arg_error(); |
| } |
| } else if (strcmp(argv[i],"-globalmodule") == 0) { |
| useGlobalModule = true; |
| Swig_mark_arg(i); |
| } else if (strcmp(argv[i],"-minherit") == 0) { |
| multipleInheritance = true; |
| director_multiple_inheritance = 1; |
| Swig_mark_arg(i); |
| } else if (strcmp(argv[i],"-prefix") == 0) { |
| if (argv[i+1]) { |
| char *name = argv[i+1]; |
| prefix = NewString(name); |
| Swig_mark_arg(i); |
| Swig_mark_arg(i+1); |
| i++; |
| } else { |
| Swig_arg_error(); |
| } |
| } else if (strcmp(argv[i],"-help") == 0) { |
| Printf(stdout,"%s\n", usage); |
| } |
| } |
| } |
| |
| /* Add a symbol to the parser for conditional compilation */ |
| Preprocessor_define("SWIGRUBY 1", 0); |
| |
| /* Add typemap definitions */ |
| SWIG_typemap_lang("ruby"); |
| SWIG_config_file("ruby.swg"); |
| allow_overloading(); |
| } |
| |
| /** |
| * Generate initialization code to define the Ruby module(s), |
| * accounting for nested modules as necessary. |
| */ |
| void defineRubyModule() { |
| List *modules = Split(module,':',INT_MAX); |
| if (modules != 0 && Len(modules) > 0) { |
| String *mv = 0; |
| Iterator m; |
| m = First(modules); |
| while (m.item) { |
| if (Len(m.item) > 0) { |
| if (mv != 0) { |
| Printv(f_init, tab4, modvar, |
| " = rb_define_module_under(", modvar, ", \"", m.item, "\");\n", NIL); |
| } else { |
| Printv(f_init, tab4, modvar, |
| " = rb_define_module(\"", m.item, "\");\n", NIL); |
| mv = NewString(modvar); |
| } |
| } |
| m = Next(m); |
| } |
| Delete(mv); |
| Delete(modules); |
| } |
| } |
| |
| void registerMagicMethods() { |
| |
| special_methods = NewHash(); |
| |
| /* Python style special method name. */ |
| /* Basic */ |
| Setattr(special_methods, "__repr__", "inspect"); |
| Setattr(special_methods, "__str__", "to_s"); |
| Setattr(special_methods, "__cmp__", "<=>"); |
| Setattr(special_methods, "__hash__", "hash"); |
| Setattr(special_methods, "__nonzero__", "nonzero?"); |
| |
| /* Callable */ |
| Setattr(special_methods, "__call__", "call"); |
| |
| /* Collection */ |
| Setattr(special_methods, "__len__", "length"); |
| Setattr(special_methods, "__getitem__", "[]"); |
| Setattr(special_methods, "__setitem__", "[]="); |
| |
| /* Operators */ |
| Setattr(special_methods, "__add__", "+"); |
| Setattr(special_methods, "__pos__", "+@"); |
| Setattr(special_methods, "__sub__", "-"); |
| Setattr(special_methods, "__neg__", "-@"); |
| Setattr(special_methods, "__mul__", "*"); |
| Setattr(special_methods, "__div__", "/"); |
| Setattr(special_methods, "__mod__", "%"); |
| Setattr(special_methods, "__lshift__", "<<"); |
| Setattr(special_methods, "__rshift__", ">>"); |
| Setattr(special_methods, "__and__", "&"); |
| Setattr(special_methods, "__or__", "|"); |
| Setattr(special_methods, "__xor__", "^"); |
| Setattr(special_methods, "__invert__", "~"); |
| Setattr(special_methods, "__lt__", "<"); |
| Setattr(special_methods, "__le__", "<="); |
| Setattr(special_methods, "__gt__", ">"); |
| Setattr(special_methods, "__ge__", ">="); |
| Setattr(special_methods, "__eq__", "=="); |
| |
| /* Other numeric */ |
| Setattr(special_methods, "__divmod__", "divmod"); |
| Setattr(special_methods, "__pow__", "**"); |
| Setattr(special_methods, "__abs__", "abs"); |
| Setattr(special_methods, "__int__", "to_i"); |
| Setattr(special_methods, "__float__", "to_f"); |
| Setattr(special_methods, "__coerce__", "coerce"); |
| } |
| |
| /* --------------------------------------------------------------------- |
| * top() |
| * --------------------------------------------------------------------- */ |
| |
| virtual int top(Node *n) { |
| |
| /** |
| * See if any Ruby module options have been specified as options |
| * to the %module directive. |
| */ |
| Node *swigModule = Getattr(n, "module"); |
| if (swigModule) { |
| Node *options = Getattr(swigModule, "options"); |
| if (options) { |
| if (Getattr(options, "directors")) { |
| allow_directors(); |
| } |
| if (Getattr(options, "dirprot")) { |
| allow_dirprot(); |
| } |
| if (Getattr(options, "ruby_globalmodule")) { |
| useGlobalModule = true; |
| } |
| if (Getattr(options, "ruby_minherit")) { |
| multipleInheritance = true; |
| director_multiple_inheritance = 1; |
| } |
| } |
| } |
| |
| /* Set comparison with none for ConstructorToFunction */ |
| |
| |
| setSubclassInstanceCheck(NewStringf("strcmp(rb_obj_classname(self), classname) != 0")); |
| // setSubclassInstanceCheck(NewString("CLASS_OF(self) != cFoo.klass")); |
| |
| /* Initialize all of the output files */ |
| String *outfile = Getattr(n,"outfile"); |
| String *outfile_h = Getattr(n, "outfile_h"); |
| |
| f_runtime = NewFile(outfile,"w"); |
| if (!f_runtime) { |
| FileErrorDisplay(outfile); |
| SWIG_exit(EXIT_FAILURE); |
| } |
| |
| if (directorsEnabled()) { |
| f_runtime_h = NewFile(outfile_h,"w"); |
| if (!f_runtime_h) { |
| FileErrorDisplay(outfile_h); |
| SWIG_exit(EXIT_FAILURE); |
| } |
| } |
| |
| f_init = NewString(""); |
| f_header = NewString(""); |
| f_wrappers = NewString(""); |
| f_directors_h = NewString(""); |
| f_directors = NewString(""); |
| f_initbeforefunc = NewString(""); |
| |
| /* Register file targets with the SWIG file handler */ |
| Swig_register_filebyname("header",f_header); |
| Swig_register_filebyname("wrapper",f_wrappers); |
| Swig_register_filebyname("runtime",f_runtime); |
| Swig_register_filebyname("init",f_init); |
| Swig_register_filebyname("director",f_directors); |
| Swig_register_filebyname("director_h",f_directors_h); |
| Swig_register_filebyname("initbeforefunc", f_initbeforefunc); |
| |
| modvar = 0; |
| current = NO_CPP; |
| klass = 0; |
| classes = NewHash(); |
| |
| registerMagicMethods(); |
| |
| Swig_banner(f_runtime); |
| |
| if (directorsEnabled()) { |
| Printf(f_runtime,"#define SWIG_DIRECTORS\n"); |
| } |
| |
| /* typedef void *VALUE */ |
| SwigType *value = NewSwigType(T_VOID); |
| SwigType_add_pointer(value); |
| SwigType_typedef(value,(char*)"VALUE"); |
| Delete(value); |
| |
| /* Set module name */ |
| set_module(Char(Getattr(n,"name"))); |
| |
| if (directorsEnabled()) { |
| Swig_banner(f_directors_h); |
| Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module); |
| Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module); |
| Printf(f_directors_h, "class Swig::Director;\n\n"); |
| Swig_insert_file("director.swg", f_directors); |
| Printf(f_directors, "\n\n"); |
| Printf(f_directors, "/* ---------------------------------------------------\n"); |
| Printf(f_directors, " * C++ director class methods\n"); |
| Printf(f_directors, " * --------------------------------------------------- */\n\n"); |
| Printf(f_directors, "#include \"%s\"\n\n", Swig_file_filename(outfile_h)); |
| } |
| |
| Printf(f_header,"#define SWIG_init Init_%s\n", feature); |
| Printf(f_header,"#define SWIG_name \"%s\"\n\n", module); |
| Printf(f_header,"static VALUE %s;\n", modvar); |
| |
| /* Start generating the initialization function */ |
| Printv(f_init, |
| "\n", |
| "#ifdef __cplusplus\n", |
| "extern \"C\"\n", |
| "#endif\n", |
| "SWIGEXPORT void Init_", feature, "(void) {\n", |
| "size_t i;\n", |
| "\n", |
| NIL); |
| |
| Printv(f_init, tab4, "SWIG_InitRuntime();\n", NIL); |
| |
| if (!useGlobalModule) |
| defineRubyModule(); |
| |
| Printv(f_init, |
| "\n", |
| "SWIG_InitializeModule(0);\n", |
| "for (i = 0; i < swig_module.size; i++) {\n", |
| "SWIG_define_class(swig_module.types[i]);\n", |
| "}\n", |
| NIL); |
| Printf(f_init,"\n"); |
| |
| /* Initialize code to keep track of objects */ |
| Printf(f_init,"SWIG_RubyInitializeTrackings();\n"); |
| |
| Language::top(n); |
| |
| /* Finish off our init function */ |
| Printf(f_init,"}\n"); |
| SwigType_emit_type_table(f_runtime,f_wrappers); |
| |
| /* Close all of the files */ |
| Dump(f_header,f_runtime); |
| |
| if (directorsEnabled()) { |
| Dump(f_directors, f_runtime); |
| Dump(f_directors_h, f_runtime_h); |
| Printf(f_runtime_h, "\n"); |
| Printf(f_runtime_h, "#endif\n"); |
| Close(f_runtime_h); |
| } |
| |
| Dump(f_wrappers,f_runtime); |
| Dump(f_initbeforefunc, f_runtime); |
| Wrapper_pretty_print(f_init,f_runtime); |
| |
| Delete(f_header); |
| Delete(f_wrappers); |
| Delete(f_init); |
| Delete(f_initbeforefunc); |
| Close(f_runtime); |
| Delete(f_runtime); |
| |
| return SWIG_OK; |
| } |
| |
| /* ----------------------------------------------------------------------------- |
| * importDirective() |
| * ----------------------------------------------------------------------------- */ |
| |
| virtual int importDirective(Node *n) { |
| String *modname = Getattr(n,"module"); |
| if (modname) { |
| if (prefix) { |
| Insert(modname, 0, prefix); |
| } |
| |
| List *modules = Split(modname,':',INT_MAX); |
| if (modules && Len(modules) > 0) { |
| modname = NewString(""); |
| String *last = NULL; |
| Iterator m = First(modules); |
| while (m.item) { |
| if (Len(m.item) > 0) { |
| if (last) { |
| Append(modname, "/"); |
| } |
| Append(modname, m.item); |
| last = m.item; |
| } |
| m = Next(m); |
| } |
| Printf(f_init,"rb_require(\"%s\");\n", modname); |
| Delete(modname); |
| } |
| Delete(modules); |
| } |
| return Language::importDirective(n); |
| } |
| |
| /* --------------------------------------------------------------------- |
| * set_module(const char *mod_name) |
| * |
| * Sets the module name. Does nothing if it's already set (so it can |
| * be overridden as a command line option). |
| *---------------------------------------------------------------------- */ |
| |
| void set_module(const char *s) { |
| String *mod_name = NewString(s); |
| if (module == 0) { |
| /* Start with the empty string */ |
| module = NewString(""); |
| |
| if (prefix) { |
| Insert(mod_name, 0, prefix); |
| } |
| |
| /* Account for nested modules */ |
| List *modules = Split(mod_name,':',INT_MAX); |
| if (modules != 0 && Len(modules) > 0) { |
| String *last = 0; |
| Iterator m = First(modules); |
| while (m.item) { |
| if (Len(m.item) > 0) { |
| String *cap = NewString(m.item); |
| (Char(cap))[0] = toupper((Char(cap))[0]); |
| if (last != 0) { |
| Append(module, "::"); |
| } |
| Append(module, cap); |
| last = m.item; |
| } |
| m = Next(m); |
| } |
| if (feature == 0) { |
| feature = Copy(last); |
| } |
| (Char(last))[0] = toupper((Char(last))[0]); |
| modvar = NewStringf("m%s", last); |
| Delete(modules); |
| } |
| } |
| Delete(mod_name); |
| } |
| |
| /* -------------------------------------------------------------------------- |
| * nativeWrapper() |
| * -------------------------------------------------------------------------- */ |
| virtual int nativeWrapper(Node *n) { |
| String *funcname = Getattr(n,"wrap:name"); |
| Swig_warning(WARN_LANG_NATIVE_UNIMPL, input_file, line_number, |
| "Adding native function %s not supported (ignored).\n", funcname); |
| return SWIG_NOWRAP; |
| } |
| |
| /** |
| * Process the comma-separated list of aliases (if any). |
| */ |
| void defineAliases(Node *n, const String_or_char *iname) { |
| String *aliasv = Getattr(n,"feature:alias"); |
| if (aliasv) { |
| List *aliases = Split(aliasv,',',INT_MAX); |
| if (aliases && Len(aliases) > 0) { |
| Iterator alias = First(aliases); |
| while (alias.item) { |
| if (Len(alias.item) > 0) { |
| Printv(klass->init, tab4, "rb_define_alias(", klass->vname, ", \"", alias.item, "\", \"", iname, "\");\n", NIL); |
| } |
| alias = Next(alias); |
| } |
| } |
| Delete(aliases); |
| } |
| } |
| |
| /* --------------------------------------------------------------------- |
| * create_command(Node *n, char *iname) |
| * |
| * Creates a new command from a C function. |
| * iname = Name of function in scripting language |
| * |
| * A note about what "protected" and "private" mean in Ruby: |
| * |
| * A private method is accessible only within the class or its subclasses, |
| * and it is callable only in "function form", with 'self' (implicit or |
| * explicit) as a receiver. |
| * |
| * A protected method is callable only from within its class, but unlike |
| * a private method, it can be called with a receiver other than self, such |
| * as another instance of the same class. |
| * --------------------------------------------------------------------- */ |
| |
| void create_command(Node *n, const String_or_char *iname) { |
| |
| String *alloc_func = Swig_name_wrapper(iname); |
| String *wname = Swig_name_wrapper(iname); |
| if (CPlusPlus) { |
| Insert(wname,0,"VALUEFUNC("); |
| Append(wname,")"); |
| } |
| if (current != NO_CPP) |
| iname = klass->strip(iname); |
| if (Getattr(special_methods, iname)) { |
| iname = GetChar(special_methods, iname); |
| } |
| |
| String *s = NewString(""); |
| String *temp = NewString(""); |
| |
| #ifdef SWIG_PROTECTED_TARGET_METHODS |
| const char* rb_define_method = is_public(n) ? |
| "rb_define_method" : "rb_define_protected_method" ; |
| #else |
| const char* rb_define_method = "rb_define_method"; |
| #endif |
| switch (current) { |
| case MEMBER_FUNC: |
| { |
| if (multipleInheritance) { |
| Printv(klass->init, tab4, rb_define_method,"(", klass->mImpl, ", \"", |
| iname, "\", ", wname, ", -1);\n", NIL); |
| } else { |
| Printv(klass->init, tab4, rb_define_method, "(", klass->vname, ", \"", |
| iname, "\", ", wname, ", -1);\n", NIL); |
| } |
| } |
| break; |
| case CONSTRUCTOR_ALLOCATE: |
| Printv(s, tab4, "rb_define_alloc_func(", klass->vname, ", ", alloc_func, ");\n", NIL); |
| Replaceall(klass->init,"$allocator", s); |
| break; |
| case CONSTRUCTOR_INITIALIZE: |
| Printv(s, tab4, rb_define_method,"(", klass->vname, |
| ", \"initialize\", ", wname, ", -1);\n", NIL); |
| Replaceall(klass->init,"$initializer", s); |
| break; |
| case MEMBER_VAR: |
| Append(temp,iname); |
| Replaceall(temp,"_set", "="); |
| Replaceall(temp,"_get", ""); |
| if (multipleInheritance) { |
| Printv(klass->init, tab4, "rb_define_method(", klass->mImpl, ", \"", |
| temp, "\", ", wname, ", -1);\n", NIL); |
| } else { |
| Printv(klass->init, tab4, "rb_define_method(", klass->vname, ", \"", |
| temp, "\", ", wname, ", -1);\n", NIL); |
| } |
| break; |
| case STATIC_FUNC: |
| Printv(klass->init, tab4, "rb_define_singleton_method(", klass->vname, |
| ", \"", iname, "\", ", wname, ", -1);\n", NIL); |
| break; |
| case NO_CPP: |
| if (!useGlobalModule) { |
| Printv(s, tab4, "rb_define_module_function(", modvar, ", \"", |
| iname, "\", ", wname, ", -1);\n",NIL); |
| Printv(f_init,s,NIL); |
| } else { |
| Printv(s, tab4, "rb_define_global_function(\"", |
| iname, "\", ", wname, ", -1);\n",NIL); |
| Printv(f_init,s,NIL); |
| } |
| break; |
| case DESTRUCTOR: |
| case CLASS_CONST: |
| case STATIC_VAR: |
| assert(false); // Should not have gotten here for these types |
| default: |
| assert(false); |
| } |
| |
| defineAliases(n, iname); |
| |
| Delete(temp); |
| Delete(s); |
| Delete(wname); |
| Delete(alloc_func); |
| } |
| |
| /* --------------------------------------------------------------------- |
| * applyInputTypemap() |
| * |
| * Look up the appropriate "in" typemap for this parameter (p), |
| * substitute the correct strings for the $target and $input typemap |
| * parameters, and dump the resulting code to the wrapper file. |
| * --------------------------------------------------------------------- */ |
| |
| Parm *applyInputTypemap(Parm *p, String *ln, String *source, Wrapper *f) { |
| String *tm; |
| SwigType *pt = Getattr(p,"type"); |
| if ((tm = Getattr(p,"tmap:in"))) { |
| Replaceall(tm,"$target",ln); |
| Replaceall(tm,"$source",source); |
| Replaceall(tm,"$input",source); |
| |
| if (Getattr(p,"wrap:disown") || (Getattr(p,"tmap:in:disown"))) { |
| Replaceall(tm,"$disown","SWIG_POINTER_DISOWN"); |
| } |
| else { |
| Replaceall(tm,"$disown","0"); |
| } |
| |
| /* Are we tracking the type represented by the |
| * object being disowned? Note this code cannot |
| * go into the first part of the wrap:disown if |
| * statement above because that is not activated |
| * when the SWIGTYPE *DISOWN type map is applied. */ |
| if (trackType(pt)) { |
| setTrackObjectsFlagForConvertPtr(tm); |
| } |
| |
| Setattr(p,"emit:input",Copy(source)); |
| Printf(f->code,"%s\n", tm); |
| p = Getattr(p,"tmap:in:next"); |
| } 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)); |
| p = nextSibling(p); |
| } |
| return p; |
| } |
| |
| Parm *skipIgnoredArgs(Parm *p) { |
| while (checkAttribute(p,"tmap:in:numinputs","0")) { |
| p = Getattr(p,"tmap:in:next"); |
| } |
| return p; |
| } |
| |
| /* --------------------------------------------------------------------- |
| * marshalInputArgs() |
| * |
| * Process all of the arguments passed into the scripting language |
| * method and convert them into C/C++ function arguments using the |
| * supplied typemaps. |
| * --------------------------------------------------------------------- */ |
| |
| void marshalInputArgs(Node *n, ParmList *l, int numarg, int numreq, String *kwargs, bool allow_kwargs, Wrapper *f) { |
| int i; |
| Parm *p; |
| String *tm; |
| String *source; |
| String *target; |
| |
| source = NewString(""); |
| target = NewString(""); |
| |
| bool ctor_director = (current == CONSTRUCTOR_INITIALIZE && Swig_directorclass(n)); |
| |
| /** |
| * The 'start' value indicates which of the C/C++ function arguments |
| * produced here corresponds to the first value in Ruby's argv[] array. |
| * The value of start is either zero or one. If start is zero, then |
| * the first argument (with name arg1) is based on the value of argv[0]. |
| * If start is one, then arg1 is based on the value of argv[1]. |
| */ |
| int start = (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) ? 1 : 0; |
| |
| int varargs = emit_isvarargs(l); |
| |
| Printf(kwargs,"{ "); |
| for (i = 0, p = l; i < numarg; i++) { |
| |
| p = skipIgnoredArgs(p); |
| |
| String *pn = Getattr(p,"name"); |
| String *ln = Getattr(p,"lname"); |
| |
| /* Produce string representation of source argument */ |
| Clear(source); |
| |
| /* First argument is a special case */ |
| if (i == 0) { |
| Printv(source, (start == 0) ? "argv[0]" : "self", NIL); |
| } else { |
| Printf(source,"argv[%d]",i-start); |
| } |
| |
| /* Produce string representation of target argument */ |
| Clear(target); |
| Printf(target,"%s",Char(ln)); |
| |
| if (i >= (numreq)) { /* Check if parsing an optional argument */ |
| Printf(f->code," if (argc > %d) {\n", i - start); |
| } |
| |
| /* Record argument name for keyword argument handling */ |
| if (Len(pn)) { |
| Printf(kwargs,"\"%s\",", pn); |
| } else { |
| Printf(kwargs,"\"arg%d\",", i+1); |
| } |
| |
| /* Look for an input typemap */ |
| p = applyInputTypemap(p, ln, source, f); |
| if (i >= numreq) { |
| Printf(f->code,"}\n"); |
| } |
| } |
| |
| /* Finish argument marshalling */ |
| Printf(kwargs," NULL }"); |
| if (allow_kwargs) { |
| Printv(f->locals, tab4, "char *kwnames[] = ", kwargs, ";\n", NIL); |
| } |
| |
| /* Trailing varargs */ |
| if (varargs) { |
| if (p && (tm = Getattr(p,"tmap:in"))) { |
| Clear(source); |
| Printf(source,"argv[%d]",i-start); |
| Replaceall(tm,"$input",source); |
| Setattr(p,"emit:input",Copy(source)); |
| Printf(f->code,"if (argc > %d) {\n", i-start); |
| Printv(f->code,tm,"\n",NIL); |
| Printf(f->code,"}\n"); |
| } |
| } |
| |
| Delete(source); |
| Delete(target); |
| } |
| |
| /* --------------------------------------------------------------------- |
| * insertConstraintCheckingCode(ParmList *l, Wrapper *f) |
| * |
| * Checks each of the parameters in the parameter list for a "check" |
| * typemap and (if it finds one) inserts the typemapping code into |
| * the function wrapper. |
| * --------------------------------------------------------------------- */ |
| |
| void insertConstraintCheckingCode(ParmList *l, Wrapper *f) { |
| Parm *p; |
| String *tm; |
| 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); |
| } |
| } |
| } |
| |
| /* --------------------------------------------------------------------- |
| * insertCleanupCode(ParmList *l, String *cleanup) |
| * |
| * Checks each of the parameters in the parameter list for a "freearg" |
| * typemap and (if it finds one) inserts the typemapping code into |
| * the function wrapper. |
| * --------------------------------------------------------------------- */ |
| |
| void insertCleanupCode(ParmList *l, String *cleanup) { |
| String *tm; |
| for (Parm *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); |
| } |
| } |
| } |
| |
| /* --------------------------------------------------------------------- |
| * insertArgOutputCode(ParmList *l, String *outarg, int& need_result) |
| * |
| * Checks each of the parameters in the parameter list for a "argout" |
| * typemap and (if it finds one) inserts the typemapping code into |
| * the function wrapper. |
| * --------------------------------------------------------------------- */ |
| |
| void insertArgOutputCode(ParmList *l, String *outarg, int& need_result) { |
| String *tm; |
| for (Parm *p = l; p; ) { |
| if ((tm = Getattr(p,"tmap:argout"))) { |
| Replaceall(tm,"$source",Getattr(p,"lname")); |
| Replaceall(tm,"$target","vresult"); |
| Replaceall(tm,"$result","vresult"); |
| Replaceall(tm,"$arg",Getattr(p,"emit:input")); |
| Replaceall(tm,"$input",Getattr(p,"emit:input")); |
| |
| /* Are we tracking the type that is being returned |
| * by this output parameter? */ |
| SwigType *pt = Getattr(p,"type"); |
| if (pt && trackType(pt)) { |
| setTrackObjectsFlagForNewPointer(tm); |
| } |
| |
| Printv(outarg,tm,"\n",NIL); |
| need_result = 1; |
| p = Getattr(p,"tmap:argout:next"); |
| } else { |
| p = nextSibling(p); |
| } |
| } |
| } |
| |
| /* --------------------------------------------------------------------- |
| * validIdentifier() |
| * |
| * Is this a valid identifier in the scripting language? |
| * Ruby method names can include any combination of letters, numbers |
| * and underscores. A Ruby method name may optionally end with |
| * a question mark ("?"), exclamation point ("!") or equals sign ("="). |
| * |
| * Methods whose names end with question marks are, by convention, |
| * predicate methods that return true or false (e.g. Array#empty?). |
| * |
| * Methods whose names end with exclamation points are, by convention, |
| * "mutators" that modify the instance in place (e.g. Array#sort!). |
| * |
| * Methods whose names end with an equals sign are attribute setters |
| * (e.g. Thread#critical=). |
| * --------------------------------------------------------------------- */ |
| |
| virtual int validIdentifier(String *s) { |
| char *c = Char(s); |
| while (*c) { |
| if ( !( isalnum(*c) || (*c == '_') || (*c == '?') || (*c == '!') || (*c == '=') ) ) return 0; |
| c++; |
| } |
| return 1; |
| } |
| |
| /* --------------------------------------------------------------------- |
| * trackType() |
| * |
| * Returns whether this type should be tracked. |
| * --------------------------------------------------------------------- */ |
| bool trackType(SwigType* aType) { |
| /* Get the base type */ |
| SwigType* baseType = SwigType_base(aType); |
| Node* classNode = classLookup(baseType); |
| |
| if (classNode && GetFlag(classNode, "feature:trackobjects")) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| /* --------------------------------------------------------------------- |
| * setTrackObjectsFlagForConvertPtr() |
| * |
| * Adds "|SWIG_TRACK_OBJECTS" flag to be passed to SWIG_ConvertPtr |
| * --------------------------------------------------------------------- */ |
| void setTrackObjectsFlagForConvertPtr(String* originalString) { |
| /* If feature:trackobjects is defined for a class and an object |
| * of that class is giving up ownership of the underlying C++ |
| * object, then we need to set the SWIG_TRACK_OBJECTS flag. |
| * This notifies the SWIG_ConvertPtr method so that it can |
| * appropriately reset the free function of the object.*/ |
| |
| Replaceall(originalString, "SWIG_POINTER_DISOWN", |
| "SWIG_POINTER_DISOWN | SWIG_TRACK_OBJECTS"); |
| } |
| |
| /* --------------------------------------------------------------------- |
| * setTrackObjectsFlagForNewPointer() |
| * |
| * Adds "|SWIG_TRACK_OBJECTS" flag to be passed to SWIG_NewPointer |
| * --------------------------------------------------------------------- */ |
| void setTrackObjectsFlagForNewPointer(String* originalString) { |
| /* If feature:trackobjects is defined for a class then |
| * we want to send a flag to the SWIG_NewPointerObj method. |
| * Unfortunately, this implementation is quite awful. |
| * We want to change code like this: |
| * |
| * SWIG_NewPointerObj((void *) result, SWIGTYPE_p_Foo,0); |
| * |
| * To this: |
| * |
| * SWIG_NewPointerObj((void *) result, SWIGTYPE_p_Foo,0|SWIG_TRACK_OBJECTS); |
| * |
| * A better implemenation would be to introduce a $track_objects |
| * marker, similar to how $disown and $owner now work. However, |
| * that would require changing all typemaps that currently |
| * call SWIG_NewPointerObj which did not seem like a good idea. |
| * |
| * The reason why passing a flag to SWIG_NewPointerObj is the best |
| * implemenation is that: |
| * - it already is aware of object tracking since it uses |
| * the SWIG_RubyInstanceFor method - thus this is more |
| * cohesive |
| * - it centers most object tracking code in SWIG_NewPointerObj and |
| * SWIG_ConvertPtr as opposed to scattering it all over the place. |
| * - it allows SWIG_NewPointerObj to be optimized so that |
| * SWIG_RubyInstanceFor is called only for objects that the |
| * user as marked to track */ |
| |
| /* Look for the string SWIG_NewPointerObj */ |
| char* start = Strstr(originalString, "SWIG_NewPointerObj"); |
| |
| if (start) { |
| /* Okay - found it. We now replace ); with "|SWIG_TRACK_OBJECTS);" |
| * Of course, we only want to replace the first occurence we see. |
| * Note this code is easily subverted if a user types in |
| * "SWIG_NewPointerObj(a,b) ; |
| * |
| * It would be best if we could call the replace method |
| * on start, but that does not work because replace only |
| * works on string objects (although the documenation |
| * implies otherwise.*/ |
| String* replaceString = NewString(start); |
| Replace(replaceString, ");", "|SWIG_TRACK_OBJECTS);", DOH_REPLACE_FIRST); |
| Replace(originalString, start, replaceString, DOH_REPLACE_FIRST); |
| } |
| } |
| |
| /* --------------------------------------------------------------------- |
| * functionWrapper() |
| * |
| * Create a function declaration and register it with the interpreter. |
| * --------------------------------------------------------------------- */ |
| |
| virtual int functionWrapper(Node *n) { |
| String *nodeType; |
| bool constructor; |
| bool destructor; |
| String *storage; |
| bool isVirtual; |
| |
| String *symname = Copy(Getattr(n,"sym:name")); |
| SwigType *t = Getattr(n,"type"); |
| ParmList *l = Getattr(n,"parms"); |
| Node *parent = Getattr(n,"parentNode"); |
| String *tm; |
| |
| int need_result = 0; |
| |
| /* Ruby needs no destructor wrapper */ |
| if (current == DESTRUCTOR) |
| return SWIG_NOWRAP; |
| |
| nodeType = Getattr(n, "nodeType"); |
| constructor = (!Cmp(nodeType, "constructor")); |
| destructor = (!Cmp(nodeType, "destructor")); |
| storage = Getattr(n, "storage"); |
| isVirtual = (Cmp(storage, "virtual") == 0); |
| |
| /* If the C++ class constructor is overloaded, we only want to |
| * write out the "new" singleton method once since it is always |
| * the same. (It's the "initialize" method that will handle the |
| * overloading). */ |
| |
| if (current == CONSTRUCTOR_ALLOCATE && |
| Swig_symbol_isoverloaded(n) && |
| Getattr(n, "sym:nextSibling") != 0) return SWIG_OK; |
| |
| String *overname = 0; |
| if (Getattr(n, "sym:overloaded")) { |
| overname = Getattr(n, "sym:overname"); |
| } else { |
| if (!addSymbol(symname, n)) |
| return SWIG_ERROR; |
| } |
| |
| String *cleanup = NewString(""); |
| String *outarg = NewString(""); |
| String *kwargs = NewString(""); |
| Wrapper *f = NewWrapper(); |
| |
| /* Rename predicate methods */ |
| if (GetFlag(n, "feature:predicate")) { |
| Append(symname, "?"); |
| } |
| |
| /* Determine the name of the SWIG wrapper function */ |
| String *wname = Swig_name_wrapper(symname); |
| if (overname && current != CONSTRUCTOR_ALLOCATE) { |
| Append(wname,overname); |
| } |
| |
| /* Emit arguments */ |
| if (current != CONSTRUCTOR_ALLOCATE) { |
| emit_args(t,l,f); |
| } |
| |
| /* Attach standard typemaps */ |
| if (current != CONSTRUCTOR_ALLOCATE) { |
| emit_attach_parmmaps(l, f); |
| } |
| Setattr(n, "wrap:parms", l); |
| |
| /* Get number of arguments */ |
| int numarg = emit_num_arguments(l); |
| int numreq = emit_num_required(l); |
| int varargs = emit_isvarargs(l); |
| bool allow_kwargs = GetFlag(n,"feature:kwargs") ? true : false; |
| |
| bool ctor_director = (current == CONSTRUCTOR_INITIALIZE && Swig_directorclass(n)); |
| int start = (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) ? 1 : 0; |
| |
| /* Now write the wrapper function itself */ |
| if (current == CONSTRUCTOR_ALLOCATE) { |
| Printf(f->def, "#ifdef HAVE_RB_DEFINE_ALLOC_FUNC\n"); |
| Printv(f->def, "static VALUE\n", wname, "(VALUE self) {", NIL); |
| Printf(f->def, "#else\n"); |
| Printv(f->def, "static VALUE\n", wname, "(int argc, VALUE *argv, VALUE self) {", NIL); |
| Printf(f->def, "#endif\n"); |
| } else if (current == CONSTRUCTOR_INITIALIZE) { |
| Printv(f->def, "static VALUE\n", wname, "(int argc, VALUE *argv, VALUE self) {", NIL); |
| if (!varargs) { |
| Printf(f->code,"if ((argc < %d) || (argc > %d))\n", numreq-start, numarg-start); |
| } else { |
| Printf(f->code,"if (argc < %d)\n", numreq-start); |
| } |
| Printf(f->code,"rb_raise(rb_eArgError, \"wrong # of arguments(%%d for %d)\",argc);\n",numreq-start); |
| } else { |
| Printv(f->def, "static VALUE\n", wname, "(int argc, VALUE *argv, VALUE self) {", NIL); |
| if (!varargs) { |
| Printf(f->code,"if ((argc < %d) || (argc > %d))\n", numreq-start, numarg-start); |
| } else { |
| Printf(f->code,"if (argc < %d)\n", numreq-start); |
| } |
| Printf(f->code,"rb_raise(rb_eArgError, \"wrong # of arguments(%%d for %d)\",argc);\n",numreq-start); |
| } |
| |
| /* Now walk the function parameter list and generate code */ |
| /* to get arguments */ |
| if (current != CONSTRUCTOR_ALLOCATE) { |
| marshalInputArgs(n, l, numarg, numreq, kwargs, allow_kwargs, f); |
| } |
| |
| // FIXME? |
| if (ctor_director) { |
| numarg--; |
| numreq--; |
| } |
| |
| /* Insert constraint checking code */ |
| insertConstraintCheckingCode(l, f); |
| |
| /* Insert cleanup code */ |
| insertCleanupCode(l, cleanup); |
| |
| /* Insert argument output code */ |
| insertArgOutputCode(l, outarg, need_result); |
| |
| /* if the object is a director, and the method call originated from its |
| * underlying python object, resolve the call by going up the c++ |
| * inheritance chain. otherwise try to resolve the method in python. |
| * without this check an infinite loop is set up between the director and |
| * shadow class method calls. |
| */ |
| |
| // NOTE: this code should only be inserted if this class is the |
| // base class of a director class. however, in general we haven't |
| // yet analyzed all classes derived from this one to see if they are |
| // directors. furthermore, this class may be used as the base of |
| // a director class defined in a completely different module at a |
| // later time, so this test must be included whether or not directorbase |
| // is true. we do skip this code if directors have not been enabled |
| // at the command line to preserve source-level compatibility with |
| // non-polymorphic swig. also, if this wrapper is for a smart-pointer |
| // method, there is no need to perform the test since the calling object |
| // (the smart-pointer) and the director object (the "pointee") are |
| // distinct. |
| |
| if (directorsEnabled()) { |
| if (!is_smart_pointer()) { |
| if (/*directorbase &&*/ !constructor && !destructor |
| && isVirtual && !Getattr(n,"feature:nodirector")) { |
| Wrapper_add_local(f, "director", "Swig::Director *director = 0"); |
| Printf(f->code, "director = dynamic_cast<Swig::Director *>(arg1);\n"); |
| Printf(f->code, "if (director && (director->swig_get_self() == self)) director->swig_set_up();\n"); |
| } |
| } |
| } |
| |
| /* Now write code to make the function call */ |
| if (current != CONSTRUCTOR_ALLOCATE) { |
| if (current == CONSTRUCTOR_INITIALIZE) { |
| String *action = Getattr(n,"wrap:action"); |
| if (action) { |
| Append(action,"DATA_PTR(self) = result;\n"); |
| |
| if (GetFlag(n,"feature:trackobjects")) { |
| Append(action,"SWIG_RubyAddTracking(result, self);\n"); |
| } |
| } |
| } |
| emit_action(n,f); |
| } |
| |
| /* Return value if necessary */ |
| if (SwigType_type(t) != T_VOID && current != CONSTRUCTOR_ALLOCATE && current != CONSTRUCTOR_INITIALIZE) { |
| need_result = 1; |
| if (GetFlag(n, "feature:predicate")) { |
| Printv(f->code, tab4, "vresult = (result ? Qtrue : Qfalse);\n", NIL); |
| } else { |
| tm = Swig_typemap_lookup_new("out",n,"result",0); |
| if (tm) { |
| Replaceall(tm,"$result","vresult"); |
| Replaceall(tm,"$source","result"); |
| Replaceall(tm,"$target","vresult"); |
| |
| if (GetFlag(n, "feature:new")) |
| Replaceall(tm,"$owner", "1"); |
| else |
| Replaceall(tm,"$owner", "0"); |
| |
| if (trackType(t)) { |
| setTrackObjectsFlagForNewPointer(tm); |
| } |
| |
| // FIXME: this will not try to unwrap directors returned as non-director |
| // base class pointers! |
| |
| /* New addition to unwrap director return values so that the original |
| * Ruby object is returned instead. |
| */ |
| bool unwrap = false; |
| String *decl = Getattr(n, "decl"); |
| int is_pointer = SwigType_ispointer_return(decl); |
| int is_reference = SwigType_isreference_return(decl); |
| if (is_pointer || is_reference) { |
| String *type = Getattr(n, "type"); |
| Node *modname = Getattr(parent, "module"); |
| Node *target = Swig_directormap(modname, type); |
| if (target) unwrap = true; |
| } |
| if (unwrap) { |
| Wrapper_add_local(f, "resultdirector", "Swig::Director *resultdirector = 0"); |
| Printf(f->code, "resultdirector = dynamic_cast<Swig::Director *>(result);\n"); |
| Printf(f->code, "if (resultdirector) {\n"); |
| Printf(f->code, " vresult = resultdirector->swig_get_self();\n"); |
| Printf(f->code, "} else {\n"); |
| Printf(f->code,"%s\n", tm); |
| Printf(f->code, "}\n"); |
| } else { |
| Printf(f->code,"%s\n", tm); |
| } |
| } else { |
| Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, |
| "Unable to use return type %s.\n", SwigType_str(t,0)); |
| } |
| } |
| } |
| |
| /* Extra code needed for new and initialize methods */ |
| if (current == CONSTRUCTOR_ALLOCATE) { |
| need_result = 1; |
| Printf(f->code, "VALUE vresult = SWIG_NewClassInstance(self, SWIGTYPE%s);\n", Char(SwigType_manglestr(t))); |
| Printf(f->code, "#ifndef HAVE_RB_DEFINE_ALLOC_FUNC\n"); |
| Printf(f->code, "rb_obj_call_init(vresult, argc, argv);\n"); |
| Printf(f->code, "#endif\n"); |
| } else if (current == CONSTRUCTOR_INITIALIZE) { |
| need_result = 1; |
| // Printf(f->code, "DATA_PTR(self) = result;\n"); |
| } |
| |
| /* Dump argument output code; */ |
| Printv(f->code,outarg,NIL); |
| |
| /* Dump the argument cleanup code */ |
| if (current != CONSTRUCTOR_ALLOCATE) |
| Printv(f->code,cleanup,NIL); |
| |
| /* Look for any remaining cleanup. This processes the %new directive */ |
| if (current != CONSTRUCTOR_ALLOCATE && GetFlag(n, "feature:new")) { |
| tm = Swig_typemap_lookup_new("newfree",n,"result",0); |
| if (tm) { |
| Replaceall(tm,"$source","result"); |
| Printv(f->code,tm, "\n",NIL); |
| } |
| } |
| |
| /* Special processing on return value. */ |
| tm = Swig_typemap_lookup_new("ret",n,"result",0); |
| if (tm) { |
| Replaceall(tm,"$source","result"); |
| Printv(f->code,tm, NIL); |
| } |
| |
| /* Wrap things up (in a manner of speaking) */ |
| if (need_result) { |
| if (current == CONSTRUCTOR_ALLOCATE) { |
| Printv(f->code, tab4, "return vresult;\n", NIL); |
| } else if (current == CONSTRUCTOR_INITIALIZE) { |
| Printv(f->code, tab4, "return self;\n", NIL); |
| } else { |
| Wrapper_add_local(f,"vresult","VALUE vresult = Qnil"); |
| Printv(f->code, tab4, "return vresult;\n", NIL); |
| } |
| } else { |
| Printv(f->code, tab4, "return Qnil;\n", NIL); |
| } |
| |
| /* Error handling code */ |
| /* |
| Printf(f->code,"fail:\n"); |
| Printv(f->code,cleanup,NIL); |
| Printv(f->code,"return Qnil;\n",NIL); |
| */ |
| Printf(f->code,"}\n"); |
| |
| /* Substitute the cleanup code */ |
| Replaceall(f->code,"$cleanup",cleanup); |
| |
| /* Emit the function */ |
| Wrapper_print(f, f_wrappers); |
| |
| /* Now register the function with the interpreter */ |
| if (!Swig_symbol_isoverloaded(n)) { |
| create_command(n, symname); |
| } else { |
| if (current == CONSTRUCTOR_ALLOCATE) { |
| create_command(n, symname); |
| } else { |
| Setattr(n, "wrap:name", wname); |
| if (!Getattr(n, "sym:nextSibling")) |
| dispatchFunction(n); |
| } |
| } |
| |
| Delete(kwargs); |
| Delete(cleanup); |
| Delete(outarg); |
| DelWrapper(f); |
| Delete(symname); |
| |
| return SWIG_OK; |
| } |
| |
| /* ------------------------------------------------------------ |
| * dispatchFunction() |
| * ------------------------------------------------------------ */ |
| |
| void dispatchFunction(Node *n) { |
| /* Last node in overloaded chain */ |
| |
| int maxargs; |
| String *tmp = NewString(""); |
| String *dispatch = Swig_overload_dispatch(n, "return %s(nargs, args, self);", &maxargs); |
| |
| /* Generate a dispatch wrapper for all overloaded functions */ |
| |
| Wrapper *f = NewWrapper(); |
| String *symname = Getattr(n, "sym:name"); |
| String *wname = Swig_name_wrapper(symname); |
| |
| Printv(f->def, |
| "static VALUE ", wname, |
| "(int nargs, VALUE *args, VALUE self) {", |
| NIL); |
| |
| Wrapper_add_local(f, "argc", "int argc"); |
| bool ctor_director = (current == CONSTRUCTOR_INITIALIZE && Swig_directorclass(n)); |
| if (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) { |
| Printf(tmp, "VALUE argv[%d]", maxargs+1); |
| } else { |
| Printf(tmp, "VALUE argv[%d]", maxargs); |
| } |
| Wrapper_add_local(f, "argv", tmp); |
| Wrapper_add_local(f, "ii", "int ii"); |
| |
| if (current == MEMBER_FUNC || current == MEMBER_VAR || ctor_director) { |
| Printf(f->code, "argc = nargs + 1;\n"); |
| Printf(f->code, "argv[0] = self;\n"); |
| Printf(f->code, "for (ii = 1; (ii < argc) && (ii < %d); ii++) {\n", maxargs); |
| Printf(f->code, "argv[ii] = args[ii-1];\n"); |
| Printf(f->code, "}\n"); |
| } else { |
| Printf(f->code, "argc = nargs;\n"); |
| Printf(f->code, "for (ii = 0; (ii < argc) && (ii < %d); ii++) {\n", maxargs); |
| Printf(f->code, "argv[ii] = args[ii];\n"); |
| Printf(f->code, "}\n"); |
| } |
| |
| Replaceall(dispatch, "$args", "nargs, args, self"); |
| Printv(f->code, dispatch, "\n", NIL); |
| Printf(f->code, "rb_raise(rb_eArgError, \"No matching function for overloaded '%s'\");\n", symname); |
| Printf(f->code,"return Qnil;\n"); |
| Printv(f->code, "}\n", NIL); |
| Wrapper_print(f, f_wrappers); |
| create_command(n, Char(symname)); |
| |
| DelWrapper(f); |
| Delete(dispatch); |
| Delete(tmp); |
| Delete(wname); |
| } |
| |
| /* --------------------------------------------------------------------- |
| * variableWrapper() |
| * --------------------------------------------------------------------- */ |
| |
| virtual int variableWrapper(Node *n) { |
| |
| char *name = GetChar(n,"name"); |
| char *iname = GetChar(n,"sym:name"); |
| SwigType *t = Getattr(n,"type"); |
| String *tm; |
| String *getfname, *setfname; |
| Wrapper *getf, *setf; |
| |
| getf = NewWrapper(); |
| setf = NewWrapper(); |
| |
| /* create getter */ |
| getfname = NewString(Swig_name_get(iname)); |
| Printv(getf->def, "static VALUE\n", getfname, "(", NIL); |
| Printf(getf->def, "VALUE self"); |
| Printf(getf->def, ") {"); |
| Wrapper_add_local(getf,"_val","VALUE _val"); |
| |
| tm = Swig_typemap_lookup_new("varout",n, name, 0); |
| if (tm) { |
| Replaceall(tm,"$result","_val"); |
| Replaceall(tm,"$target","_val"); |
| Replaceall(tm,"$source",name); |
| Printv(getf->code,tm, NIL); |
| } else { |
| Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, |
| "Unable to read variable of type %s\n", SwigType_str(t,0)); |
| } |
| Printv(getf->code, tab4, "return _val;\n}\n", NIL); |
| Wrapper_print(getf,f_wrappers); |
| |
| if (GetFlag(n,"feature:immutable")) { |
| setfname = NewString("NULL"); |
| } else { |
| /* create setter */ |
| setfname = NewString(Swig_name_set(iname)); |
| Printv(setf->def, "static VALUE\n", setfname, "(VALUE self, ", NIL); |
| Printf(setf->def, "VALUE _val) {"); |
| |
| tm = Swig_typemap_lookup_new("varin",n,name,0); |
| if (tm) { |
| Replaceall(tm,"$input","_val"); |
| Replaceall(tm,"$source","_val"); |
| Replaceall(tm,"$target",name); |
| Printv(setf->code,tm,"\n",NIL); |
| } else { |
| Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, |
| "Unable to set variable of type %s\n", SwigType_str(t,0)); |
| } |
| Printv(setf->code, tab4, "return _val;\n",NIL); |
| Printf(setf->code,"}\n"); |
| Wrapper_print(setf,f_wrappers); |
| } |
| |
| /* define accessor method */ |
| if (CPlusPlus) { |
| Insert(getfname,0,"VALUEFUNC("); |
| Append(getfname,")"); |
| Insert(setfname,0,"VALUEFUNC("); |
| Append(setfname,")"); |
| } |
| |
| String *s = NewString(""); |
| switch (current) { |
| case STATIC_VAR: |
| /* C++ class variable */ |
| Printv(s, |
| tab4, "rb_define_singleton_method(", klass->vname, ", \"", |
| klass->strip(iname), "\", ", getfname, ", 0);\n", |
| NIL); |
| if (!GetFlag(n,"feature:immutable")) { |
| Printv(s, |
| tab4, "rb_define_singleton_method(", klass->vname, ", \"", |
| klass->strip(iname), "=\", ", setfname, ", 1);\n", |
| NIL); |
| } |
| Printv(klass->init,s,NIL); |
| break; |
| default: |
| /* C global variable */ |
| /* wrapped in Ruby module attribute */ |
| assert(current == NO_CPP); |
| if (!useGlobalModule) { |
| Printv(s, |
| tab4, "rb_define_singleton_method(", modvar, ", \"", |
| iname, "\", ", getfname, ", 0);\n", |
| NIL); |
| if (!GetFlag(n,"feature:immutable")) { |
| Printv(s, |
| tab4, "rb_define_singleton_method(", modvar, ", \"", |
| iname, "=\", ", setfname, ", 1);\n", |
| NIL); |
| } |
| } else { |
| Printv(s, |
| tab4, "rb_define_global_method(\"", |
| iname, "\", ", getfname, ", 0);\n", |
| NIL); |
| if (!GetFlag(n,"feature:immutable")) { |
| Printv(s, |
| tab4, "rb_define_global_method(\"", |
| iname, "=\", ", setfname, ", 1);\n", |
| NIL); |
| } |
| } |
| Printv(f_init,s,NIL); |
| Delete(s); |
| break; |
| } |
| Delete(getfname); |
| Delete(setfname); |
| DelWrapper(setf); |
| DelWrapper(getf); |
| return SWIG_OK; |
| } |
| |
| |
| /* --------------------------------------------------------------------- |
| * validate_const_name(char *name) |
| * |
| * Validate constant name. |
| * --------------------------------------------------------------------- */ |
| |
| char * |
| validate_const_name(char *name, const char *reason) { |
| if (!name || name[0] == '\0') |
| return name; |
| |
| if (isupper(name[0])) |
| return name; |
| |
| if (islower(name[0])) { |
| name[0] = toupper(name[0]); |
| Swig_warning(WARN_RUBY_WRONG_NAME, input_file, line_number, |
| "Wrong %s name (corrected to `%s')\n", reason, name); |
| return name; |
| } |
| |
| Swig_warning(WARN_RUBY_WRONG_NAME, input_file, line_number, |
| "Wrong %s name %s\n", reason, name); |
| |
| return name; |
| } |
| |
| /* --------------------------------------------------------------------- |
| * constantWrapper() |
| * --------------------------------------------------------------------- */ |
| |
| virtual int constantWrapper(Node *n) { |
| Swig_require("constantWrapper",n, "*sym:name", "type", "value", NIL); |
| |
| char *iname = GetChar(n,"sym:name"); |
| SwigType *type = Getattr(n,"type"); |
| String *rawval = Getattr(n,"rawval"); |
| String *value = rawval ? rawval : Getattr(n,"value"); |
| |
| if (current == CLASS_CONST) { |
| iname = klass->strip(iname); |
| } |
| validate_const_name(iname, "constant"); |
| SetChar(n, "sym:name", iname); |
| |
| /* Special hook for member pointer */ |
| if (SwigType_type(type) == T_MPOINTER) { |
| String *wname = Swig_name_wrapper(iname); |
| Printf(f_header, "static %s = %s;\n", SwigType_str(type, wname), value); |
| value = Char(wname); |
| } |
| String *tm = Swig_typemap_lookup_new("constant", n, value, 0); |
| if (tm) { |
| Replaceall(tm, "$source", value); |
| Replaceall(tm, "$target", iname); |
| Replaceall(tm, "$symname", iname); |
| Replaceall(tm, "$value", value); |
| if (current == CLASS_CONST) { |
| if (multipleInheritance) { |
| Replaceall(tm, "$module", klass->mImpl); |
| Printv(klass->init, tm, "\n", NIL); |
| } else { |
| Replaceall(tm, "$module", klass->vname); |
| Printv(klass->init, tm, "\n", NIL); |
| } |
| } else { |
| if (!useGlobalModule) { |
| Replaceall(tm, "$module", modvar); |
| } else { |
| Replaceall(tm, "$module", "rb_cObject"); |
| } |
| 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; |
| } |
| |
| /* ----------------------------------------------------------------------------- |
| * classDeclaration() |
| * |
| * Records information about classes---even classes that might be defined in |
| * other modules referenced by %import. |
| * ----------------------------------------------------------------------------- */ |
| |
| virtual int classDeclaration(Node *n) { |
| if (!Getattr(n,"feature:onlychildren")) { |
| String *name = Getattr(n,"name"); |
| String *symname = Getattr(n,"sym:name"); |
| String *tdname = Getattr(n,"tdname"); |
| |
| name = tdname ? tdname : name; |
| String *namestr = SwigType_namestr(name); |
| klass = RCLASS(classes, Char(namestr)); |
| if (!klass) { |
| klass = new RClass(); |
| String *valid_name = NewString(symname ? symname : namestr); |
| validate_const_name(Char(valid_name), "class"); |
| klass->set_name(namestr, symname, valid_name); |
| SET_RCLASS(classes, Char(namestr), klass); |
| Delete(valid_name); |
| } |
| Delete(namestr); |
| } |
| return Language::classDeclaration(n); |
| } |
| |
| /** |
| * Process the comma-separated list of mixed-in module names (if any). |
| */ |
| void includeRubyModules(Node *n) { |
| String *mixin = Getattr(n,"feature:mixin"); |
| if (mixin) { |
| List *modules = Split(mixin,',',INT_MAX); |
| if (modules && Len(modules) > 0) { |
| Iterator mod = First(modules); |
| while (mod.item) { |
| if (Len(mod.item) > 0) { |
| Printf(klass->init, "rb_include_module(%s, rb_eval_string(\"%s\"));\n", klass->vname, mod.item); |
| } |
| mod = Next(mod); |
| } |
| } |
| Delete(modules); |
| } |
| } |
| |
| void handleBaseClasses(Node *n) { |
| List *baselist = Getattr(n,"bases"); |
| if (baselist && Len(baselist)) { |
| Iterator base = First(baselist); |
| while(base.item && GetFlag(base.item,"feature:ignore")) { |
| base = Next(base); |
| } |
| while (base.item) { |
| String *basename = Getattr(base.item,"name"); |
| String *basenamestr = SwigType_namestr(basename); |
| RClass *super = RCLASS(classes, Char(basenamestr)); |
| Delete(basenamestr); |
| if (super) { |
| SwigType *btype = NewString(basename); |
| SwigType_add_pointer(btype); |
| SwigType_remember(btype); |
| if (multipleInheritance) { |
| String *bmangle = SwigType_manglestr(btype); |
| Insert(bmangle,0,"((swig_class *) SWIGTYPE"); |
| Append(bmangle,"->clientdata)->mImpl"); |
| Printv(klass->init, "rb_include_module(", klass->mImpl, ", ", bmangle, ");\n", NIL); |
| Delete(bmangle); |
| } else { |
| String *bmangle = SwigType_manglestr(btype); |
| Insert(bmangle,0,"((swig_class *) SWIGTYPE"); |
| Append(bmangle,"->clientdata)->klass"); |
| Replaceall(klass->init,"$super",bmangle); |
| Delete(bmangle); |
| } |
| Delete(btype); |
| } |
| base = Next(base); |
| while(base.item && GetFlag(base.item,"feature:ignore")) { |
| base = Next(base); |
| } |
| if (!multipleInheritance) { |
| /* Warn about multiple inheritance for additional base class(es) */ |
| while (base.item) { |
| if (GetFlag(base.item,"feature:ignore")) { |
| base = Next(base); |
| continue; |
| } |
| String *proxyclassname = SwigType_str(Getattr(n,"classtypeobj"),0); |
| String *baseclassname = SwigType_str(Getattr(base.item,"name"),0); |
| Swig_warning(WARN_RUBY_MULTIPLE_INHERITANCE, input_file, line_number, |
| "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Ruby.\n", proxyclassname, baseclassname); |
| base = Next(base); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Check to see if a %markfunc was specified. |
| */ |
| void handleMarkFuncDirective(Node *n) { |
| String *markfunc = Getattr(n, "feature:markfunc"); |
| if (markfunc) { |
| Printf(klass->init, "c%s.mark = (void (*)(void *)) %s;\n", klass->name, markfunc); |
| } else { |
| Printf(klass->init, "c%s.mark = 0;\n", klass->name); |
| } |
| } |
| |
| /** |
| * Check to see if a %freefunc was specified. |
| */ |
| void handleFreeFuncDirective(Node *n) { |
| String *freefunc = Getattr(n, "feature:freefunc"); |
| if (freefunc) { |
| Printf(klass->init, "c%s.destroy = (void (*)(void *)) %s;\n", klass->name, freefunc); |
| } else { |
| if (klass->destructor_defined) { |
| Printf(klass->init, "c%s.destroy = (void (*)(void *)) free_%s;\n", klass->name, klass->mname); |
| } |
| } |
| } |
| |
| /* ---------------------------------------------------------------------- |
| * classHandler() |
| * ---------------------------------------------------------------------- */ |
| |
| virtual int classHandler(Node *n) { |
| |
| String *name = Getattr(n,"name"); |
| String *symname = Getattr(n,"sym:name"); |
| String *namestr = SwigType_namestr(name); // does template expansion |
| |
| klass = RCLASS(classes, Char(namestr)); |
| assert(klass != 0); |
| Delete(namestr); |
| String *valid_name = NewString(symname); |
| validate_const_name(Char(valid_name), "class"); |
| |
| Clear(klass->type); |
| Printv(klass->type, Getattr(n,"classtype"), NIL); |
| Printv(f_wrappers, "swig_class c", valid_name, ";\n\n", NIL); |
| Printv(klass->init, "\n", tab4, NIL); |
| if (multipleInheritance) { |
| if (!useGlobalModule) { |
| Printv(klass->init, klass->vname, " = rb_define_class_under(", modvar, |
| ", \"", klass->name, "\", rb_cObject);\n", NIL); |
| } else { |
| Printv(klass->init, klass->vname, " = rb_define_class(\"", |
| klass->name, "\", rb_cObject);\n", NIL); |
| } |
| Printv(klass->init, klass->mImpl, " = rb_define_module_under(", klass->vname, ", \"Impl\");\n", NIL); |
| } else { |
| if (!useGlobalModule) { |
| Printv(klass->init, klass->vname, " = rb_define_class_under(", modvar, |
| ", \"", klass->name, "\", $super);\n", NIL); |
| } else { |
| Printv(klass->init, klass->vname, " = rb_define_class(\"", |
| klass->name, "\", $super);\n", NIL); |
| } |
| } |
| |
| SwigType *tt = NewString(name); |
| SwigType_add_pointer(tt); |
| SwigType_remember(tt); |
| String *tm = SwigType_manglestr(tt); |
| Printf(klass->init, "SWIG_TypeClientData(SWIGTYPE%s, (void *) &c%s);\n", tm, valid_name); |
| Delete(tm); |
| Delete(tt); |
| Delete(valid_name); |
| |
| includeRubyModules(n); |
| |
| Printv(klass->init, "$allocator",NIL); |
| Printv(klass->init, "$initializer",NIL); |
| |
| Language::classHandler(n); |
| |
| handleBaseClasses(n); |
| handleMarkFuncDirective(n); |
| handleFreeFuncDirective(n); |
| |
| if (multipleInheritance) { |
| Printv(klass->init, "rb_include_module(", klass->vname, ", ", klass->mImpl, ");\n", NIL); |
| } |
| |
| String *s = NewString(""); |
| Printv(s, tab4, "rb_undef_alloc_func(", klass->vname, ");\n", NIL); |
| Replaceall(klass->init,"$allocator", s); |
| Replaceall(klass->init,"$initializer", ""); |
| Replaceall(klass->init,"$super", "rb_cObject"); |
| Delete(s); |
| |
| Printv(f_init,klass->init,NIL); |
| klass = 0; |
| return SWIG_OK; |
| } |
| |
| /* ---------------------------------------------------------------------- |
| * memberfunctionHandler() |
| * |
| * Method for adding C++ member function |
| * |
| * By default, we're going to create a function of the form : |
| * |
| * Foo_bar(this,args) |
| * |
| * Where Foo is the classname, bar is the member name and the this pointer |
| * is explicitly attached to the beginning. |
| * |
| * The renaming only applies to the member function part, not the full |
| * classname. |
| * |
| * --------------------------------------------------------------------- */ |
| |
| virtual int memberfunctionHandler(Node *n) { |
| current = MEMBER_FUNC; |
| Language::memberfunctionHandler(n); |
| current = NO_CPP; |
| return SWIG_OK; |
| } |
| |
| /* --------------------------------------------------------------------- |
| * constructorHandler() |
| * |
| * Method for adding C++ member constructor |
| * -------------------------------------------------------------------- */ |
| |
| void set_director_ctor_code(Node *n) |
| { |
| /* director ctor code is specific for each class */ |
| Delete(director_prot_ctor_code); |
| director_prot_ctor_code = NewString(""); |
| Node *pn = Swig_methodclass(n); |
| String *symname = Getattr(pn,"sym:name"); |
| String *name = Copy(symname); |
| char *cname = Char(name); |
| if(cname) cname[0] = toupper(cname[0]); |
| Printv(director_prot_ctor_code, |
| "char *classname = \"",module,"::",cname,"\";\n", |
| "if ( $comparison ) { /* subclassed */\n", |
| " $director_new \n", |
| "} else {\n", |
| " rb_raise(rb_eNameError,\"accessing abstract class or protected constructor\"); \n", |
| " return Qnil;\n", |
| "}\n", NIL); |
| Delete(director_ctor_code); |
| director_ctor_code = NewString(""); |
| Printv(director_ctor_code, |
| "char *classname = \"",module,"::",cname,"\";\n", |
| "if ( $comparison ) { /* subclassed */\n", |
| " $director_new \n", |
| "} else {\n", |
| " $nondirector_new \n", |
| "}\n", NIL); |
| Delete(name); |
| } |
| |
| virtual int constructorHandler(Node *n) { |
| int use_director = Swig_directorclass(n); |
| if (use_director) { |
| set_director_ctor_code(n); |
| } |
| |
| /* First wrap the allocate method */ |
| current = CONSTRUCTOR_ALLOCATE; |
| Swig_name_register((String_or_char *) "construct", (String_or_char *) "%c_allocate"); |
| |
| |
| Language::constructorHandler(n); |
| |
| /* |
| * If we're wrapping the constructor of a C++ director class, prepend a new parameter |
| * to receive the scripting language object (e.g. 'self') |
| * |
| */ |
| Swig_save("ruby:constructorHandler",n,"parms",NIL); |
| if (use_director) { |
| Parm *parms = Getattr(n, "parms"); |
| Parm *self; |
| String *name = NewString("self"); |
| String *type = NewString("VALUE"); |
| self = NewParm(type, name); |
| Delete(type); |
| Delete(name); |
| Setattr(self, "lname", "Qnil"); |
| if (parms) set_nextSibling(self, parms); |
| Setattr(n, "parms", self); |
| Setattr(n, "wrap:self", "1"); |
| Delete(self); |
| } |
| |
| /* Now do the instance initialize method */ |
| current = CONSTRUCTOR_INITIALIZE; |
| Swig_name_register((String_or_char *) "construct", (String_or_char *) "new_%c"); |
| Language::constructorHandler(n); |
| |
| /* Restore original parameter list */ |
| Delattr(n, "wrap:self"); |
| Swig_restore(n); |
| |
| /* Done */ |
| Swig_name_unregister((String_or_char *) "construct"); |
| current = NO_CPP; |
| klass->constructor_defined = 1; |
| return SWIG_OK; |
| } |
| |
| virtual int copyconstructorHandler(Node *n) { |
| int use_director = Swig_directorclass(n); |
| if (use_director) { |
| set_director_ctor_code(n); |
| } |
| |
| /* First wrap the allocate method */ |
| current = CONSTRUCTOR_ALLOCATE; |
| Swig_name_register((String_or_char *) "construct", (String_or_char *) "%c_allocate"); |
| |
| return Language::copyconstructorHandler(n); |
| } |
| |
| |
| /* --------------------------------------------------------------------- |
| * destructorHandler() |
| * -------------------------------------------------------------------- */ |
| |
| virtual int destructorHandler(Node *n) { |
| current = DESTRUCTOR; |
| Language::destructorHandler(n); |
| |
| String *freefunc = NewString(""); |
| String *freebody = NewString(""); |
| |
| Printv(freefunc, "free_", klass->mname, NIL); |
| Printv(freebody, "static void\n", |
| freefunc, "(", klass->type, " *", Swig_cparm_name(0,0), ") {\n", |
| tab4, NIL); |
| |
| if (Extend) { |
| String *wrap = Getattr(n, "wrap:code"); |
| if (wrap) { |
| Printv(f_wrappers, wrap, NIL); |
| } |
| /* Printv(freebody, Swig_name_destroy(name), "(", Swig_cparm_name(0,0), ")", NIL); */ |
| Printv(freebody,Getattr(n,"wrap:action"), NIL); |
| } else { |
| String *action = Getattr(n,"wrap:action"); |
| if (action) { |
| Printv(freebody, action, NIL); |
| } else { |
| /* In the case swig emits no destroy function. */ |
| if (CPlusPlus) |
| Printf(freebody, "delete %s;\n", Swig_cparm_name(0,0)); |
| else |
| Printf(freebody, "free((char*) %s);\n", Swig_cparm_name(0,0)); |
| } |
| } |
| |
| if (GetFlag(n,"feature:trackobjects")) { |
| Printf(freebody, " SWIG_RubyRemoveTracking(%s);\n", Swig_cparm_name(0,0)); |
| } |
| Printv(freebody, "}\n\n", NIL); |
| |
| Printv(f_wrappers, freebody, NIL); |
| |
| klass->destructor_defined = 1; |
| current = NO_CPP; |
| Delete(freefunc); |
| Delete(freebody); |
| return SWIG_OK; |
| } |
| |
| /* --------------------------------------------------------------------- |
| * membervariableHandler() |
| * |
| * This creates a pair of functions to set/get the variable of a member. |
| * -------------------------------------------------------------------- */ |
| |
| virtual int membervariableHandler(Node *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; |
| Language::memberconstantHandler(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; |
| } |
| |
| /* C++ director class generation */ |
| virtual int classDirector(Node *n) { |
| return Language::classDirector(n); |
| } |
| |
| virtual int classDirectorInit(Node *n) { |
| String *declaration; |
| 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); |
| return Language::classDirectorInit(n); |
| } |
| |
| virtual int classDirectorEnd(Node *n) { |
| Printf(f_directors_h, "};\n\n"); |
| return Language::classDirectorEnd(n); |
| } |
| |
| /* ------------------------------------------------------------ |
| * classDirectorConstructor() |
| * ------------------------------------------------------------ */ |
| |
| virtual int classDirectorConstructor(Node *n) { |
| Node *parent = Getattr(n, "parentNode"); |
| String *sub = NewString(""); |
| String *decl = Getattr(n, "decl"); |
| String *supername = Swig_class_name(parent); |
| String *classname = NewString(""); |
| Printf(classname, "SwigDirector_%s", supername); |
| |
| /* insert self parameter */ |
| Parm *p; |
| ParmList *superparms = Getattr(n, "parms"); |
| ParmList *parms = CopyParmList(superparms); |
| String *type = NewString("VALUE"); |
| p = NewParm(type, NewString("self")); |
| set_nextSibling(p, parms); |
| parms = p; |
| |
| if (!Getattr(n,"defaultargs")) { |
| /* constructor */ |
| { |
| Wrapper *w = NewWrapper(); |
| String *call; |
| String *basetype = Getattr(parent, "classtype"); |
| String *target = Swig_method_decl(decl, classname, parms, 0, 0); |
| call = Swig_csuperclass_call(0, basetype, superparms); |
| Printf(w->def, "%s::%s: %s, Swig::Director(self) { }", classname, target, call); |
| Delete(target); |
| Wrapper_print(w, f_directors); |
| Delete(call); |
| DelWrapper(w); |
| } |
| |
| /* constructor header */ |
| { |
| String *target = Swig_method_decl(decl, classname, parms, 0, 1); |
| Printf(f_directors_h, " %s;\n", target); |
| Delete(target); |
| } |
| } |
| |
| Delete(sub); |
| Delete(classname); |
| Delete(supername); |
| Delete(parms); |
| return Language::classDirectorConstructor(n); |
| } |
| |
| /* ------------------------------------------------------------ |
| * classDirectorDefaultConstructor() |
| * ------------------------------------------------------------ */ |
| |
| virtual int classDirectorDefaultConstructor(Node *n) { |
| String *classname; |
| Wrapper *w; |
| classname = Swig_class_name(n); |
| w = NewWrapper(); |
| Printf(w->def, "SwigDirector_%s::SwigDirector_%s(VALUE self) : Swig::Director(self) { }", classname, classname); |
| Wrapper_print(w, f_directors); |
| DelWrapper(w); |
| Printf(f_directors_h, " SwigDirector_%s(VALUE self);\n", classname); |
| Delete(classname); |
| return Language::classDirectorDefaultConstructor(n); |
| } |
| |
| /* --------------------------------------------------------------- |
| * exceptionSafeMethodCall() |
| * |
| * Emit a virtual director method to pass a method call on to the |
| * underlying Ruby instance. |
| * |
| * --------------------------------------------------------------- */ |
| |
| void exceptionSafeMethodCall(String *className, Node *n, Wrapper *w, int argc, String *args) { |
| |
| Wrapper *body = NewWrapper(); |
| Wrapper *rescue = NewWrapper(); |
| |
| String *methodName = Getattr(n, "sym:name"); |
| String *bodyName = NewStringf("%s_%s_body", className, methodName); |
| String *rescueName = NewStringf("%s_%s_rescue", className, methodName); |
| String *depthCountName = NewStringf("%s_%s_call_depth", className, methodName); |
| |
| // Check for an exception typemap of some kind |
| String *tm = Swig_typemap_lookup_new("director:except", n, "result", 0); |
| if (!tm) { |
| tm = Getattr(n, "feature:director:except"); |
| } |
| |
| if ((tm != 0) && (Len(tm) > 0) && (Strcmp(tm, "1") != 0)) |
| { |
| // Declare a global to hold the depth count |
| Printf(f_directors, "static int %s = 0;\n", depthCountName); |
| |
| // Function body |
| Printf(body->def, "VALUE %s(VALUE data) {\n", bodyName); |
| Wrapper_add_localv(body, "args", "Swig::body_args *", "args", "= reinterpret_cast<Swig::body_args *>(data)", NIL); |
| Wrapper_add_localv(body, "result", "VALUE", "result", "= Qnil", NIL); |
| Printf(body->code, "%s++;\n", depthCountName, NIL); |
| Printv(body->code, "result = rb_funcall2(args->recv, args->id, args->argc, args->argv);\n", NIL); |
| Printf(body->code, "%s--;\n", depthCountName, NIL); |
| Printv(body->code, "return result;\n", NIL); |
| Printv(body->code, "}", NIL); |
| |
| // Exception handler |
| Printf(rescue->def, "VALUE %s(VALUE args, VALUE error) {\n", rescueName); |
| Replaceall(tm, "$error", "error"); |
| Printf(rescue->code, "if (%s == 1) ", depthCountName); |
| Printv(rescue->code, Str(tm), "\n", NIL); |
| Printf(rescue->code, "%s--;\n", depthCountName); |
| Printv(rescue->code, "rb_exc_raise(error);\n", NIL); |
| Printv(rescue->code, "}", NIL); |
| |
| // Main code |
| Wrapper_add_localv(w, "args", "Swig::body_args", "args", NIL); |
| Wrapper_add_localv(w, "status", "int", "status", NIL); |
| Printv(w->code, "args.recv = swig_get_self();\n", NIL); |
| Printf(w->code, "args.id = rb_intern(\"%s\");\n", methodName); |
| Printf(w->code, "args.argc = %d;\n", argc); |
| if (argc > 0) { |
| Wrapper_add_localv(w, "i", "int", "i", NIL); |
| Printf(w->code, "args.argv = new VALUE[%d];\n", argc); |
| for (int i = 0; i < argc; i++) { |
| Printf(w->code, "args.argv[%d] = obj%d;\n", i, i); |
| } |
| } else { |
| Printv(w->code, "args.argv = 0;\n", NIL); |
| } |
| Printf(w->code, |
| "result = rb_protect(PROTECTFUNC(%s), reinterpret_cast<VALUE>(&args), &status);\n", bodyName, rescueName); |
| Printf(w->code, |
| "if (status) {\n"); |
| Printf(w->code, |
| "VALUE lastErr = rb_gv_get(\"$!\");\n"); |
| Printf(w->code, |
| "%s(reinterpret_cast<VALUE>(&args), lastErr);\n", rescueName); |
| Printf(w->code, "}\n"); |
| if (argc > 0) { |
| Printv(w->code, "delete [] args.argv;\n", NIL); |
| } |
| |
| // Dump wrapper code |
| Wrapper_print(body, f_directors); |
| Wrapper_print(rescue, f_directors); |
| } |
| else |
| { |
| if (argc > 0) { |
| Printf(w->code, "result = rb_funcall(swig_get_self(), rb_intern(\"%s\"), %d%s);\n", methodName, argc, args); |
| } else { |
| Printf(w->code, "result = rb_funcall(swig_get_self(), rb_intern(\"%s\"), 0, NULL);\n", methodName); |
| } |
| } |
| |
| // Clean up |
| Delete(bodyName); |
| Delete(rescueName); |
| Delete(depthCountName); |
| DelWrapper(body); |
| DelWrapper(rescue); |
| } |
| |
| virtual int classDirectorMethod(Node *n, Node *parent, String *super) { |
| int is_void = 0; |
| int is_pointer = 0; |
| String *decl; |
| String *type; |
| String *name; |
| String *classname; |
| String *declaration; |
| ParmList *l; |
| Wrapper *w; |
| String *tm; |
| String *wrap_args; |
| String *return_type; |
| Parm* p; |
| String *value = Getattr(n, "value"); |
| String *storage = Getattr(n,"storage"); |
| bool pure_virtual = false; |
| int status = SWIG_OK; |
| int idx; |
| |
| if (Cmp(storage,"virtual") == 0) { |
| if (Cmp(value,"0") == 0) { |
| pure_virtual = true; |
| } |
| } |
| |
| classname = Getattr(parent, "sym:name"); |
| type = Getattr(n, "type"); |
| name = Getattr(n, "name"); |
| |
| w = NewWrapper(); |
| declaration = NewString(""); |
| |
| /* determine if the method returns a pointer */ |
| decl = Getattr(n, "decl"); |
| is_pointer = SwigType_ispointer_return(decl); |
| is_void = (!Cmp(type, "void") && !is_pointer); |
| |
| /* form complete return type */ |
| return_type = Copy(type); |
| { |
| SwigType *t = Copy(decl); |
| SwigType *f = 0; |
| f = SwigType_pop_function(t); |
| SwigType_push(return_type, t); |
| Delete(f); |
| Delete(t); |
| } |
| |
| /* virtual method definition */ |
| l = Getattr(n, "parms"); |
| String *target; |
| String *pclassname = NewStringf("SwigDirector_%s", classname); |
| String *qualified_name = NewStringf("%s::%s", pclassname, name); |
| target = Swig_method_decl(decl, qualified_name, l, 0, 0); |
| String *rtype = SwigType_str(type, 0); |
| Printf(w->def, "%s %s", rtype, target); |
| Delete(qualified_name); |
| Delete(target); |
| /* header declaration */ |
| target = Swig_method_decl(decl, name, l, 0, 1); |
| Printf(declaration, " virtual %s %s", rtype, target); |
| Delete(target); |
| |
| // Get any exception classes in the throws typemap |
| 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 ((tm = Getattr(p,"tmap:throws"))) { |
| if (gencomma++) { |
| Append(w->def, ", "); |
| Append(declaration, ", "); |
| } |
| |
| Printf(w->def, "%s", SwigType_str(Getattr(p, "type"),0)); |
| Printf(declaration, "%s", SwigType_str(Getattr(p, "type"),0)); |
| } |
| } |
| |
| Append(w->def, ")"); |
| Append(declaration, ")"); |
| } |
| |
| Append(w->def, " {"); |
| Append(declaration, ";\n"); |
| |
| |
| /* attach typemaps to arguments (C/C++ -> Ruby) */ |
| String *arglist = NewString(""); |
| |
| |
| /** |
| * For each parameter to the C++ member function, copy the parameter name |
| * to its "lname"; this ensures that Swig_typemap_attach_parms() will do |
| * the right thing when it sees strings like "$1" in your "directorin" typemaps. |
| * Not sure if it's OK to leave it like this, but seems OK so far. |
| */ |
| typemap_copy_pname_to_lname(l); |
| |
| Swig_typemap_attach_parms("in", l, 0); |
| Swig_typemap_attach_parms("directorin", l, 0); |
| Swig_typemap_attach_parms("directorargout", l, w); |
| |
| int num_arguments = emit_num_arguments(l); |
| int i; |
| char source[256]; |
| |
| wrap_args = NewString(""); |
| int outputs = 0; |
| if (!is_void) outputs++; |
| |
| /* build argument list and type conversion string */ |
| for (i=0, idx=0, p = l; i < num_arguments; i++) { |
| |
| while (Getattr(p, "tmap:ignore")) { |
| p = Getattr(p, "tmap:ignore:next"); |
| } |
| |
| if (Getattr(p, "tmap:directorargout") != 0) outputs++; |
| |
| String* parameterName = Getattr(p, "name"); |
| String* parameterType = Getattr(p, "type"); |
| |
| Putc(',',arglist); |
| if ((tm = Getattr(p, "tmap:directorin")) != 0) { |
| sprintf(source, "obj%d", idx++); |
| Replaceall(tm, "$input", source); |
| Replaceall(tm, "$owner", "0"); |
| Printv(wrap_args, tm, "\n", NIL); |
| Wrapper_add_localv(w, source, "VALUE", source, "= Qnil", NIL); |
| Printv(arglist, source, NIL); |
| p = Getattr(p, "tmap:directorin:next"); |
| continue; |
| } else if (Cmp(parameterType, "void")) { |
| /** |
| * Special handling for pointers to other C++ director classes. |
| * Ideally this would be left to a typemap, but there is currently no |
| * way to selectively apply the dynamic_cast<> to classes that have |
| * directors. In other words, the type "SwigDirector_$1_lname" only exists |
| * for classes with directors. We avoid the problem here by checking |
| * module.wrap::directormap, but it's not clear how to get a typemap to |
| * do something similar. Perhaps a new default typemap (in addition |
| * to SWIGTYPE) called DIRECTORTYPE? |
| */ |
| if (SwigType_ispointer(parameterType) || SwigType_isreference(parameterType)) { |
| Node *modname = Getattr(parent, "module"); |
| Node *target = Swig_directormap(modname, parameterType); |
| sprintf(source, "obj%d", idx++); |
| String *nonconst = 0; |
| /* strip pointer/reference --- should move to Swig/stype.c */ |
| String *nptype = NewString(Char(parameterType)+2); |
| /* name as pointer */ |
| String *ppname = Copy(parameterName); |
| if (SwigType_isreference(parameterType)) { |
| Insert(ppname,0,"&"); |
| } |
| /* if necessary, cast away const since Ruby doesn't support it! */ |
| if (SwigType_isconst(nptype)) { |
| nonconst = NewStringf("nc_tmp_%s", parameterName); |
| String *nonconst_i = NewStringf("= const_cast<%s>(%s)", SwigType_lstr(parameterType, 0), ppname); |
| Wrapper_add_localv(w, nonconst, SwigType_lstr(parameterType, 0), nonconst, nonconst_i, NIL); |
| Delete(nonconst_i); |
| Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number, |
| "Target language argument '%s' discards const in director method %s::%s.\n", SwigType_str(parameterType, parameterName), classname, name); |
| } else { |
| nonconst = Copy(ppname); |
| } |
| Delete(nptype); |
| Delete(ppname); |
| String *mangle = SwigType_manglestr(parameterType); |
| if (target) { |
| String *director = NewStringf("director_%s", mangle); |
| Wrapper_add_localv(w, director, "Swig::Director *", director, "= 0", NIL); |
| Wrapper_add_localv(w, source, "VALUE", source, "= Qnil", NIL); |
| Printf(wrap_args, "%s = dynamic_cast<Swig::Director *>(%s);\n", director, nonconst); |
| Printf(wrap_args, "if (!%s) {\n", director); |
| Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); |
| Printf(wrap_args, "} else {\n"); |
| Printf(wrap_args, "%s = %s->swig_get_self();\n", source, director); |
| Printf(wrap_args, "}\n"); |
| Delete(director); |
| Printv(arglist, source, NIL); |
| } else { |
| Wrapper_add_localv(w, source, "VALUE", source, "= Qnil", NIL); |
| Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", |
| source, nonconst, mangle); |
| //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n", |
| // source, nonconst, base); |
| Printv(arglist, source, NIL); |
| } |
| Delete(mangle); |
| Delete(nonconst); |
| } else { |
| 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(parameterType, 0), classname, name); |
| status = SWIG_NOWRAP; |
| break; |
| } |
| } |
| p = nextSibling(p); |
| } |
| |
| /* declare method return value |
| * if the return value is a reference or const reference, a specialized typemap must |
| * handle it, including declaration of c_result ($result). |
| */ |
| if (!is_void) { |
| Wrapper_add_localv(w, "c_result", SwigType_lstr(return_type, "c_result"), NIL); |
| } |
| /* declare Ruby return value */ |
| Wrapper_add_local(w, "result", "VALUE result"); |
| |
| /* direct call to superclass if _up is set */ |
| Printf(w->code, "if (swig_get_up()) {\n"); |
| if (pure_virtual) { |
| Printf(w->code, "throw Swig::DirectorPureVirtualException();\n"); |
| } else { |
| if (is_void) { |
| Printf(w->code, "%s;\n", Swig_method_call(super,l)); |
| Printf(w->code, "return;\n"); |
| } else { |
| Printf(w->code, "return %s;\n", Swig_method_call(super,l)); |
| } |
| } |
| Printf(w->code, "}\n"); |
| |
| /* wrap complex arguments to VALUEs */ |
| Printv(w->code, wrap_args, NIL); |
| |
| /* pass the method call on to the Ruby object */ |
| exceptionSafeMethodCall(classname, n, w, idx, arglist); |
| |
| /* |
| * Ruby method may return a simple object, or an Array of objects. |
| * For in/out arguments, we have to extract the appropriate VALUEs from the Array, |
| * then marshal everything back to C/C++ (return value and output arguments). |
| */ |
| |
| /* Marshal return value and other outputs (if any) from VALUE to C/C++ type */ |
| |
| String* cleanup = NewString(""); |
| String* outarg = NewString(""); |
| |
| if (outputs > 1) { |
| Wrapper_add_local(w, "output", "VALUE output"); |
| Printf(w->code, "if (TYPE(result) != T_ARRAY) {\n"); |
| Printf(w->code, "throw Swig::DirectorTypeMismatchException(\"Ruby method failed to return an array.\");\n"); |
| Printf(w->code, "}\n"); |
| } |
| |
| idx = 0; |
| |
| /* Marshal return value */ |
| if (!is_void) { |
| /* This seems really silly. The node's type excludes qualifier/pointer/reference markers, |
| * which have to be retrieved from the decl field to construct return_type. But the typemap |
| * lookup routine uses the node's type, so we have to swap in and out the correct type. |
| * It's not just me, similar silliness also occurs in Language::cDeclaration(). |
| */ |
| Setattr(n, "type", return_type); |
| tm = Swig_typemap_lookup_new("directorout", n, "result", w); |
| Setattr(n, "type", type); |
| if (tm == 0) { |
| String *name = NewString("result"); |
| tm = Swig_typemap_search("directorout", return_type, name, NULL); |
| Delete(name); |
| } |
| if (tm != 0) { |
| if (outputs > 1) { |
| Printf(w->code, "output = rb_ary_entry(result, %d);\n", idx++); |
| Replaceall(tm, "$input", "output"); |
| } else { |
| Replaceall(tm, "$input", "result"); |
| } |
| /* TODO check this */ |
| if (Getattr(n,"wrap:disown")) { |
| Replaceall(tm,"$disown","SWIG_POINTER_DISOWN"); |
| } else { |
| Replaceall(tm,"$disown","0"); |
| } |
| Replaceall(tm, "$result", "c_result"); |
| Printv(w->code, tm, "\n", NIL); |
| } 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(return_type, 0), classname, name); |
| status = SWIG_ERROR; |
| } |
| } |
| |
| /* Marshal outputs */ |
| for (p = l; p; ) { |
| if ((tm = Getattr(p, "tmap:directorargout")) != 0) { |
| if (outputs > 1) { |
| Printf(w->code, "output = rb_ary_entry(result, %d);\n", idx++); |
| Replaceall(tm, "$input", "output"); |
| } else { |
| Replaceall(tm, "$input", "result"); |
| } |
| Replaceall(tm, "$result", Getattr(p, "name")); |
| Printv(w->code, tm, "\n", NIL); |
| p = Getattr(p, "tmap:directorargout:next"); |
| } else { |
| p = nextSibling(p); |
| } |
| } |
| |
| /* any existing helper functions to handle this? */ |
| if (!is_void) { |
| String* rettype = SwigType_str(return_type, 0); |
| if (!SwigType_isreference(return_type)) { |
| Printf(w->code, "return (%s) c_result;\n", rettype); |
| } else { |
| Printf(w->code, "return (%s) *c_result;\n", rettype); |
| } |
| Delete(rettype); |
| } |
| |
| Printf(w->code, "}\n"); |
| |
| /* emit the director method */ |
| if (status == SWIG_OK) { |
| if (!Getattr(n,"defaultargs")) { |
| Wrapper_print(w, f_directors); |
| Printv(f_directors_h, declaration, NIL); |
| } |
| } |
| |
| /* clean up */ |
| Delete(wrap_args); |
| Delete(arglist); |
| Delete(rtype); |
| Delete(return_type); |
| Delete(pclassname); |
| Delete(cleanup); |
| Delete(outarg); |
| DelWrapper(w); |
| return status; |
| } |
| |
| virtual int classDirectorConstructors(Node *n) { |
| return Language::classDirectorConstructors(n); |
| } |
| |
| virtual int classDirectorMethods(Node *n) { |
| return Language::classDirectorMethods(n); |
| } |
| |
| virtual int classDirectorDisown(Node *n) { |
| return Language::classDirectorDisown(n); |
| } |
| |
| void typemap_copy_pname_to_lname(ParmList *parms) |
| { |
| Parm *p; |
| String *pname; |
| String *lname; |
| |
| p = parms; |
| while (p) { |
| pname = Getattr(p,"name"); |
| lname = Copy(pname); |
| Setattr(p,"lname",lname); |
| p = nextSibling(p); |
| } |
| } |
| |
| String *runtimeCode() { |
| String *s = Swig_include_sys("rubydef.swg"); |
| if (!s) { |
| Printf(stderr, "*** Unable to open 'rubydef.swg'\n"); |
| s = NewString(""); |
| } |
| return s; |
| } |
| |
| String *defaultExternalRuntimeFilename() { |
| return NewString("swigrubyrun.h"); |
| } |
| }; /* class RUBY */ |
| |
| /* ----------------------------------------------------------------------------- |
| * swig_ruby() - Instantiate module |
| * ----------------------------------------------------------------------------- */ |
| |
| static Language * new_swig_ruby() { |
| return new RUBY(); |
| } |
| extern "C" Language * swig_ruby(void) { |
| return new_swig_ruby(); |
| } |
| |
| |
| /* |
| * Local Variables: |
| * c-basic-offset: 2 |
| * End: |
| */ |
| |