swig/Source/Modules/ruby.cxx

1453 lines
43 KiB
C++

/********************************************************************
* 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"
#ifndef MACSWIG
#include "swigconfig.h"
#endif
#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 */
String *vname; /* variable name */
String *type;
String *prefix;
String *header;
String *init;
int constructor_defined;
int destructor_defined;
RClass() {
temp = NewString("");
name = NewString("");
cname = NewString("");
mname = NewString("");
vname = NewString("");
type = NewString("");
prefix = NewString("");
header = NewString("");
init = NewString("");
constructor_defined = 0;
destructor_defined = 0;
}
~RClass() {
Delete(name);
Delete(cname);
Delete(vname);
Delete(mname);
Delete(type);
Delete(prefix);
Delete(header);
Delete(init);
Delete(temp);
}
void set_name(const String_or_char *cn, const String_or_char *rn, const String_or_char *valn) {
Clear(cname);
Append(cname,cn);
Delete(mname);
mname = Swig_name_mangle(cname);
Clear(name);
Append(name,valn);
Clear(vname);
Printf(vname,"c%s.klass",name);
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);
}
};
#ifdef RUBY_SUPPORTS_KEYWORD_ARGS
static const char *
usage = "\
Ruby Options (available with -ruby)\n\
-ldflags - Print runtime libraries to link with\n\
-feature name - Set feature name (used by `require')\n\
-keyword - Use keyword arguments\n";
#else
static const char *
usage = "\
Ruby Options (available with -ruby)\n\
-ldflags - Print runtime libraries to link with\n\
-feature name - Set feature name (used by `require')\n";
#endif
#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;
int current;
Hash *classes; /* key=cname val=RClass */
RClass *klass; /* Currently processing class */
Hash *special_methods; /* Python style special method name table */
File *f_runtime;
File *f_header;
File *f_wrappers;
File *f_init;
bool use_kw;
// 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;
current = NO_CPP;
classes = 0;
klass = 0;
special_methods = 0;
f_runtime = 0;
f_header = 0;
f_wrappers = 0;
f_init = 0;
use_kw = false;
}
/* ---------------------------------------------------------------------
* 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],"-help") == 0) {
Printf(stderr,"%s\n", usage);
} else if (strcmp (argv[i],"-ldflags") == 0) {
printf("%s\n", SWIG_RUBY_RUNTIME);
SWIG_exit (EXIT_SUCCESS);
} else if (strcmp(argv[i],"-keyword") == 0) {
use_kw = true;
Swig_mark_arg(i);
}
}
}
/* 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;
String *m = Firstitem(modules);
while (m != 0) {
if (Len(m) > 0) {
if (mv != 0) {
Printv(f_init, tab4, modvar,
" = rb_define_module_under(", modvar, ", \"", m, "\");\n", NIL);
} else {
Printv(f_init, tab4, modvar,
" = rb_define_module(\"", m, "\");\n", NIL);
mv = NewString(modvar);
}
}
m = Nextitem(modules);
}
Delete(mv);
Delete(modules);
}
}
/* ---------------------------------------------------------------------
* top()
* --------------------------------------------------------------------- */
virtual int top(Node *n) {
/* Initialize all of the output files */
String *outfile = Getattr(n,"outfile");
f_runtime = NewFile(outfile,"w");
if (!f_runtime) {
Printf(stderr,"*** Can't open '%s'\n", outfile);
SWIG_exit(EXIT_FAILURE);
}
f_init = 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("runtime",f_runtime);
Swig_register_filebyname("init",f_init);
modvar = 0;
current = NO_CPP;
klass = 0;
classes = NewHash();
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");
Swig_banner(f_runtime);
if (NoInclude) {
Printf(f_runtime, "#define SWIG_NOINCLUDE\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")));
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",
"void Init_", feature, "(void) {\n",
"int i;\n",
"\n",
NIL);
Printv(f_init, tab4, "SWIG_InitRuntime();\n", NIL);
defineRubyModule();
Printv(f_init,
"\n",
"for (i = 0; swig_types_initial[i]; i++) {\n",
"swig_types[i] = SWIG_TypeRegister(swig_types_initial[i]);\n",
"SWIG_define_class(swig_types[i]);\n",
"}\n",
NIL);
Printf(f_init,"\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);
Dump(f_wrappers,f_runtime);
Wrapper_pretty_print(f_init,f_runtime);
Delete(f_header);
Delete(f_wrappers);
Delete(f_init);
Close(f_runtime);
Delete(f_runtime);
return SWIG_OK;
}
/* -----------------------------------------------------------------------------
* importDirective()
* ----------------------------------------------------------------------------- */
virtual int importDirective(Node *n) {
String *modname = Getattr(n,"module");
if (modname) {
Printf(f_init,"rb_require(\"%s\");\n", modname);
}
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("");
/* Account for nested modules */
List *modules = Split(mod_name,':',INT_MAX);
if (modules != 0 && Len(modules) > 0) {
String *last = 0;
String *m = Firstitem(modules);
while (m != 0) {
if (Len(m) > 0) {
String *cap = NewString(m);
(Char(cap))[0] = toupper((Char(cap))[0]);
if (last != 0) {
Append(module, "::");
}
Append(module, cap);
last = m;
}
m = Nextitem(modules);
}
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) {
String *alias = Firstitem(aliases);
while (alias) {
if (Len(alias) > 0) {
Printv(klass->init, tab4, "rb_define_alias(", klass->vname, ", \"", alias, "\", \"", iname, "\");\n", NIL);
}
alias = Nextitem(aliases);
}
}
Delete(aliases);
}
}
/* ---------------------------------------------------------------------
* create_command(Node *n, char *iname)
*
* Creates a new command from a C function.
* iname = Name of function in scripting language
* --------------------------------------------------------------------- */
void create_command(Node *n, const String_or_char *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("");
switch (current) {
case MEMBER_FUNC:
Printv(klass->init, tab4, "rb_define_method(", klass->vname, ", \"",
iname, "\", ", wname, ", -1);\n", NIL);
break;
case CONSTRUCTOR_ALLOCATE:
Printv(s, tab4, "rb_define_singleton_method(", klass->vname,
", \"new\", ", wname, ", -1);\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", "");
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;
default:
Printv(s, tab4, "rb_define_module_function(", modvar, ", \"",
iname, "\", ", wname, ", -1);\n",NIL);
Printv(f_init,s,NIL);
break;
}
defineAliases(n, iname);
Delete(temp);
Delete(s);
Delete(wname);
}
/* ---------------------------------------------------------------------
* marshalInputArgs(int numarg, int numreq, int start, 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 marshalInputArgs(ParmList *l, int numarg, int numreq, int start, String *kwargs, bool allow_kwargs, Wrapper *f) {
int i;
Parm *p;
String *tm;
char source[256], target[256];
int use_self = (current == MEMBER_FUNC || current == MEMBER_VAR) ? 1 : 0;
int varargs = emit_isvarargs(l);
Printf(kwargs,"{ ");
for (i = 0, p = l; i < numarg; i++) {
/* Skip ignored arguments */
while (checkAttribute(p,"tmap:in:numinputs","0")) {
p = Getattr(p,"tmap:in:next");
}
SwigType *pt = Getattr(p,"type");
String *pn = Getattr(p,"name");
String *ln = Getattr(p,"lname");
/* Produce string representation of source and target arguments */
int selfp = (use_self && i == 0);
if (selfp)
strcpy(source,"self");
else
sprintf(source,"argv[%d]",i-start);
sprintf(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 */
if ((tm = Getattr(p,"tmap:in"))) {
Replaceall(tm,"$target",ln);
Replaceall(tm,"$source",source);
Replaceall(tm,"$input",source);
Setattr(p,"emit:input",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);
}
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"))) {
sprintf(source,"argv[%d]",i-start);
Replaceall(tm,"$input",source);
Setattr(p,"emit:input",source);
Printf(f->code,"if (argc > %d) {\n", i-start);
Printv(f->code,tm,"\n",NIL);
Printf(f->code,"}\n");
}
}
}
/* ---------------------------------------------------------------------
* 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);
}
}
}
/* ---------------------------------------------------------------------
* insertCleanupCode(ParmList *l, String *cleanup)
*
* 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"));
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;
}
/* ---------------------------------------------------------------------
* functionWrapper()
*
* Create a function declaration and register it with the interpreter.
* --------------------------------------------------------------------- */
virtual int functionWrapper(Node *n) {
String *symname = Copy(Getattr(n,"sym:name"));
SwigType *t = Getattr(n,"type");
ParmList *l = Getattr(n,"parms");
String *tm;
int need_result = 0;
/* Ruby needs no destructor wrapper */
if (current == DESTRUCTOR)
return SWIG_NOWRAP;
/* 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 (Getattr(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 = use_kw || Getattr(n,"feature:kwargs");
int start = (current == MEMBER_FUNC || current == MEMBER_VAR) ? 1 : 0;
/* Now write the wrapper function itself */
Printv(f->def, "static VALUE\n", wname, "(int argc, VALUE *argv, VALUE self) {", NIL);
if (current != CONSTRUCTOR_ALLOCATE) {
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(l, numarg, numreq, start, kwargs, allow_kwargs, f);
}
/* Insert constraint checking code */
insertConstraintCheckingCode(l, f);
/* Insert cleanup code */
insertCleanupCode(l, cleanup);
/* Insert argument output code */
insertArgOutputCode(l, outarg, need_result);
/* 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;");
}
}
emit_action(n,f);
}
int newobj = 0;
if (Getattr(n,"feature:new")) newobj = 1;
/* Return value if necessary */
if (SwigType_type(t) != T_VOID && current != CONSTRUCTOR_ALLOCATE && current != CONSTRUCTOR_INITIALIZE) {
need_result = 1;
if (Getattr(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");
Replaceall(tm,"$owner", newobj ? "1" : "0");
Printv(f->code, tm, "\n", NIL);
} 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, "rb_obj_call_init(vresult, argc, argv);\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 (newobj) {
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}\n", NIL);
} else if (current == CONSTRUCTOR_INITIALIZE) {
Printv(f->code, tab4, "return self;\n}\n", NIL);
} else {
Wrapper_add_local(f,"vresult","VALUE vresult = Qnil");
Printv(f->code, tab4, "return vresult;\n}\n", NIL);
}
} else {
Printv(f->code, tab4, "return Qnil;\n}\n", NIL);
}
/* 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");
if (current == MEMBER_FUNC || current == MEMBER_VAR) {
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) {
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 (Getattr(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 (!Getattr(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 */
Printv(s,
tab4, "rb_define_singleton_method(", modvar, ", \"",
iname, "\", ", getfname, ", 0);\n",
NIL);
if (!Getattr(n,"feature:immutable")) {
Printv(s,
tab4, "rb_define_singleton_method(", modvar, ", \"",
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\n", reason);
return name;
}
/* ---------------------------------------------------------------------
* constantWrapper()
* --------------------------------------------------------------------- */
virtual int constantWrapper(Node *n) {
Swig_require(&n, "*sym:name", "type", "value", NIL);
char *iname = GetChar(n,"sym:name");
SwigType *type = Getattr(n,"type");
char *value = GetChar(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) {
Replaceall(tm, "$module", klass->vname);
Printv(klass->init, tm, "\n", NIL);
} else {
Replaceall(tm,"$module", modvar);
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) {
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);
}
/* ----------------------------------------------------------------------
* 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(klass->header, "\nswig_class c", valid_name, ";\n", NIL);
Printv(klass->init, "\n", tab4, NIL);
Printv(klass->init, klass->vname, " = rb_define_class_under(", modvar,
", \"", 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);
/* Process the comma-separated list of mixed-in module names (if any) */
String *mixin = Getattr(n,"feature:mixin");
if (mixin) {
List *modules = Split(mixin,',',INT_MAX);
if (modules && Len(modules) > 0) {
String *mod = Firstitem(modules);
while (mod) {
if (Len(mod) > 0) {
Printf(klass->init, "rb_include_module(%s, rb_eval_string(\"%s\"));\n", klass->vname, mod);
}
mod = Nextitem(modules);
}
}
Delete(modules);
}
Printv(klass->init, "$allocator",NIL);
Printv(klass->init, "$initializer",NIL);
Printv(klass->header,
"$freeproto",
NIL);
Language::classHandler(n);
/* Handle inheritance */
List *baselist = Getattr(n,"bases");
if (baselist && Len(baselist)) {
Node *base = Firstitem(baselist);
String *basename = Getattr(base,"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);
String *bmangle = SwigType_manglestr(btype);
Insert(bmangle,0,"((swig_class *) SWIGTYPE");
Append(bmangle,"->clientdata)->klass");
Replaceall(klass->init,"$super",bmangle);
Delete(bmangle);
Delete(btype);
}
/* Warn about multiple inheritance if additional base class(es) listed */
base = Nextitem(baselist);
while (base) {
basename = Getattr(n,"name");
Swig_warning(WARN_RUBY_MULTIPLE_INHERITANCE, input_file, line_number,
"Warning for %s: Base %s ignored. Multiple inheritance is not supported in Ruby.\n", basename, basename);
base = Nextitem(baselist);
}
}
/* Check to see if a %markfunc was specified */
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 */
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);
}
}
Replaceall(klass->header,"$freeproto", "");
Printv(f_header, klass->header,NIL);
String *s = NewString("");
Printv(s, tab4, "rb_undef_method(CLASS_OF(", klass->vname,
"), \"new\");\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
* -------------------------------------------------------------------- */
virtual int constructorHandler(Node *n) {
/* First wrap the new singleton method */
current = CONSTRUCTOR_ALLOCATE;
Swig_name_register((String_or_char *) "construct", (String_or_char *) "%c_allocate");
Language::constructorHandler(n);
/* Now do the instance initialize method */
current = CONSTRUCTOR_INITIALIZE;
Swig_name_register((String_or_char *) "construct", (String_or_char *) "new_%c");
Language::constructorHandler(n);
/* Done */
Swig_name_unregister((String_or_char *) "construct");
current = NO_CPP;
klass->constructor_defined = 1;
return SWIG_OK;
}
/* ---------------------------------------------------------------------
* destructorHandler()
* -------------------------------------------------------------------- */
virtual int destructorHandler(Node *n) {
current = DESTRUCTOR;
Language::destructorHandler(n);
String *freefunc = NewString("");
String *freeproto = NewString("");
String *freebody = NewString("");
Printv(freefunc, "free_", klass->mname, NIL);
Printv(freeproto, "static void ", freefunc, "(", klass->type, " *);\n", 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) {
File *f_code = Swig_filebyname("header");
if (f_code) {
Printv(f_code, wrap, NIL);
}
}
/* Printv(freebody, Swig_name_destroy(name), "(", Swig_cparm_name(0,0), ")", NIL); */
Printv(freebody,Getattr(n,"wrap:action"), NIL);
} else {
/* When no extend mode, swig emits no destroy function. */
if (CPlusPlus)
Printf(freebody, "delete %s", Swig_cparm_name(0,0));
else
Printf(freebody, "free((char*) %s)", Swig_cparm_name(0,0));
}
Printv(freebody, ";\n}\n", NIL);
Replaceall(klass->header,"$freeproto", freeproto);
Printv(f_wrappers, freebody, NIL);
klass->destructor_defined = 1;
current = NO_CPP;
Delete(freefunc);
Delete(freeproto);
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;
}
}; /* class RUBY */
/* -----------------------------------------------------------------------------
* swig_ruby() - Instantiate module
* ----------------------------------------------------------------------------- */
extern "C" Language *
swig_ruby(void) {
return new RUBY();
}
/*
* Local Variables:
* c-basic-offset: 2
* End:
*/