/* ----------------------------------------------------------------------------- * generate.cxx * * This file manages the code generation process and serves as a bridge between * the new SWIG parser and the old set of C++-based language modules. * * Author(s) : David Beazley (beazley@cs.uchicago.edu) * * Copyright (C) 1999-2000. The University of Chicago * See the file LICENSE for information on usage and redistribution. * ----------------------------------------------------------------------------- */ #include "swig11.h" static char cvstag[] = "$Header$"; int ReadOnly = 0; int WrapExtern = 0; /* Access permissions: public, private, protected */ enum { PUBLIC, PRIVATE, PROTECTED }; int Access = PUBLIC; /* Miscellaneous modes */ int Native = 0; /* This function tries to locate the module name within the parse tree */ static String *find_module(DOH *node) { DOH *n; if (!node) return 0; n = node; while (n) { if (Swig_tag_check(n,"module")) { return Getname(n); } if (Swig_tag_check(n,"file")) { String *ty; ty = Getattr(n,"type"); if (Cmp(ty,"include") == 0) { DOH *m; /* Might be in an include file */ m = find_module(Getchild(n)); if (m) return m; } } n = Getnext(n); } return find_module(Getchild(node)); } /* This helper function emits external function declarations */ static void emit_extern_func(DOH *node, File *f) { Parm *p; SwigType *tc; char *c; String *storage; storage = Getattr(node,"storage"); if (!storage) return; c = Char(storage); if (strncmp(c,"extern",6) == 0) { List *tl = NewList(); p = Getparms(node); while (p) { Append(tl,Gettype(p)); p = Getnext(p); } tc = Copy(Gettype(node)); SwigType_add_function(tc,tl); Printf(f,"%s %s;\n", storage, SwigType_str(tc,Getname(node))); Delete(tc); Delete(tl); } } /* Test if static */ static int check_static(DOH *node) { String *storage = Getattr(node,"storage"); if (!storage) return 0; if (Cmp(storage,"static") == 0) return 1; return 0; } /* Test if extern */ static int check_extern(DOH *node) { String *storage = Getattr(node,"storage"); if (!storage) return 0; if (strncmp(Char(storage),"extern",6) == 0) return 1; return 0; } static String *new_name = 0; /* Handle renaming */ static void set_scriptname(DOH *node) { if (new_name) { Setattr(node,"scriptname",new_name); } else { String *aname = Getattr(node,"altname"); if (aname) { Setattr(node,"scriptname",aname); } else { Setattr(node,"scriptname", Getname(node)); } } new_name = 0; } /* ----------------------------------------------------------------------------- * C++ Support * ----------------------------------------------------------------------------- */ static DOH *class_hash = 0; /* Hash table of classes that have been seen so far */ static DOH *current_class = 0; /* Set when wrapping a class */ static DOH *class_name = 0; /* Real name of current class */ static DOH *class_types = 0; /* Types defined within this class */ static String *construct_name = 0; /* Expected name of a constructor */ int AddMethods = 0; /* Set when in addmethods mode */ int Abstract = 0; /* Set when the class is determined to be abstract */ static int have_destructor = 0; static int have_constructor = 0; /* Check for abstract classes */ int cplus_check_abstract(DOH *node) { while (node) { if (Getattr(node,"abstract")) return 1; node = Getnext(node); } return 0; } /* Given a class object, this function builds an internal symbol table */ void cplus_build_symbols(DOH *node) { Hash *sym; DOH *c; sym = Getattr(node,"symbols"); if (!sym) { sym = NewHash(); Setattr(node,"symbols",sym); } c = Getchild(node); while (c) { String *name = Getname(c); String *tag = Gettag(c); if (Cmp(tag,"c:destructor") == 0) { name = NewStringf("~%s",name); } if (name) { DOH *pnode = Getattr(sym,name); if (pnode) { Printf(stderr,"%s:%d. '%s' redefined. Previous definition at %s:%d.\n", Getfile(c),Getline(c), name, Getfile(pnode), Getline(pnode)); } else { Setattr(sym,name,c); } } c = Getnext(c); } return; } /* Inherit certain types of declarations from another class */ /* Add a class type */ static void class_addtype(String *name, String *cname) { String *s; if (!cname) s = NewStringf("%s::%s", class_name, name); else s = NewStringf("%s::%s", cname, name); if (!class_types) class_types = NewHash(); Setattr(class_types,name,s); } /* Updates a type with a fully qualified version */ static void class_update_type(String *type) { String *base, *rep; if (!type) return; base = SwigType_base(type); if (!class_types) return; rep = Getattr(class_types,base); if (rep) { SwigType_setbase(type,rep); /* Printf(stdout,"updated type = '%s'\n", type); */ } } /* Updates a list of parms with fully qualified names */ static void class_update_parms(ParmList *p) { while (p) { class_update_type(Gettype(p)); p = Getnext(p); } } /* Traverse the inheritance hierarchy of a class */ void cplus_walk_inherit(DOH *cls, void (*action)(DOH *base, void *clientdata), void *clientdata) { DOH *base; List *bases; int i, nbase; bases = Getattr(cls,"bases"); if (bases) { nbase = Len(bases); for (i = 0; i < nbase; i++) { base = Getattr(class_hash, Getitem(bases,i)); if (base) { (*action)(base,clientdata); } } } } /* Action for inheriting type definitions */ static void inherit_types(DOH *cls, void *clientdata) { DOH *ty; ty = Getattr(cls,"types"); if (ty) { String *key; SwigType_merge_scope(ty,0); for (key = Firstkey(ty); key; key = Nextkey(ty)) { class_addtype(key, Getname(cls)); } } cplus_walk_inherit(cls,inherit_types,clientdata); } /* Action for inheriting typemaps */ static void inherit_typemaps(DOH *cls, void *clientdata) { DOH *ty; cplus_walk_inherit(cls,inherit_typemaps,clientdata); ty = Getattr(cls,"typemaps"); if (ty) { if (!clientdata) Swig_typemap_new_scope(ty); else Swig_typemap_pop_scope(); } } extern "C" { int swig11_unknown(DOH *node, void *clientdata) { Printf(stdout,"::: Unknown tag - '%s'\n", Getattr(node,"tag")); return 0; } int swig11_nil(DOH *node, void *clientdata) { return 0; } /* ----------------------------------------------------------------------------- * swig11_file() * * File inclusion directives. %include, %extern, and %import. * ----------------------------------------------------------------------------- */ int swig11_file(DOH *node, void *clientdata) { DOH *c; String *type; int old_we = WrapExtern; type = Getattr(node,"type"); if ((Cmp(type, "extern") == 0) || (Cmp(type,"import") == 0)) { WrapExtern = 1; } c = Getchild(node); if (Cmp(type,"import") == 0) { /* If importing a module, we try to find the module name and pass it to the language modules */ String *modname; modname = find_module(c); if (modname) { lang->import(modname); } } Swig_emit_all(c,clientdata); WrapExtern = old_we; return 0; } /* ----------------------------------------------------------------------------- * swig11_scope() * * Handle the %scope directive. This is a new feature not present in SWIG1.1. * Creates a new typemap scope and has other side effects. * ----------------------------------------------------------------------------- */ int swig11_scope(DOH *node, void *clientdata) { DOH *c; String *name; c = Getchild(node); name = Getname(node); Swig_typemap_new_scope(0); if (name) { if (Cmp(name,"native") == 0) { int oldnative = Native; Native = 1; Swig_emit_all(c,clientdata); Native = oldnative; } else if (Cmp(name,"readonly") == 0) { int oldro = ReadOnly; ReadOnly = 1; Swig_emit_all(c,clientdata); ReadOnly = oldro; } else { Swig_emit_all(c,clientdata); } } Hash *scp = Swig_typemap_pop_scope(); Setattr(node,"typemaps", scp); return 0; } /* ----------------------------------------------------------------------------- * swig11_insert() * * Code insertion with various %{ %} directives. * ----------------------------------------------------------------------------- */ int swig11_insert(DOH *node, void *clientdata) { String *section; String *filename; String *code; File *out; if (WrapExtern) return 0; section = Getattr(node,"section"); if (!section) { section = (void *) "header"; } out = Swig_filebyname(section); if (!out) { Printf(stderr,"%s:%d. Can't insert code into unknown section '%s'\n", Getfile(node), Getline(node), section); return 0; } filename = Getattr(node,"filename"); if (filename) { /* The user is inserting the contents of a file */ if (Swig_insert_file(filename,out) < 0) { Printf(stderr,"%s:%d. File '%s' not found.\n", Getfile(node), Getline(node), filename); } return 0; } code = Getattr(node,"code"); if (code) { Printf(out,"%s",code); } return 0; } /* ----------------------------------------------------------------------------- * swig11_pragma() * * %pragma directive. * ----------------------------------------------------------------------------- */ int swig11_pragma(DOH *node, void *clientdata) { String *name; String *value; if (WrapExtern) return 0; name = Getname(node); value = Getvalue(node); if (Cmp(name,"readonly") == 0) { ReadOnly = 1; } else if (Cmp(name,"readwrite") == 0) { ReadOnly = 0; } else if (Cmp(name,"name") == 0) { new_name = value; } lang->pragma(node); return 0; } /* ----------------------------------------------------------------------------- * swig11_typemap() * * Handle the %typemap directive. * ----------------------------------------------------------------------------- */ int swig11_typemap(DOH *node, void *clientdata) { String *name; SwigType *type; String *code; DOH *parms; String *method; if (WrapExtern) return 0; method = Getattr(node,"method"); name = Getname(node); type = Gettype(node); code = Getattr(node,"code"); parms = Getparms(node); if (current_class) { class_update_type(type); class_update_type(parms); } if (code) { Swig_typemap_register(method,type,name,code,parms); } else { String *srcname; String *srctype; srcname = Getattr(node,"srcname"); srctype = Getattr(node,"srctype"); if (srcname && srctype) { Swig_typemap_copy(method,srctype,srcname,type,name); } else { Swig_typemap_clear(method,type,name); } } return 0; } /* ----------------------------------------------------------------------------- * swig11_apply() * * The %apply directive. * ----------------------------------------------------------------------------- */ int swig11_apply(DOH *node, void *clientdata) { DOH *parms; String *name; SwigType *type; if (WrapExtern) return 0; name = Getname(node); type = Gettype(node); parms = Getparms(node); while (parms) { Swig_typemap_apply(type,name,Gettype(parms),Getname(parms)); parms = Getnext(parms); } return 0; } /* ----------------------------------------------------------------------------- * swig11_exception() * * The %except directive. * ----------------------------------------------------------------------------- */ int swig11_exception(DOH *node, void *clientdata) { String *code = Getattr(node,"code"); if (WrapExtern) return 0; if (code) { Swig_except_register(code); } else { Swig_except_clear(); } return 0; } /* ----------------------------------------------------------------------------- * swig11_clear() * * The %clear directive. * ----------------------------------------------------------------------------- */ int swig11_clear(DOH *node, void *clientdata) { DOH *parms = Getattr(node,"parms"); if (WrapExtern) return 0; while (parms) { Swig_typemap_clear_apply(Gettype(parms),Getname(parms)); parms = Getnext(parms); } return 0; } /* ----------------------------------------------------------------------------- * swig11_constant * * The %constant directive * ----------------------------------------------------------------------------- */ int swig11_constant(DOH *node, void *clientdata) { if (WrapExtern) return 0; if (Access != PUBLIC) return 0; set_scriptname(node); lang->constant(node); return 0; } /* ----------------------------------------------------------------------------- * swig11_function() * * Emit a wrapper function. * ----------------------------------------------------------------------------- */ int swig11_function(DOH *node, void *clientdata) { int is_static; if (WrapExtern) return 0; if (Access != PUBLIC) return 0; is_static = check_static(node); set_scriptname(node); /* Will need some kind of class check in here */ if (current_class) { /* Function has been declared inside a class definition. */ class_update_parms(Getparms(node)); class_update_type(Gettype(node)); String *name = Getname(node); if (Cmp(name,construct_name) == 0) { have_constructor =1; if (!Abstract) { lang->cpp_constructor(node); } } else { if (is_static) lang->cpp_staticfunction(node); else lang->cpp_memberfunction(node); } } else { /* Can't wrap a static function. Oh well. */ if (is_static) return 0; emit_extern_func(node,f_header); if (Native) { lang->nativefunction(node); } else { lang->function(node); } } return 0; } /* ----------------------------------------------------------------------------- * swig11_variable() * * Wrap a variable. * ----------------------------------------------------------------------------- */ int swig11_variable(DOH *node, void *clientdata) { int is_static; SwigType *type; if (WrapExtern) return 0; if (Access != PUBLIC) return 0; if (Native) { Printf(stderr,"%s:%d. Can't wrap variables in %%native mode (ignored).\n", Getfile(node),Getline(node)); return 0; } type = Gettype(node); is_static = check_static(node); set_scriptname(node); if (current_class) { /* Inside a class definition */ if (is_static) { lang->cpp_staticvariable(node); } else { lang->cpp_variable(node); } } else { if (check_extern(node)) { Printf(f_header,"extern %s;\n", SwigType_str(type, Getname(node))); } if (is_static) return 0; if (SwigType_isconst(type)) { swig11_constant(node,clientdata); } else { lang->variable(node); } } return 0; } /* ----------------------------------------------------------------------------- * swig11_typedef() * * Handle a typedef declaration. * ----------------------------------------------------------------------------- */ int swig11_typedef(DOH *node, void *clientdata) { String *name; SwigType *type; type = Gettype(node); name = Getname(node); SwigType_typedef(type,name); if (current_class) { class_addtype(name,0); } lang->add_typedef(type, Char(name)); return 0; } /* ----------------------------------------------------------------------------- * swig11_enum() * * Support for enumerations. * ----------------------------------------------------------------------------- */ int swig11_enum(DOH *node, void *clientdata) { DOH *c; String *name; if (WrapExtern) return 0; if (Access != PUBLIC) return 0; name = Getname(node); if (name && CPlusPlus) { /* Add a typedef */ String *t = NewStringf("enum %s", name); SwigType_typedef(t,name); class_addtype(name,0); Delete(t); } c = Getchild(node); Swig_emit_all(c,clientdata); return 0; } /* ----------------------------------------------------------------------------- * swig11_enumvalue() * * Create a constant corresponding to an enum value. * ----------------------------------------------------------------------------- */ int swig11_enumvalue(DOH *node, void *clientdata) { set_scriptname(node); Setattr(node,"type","int"); /* Enums wrapped as ints */ if (!Getvalue(node)) { /* If no value, use the name itself */ if (class_name) { Setvalue(node,NewStringf("%s::%s",class_name, Getname(node))); } else { Setvalue(node,Getname(node)); } } if (current_class) { lang->cpp_constant(node); } else { swig11_constant(node,clientdata); } return 0; } /* ----------------------------------------------------------------------------- * swig11_class() * * Wrapping of C++ classes * ----------------------------------------------------------------------------- */ int swig11_class(DOH *node, void *clientdata) { DOH *c; List *bases; /* Save the class */ String *name = Getname(node); Setattr(class_hash,name,node); if (WrapExtern) return 0; if (Native) { Printf(stderr,"%s:%d. Can't wrap structures or classes in %%native mode (ignored).\n", Getfile(node),Getline(node)); return 0; } set_scriptname(node); class_name = name; class_types = 0; have_destructor = 0; have_constructor = 0; /* Need to merge in data from other scopes. For typemaps, can include scopes for each base class one after the other. For types, need to merge type information */ SwigType_new_scope(); if (name) { SwigType_set_scope_name(name); } cplus_walk_inherit(node, inherit_types, 0); /* Merge in typemaps */ cplus_walk_inherit(node, inherit_typemaps, 0); /* Create a typemap scope for this class */ Swig_typemap_new_scope(0); cplus_build_symbols(node); lang->cpp_open_class(node); current_class = node; construct_name = Getname(node); if (!CPlusPlus) { String *altname = Getattr(node,"altname"); if (altname) construct_name = altname; } c = Getchild(node); Abstract = cplus_check_abstract(c); Swig_emit_all(c,clientdata); bases = Getattr(node,"bases"); if (bases) { String *b; lang->cpp_inherit(bases); b = Firstitem(bases); while (b) { SwigType_inherit(Getname(current_class),b); b = Nextitem(bases); } } /* Check for constructors and destructors */ if (CPlusPlus) { if (!have_constructor && !Abstract) { DOH *cn = NewHash(); Setname(cn, Getname(current_class)); Setattr(cn,"scriptname", Getname(current_class)); lang->cpp_constructor(cn); } if (!have_destructor) { DOH *dn = NewHash(); Setname(dn, Getname(current_class)); Setattr(dn,"scriptname", Getname(current_class)); lang->cpp_destructor(dn); } } lang->cpp_close_class(); /* Pop the type scope and save with the class */ Hash *scp = SwigType_pop_scope(); Setattr(node,"types",scp); scp = Swig_typemap_pop_scope(); Setattr(node,"typemaps",scp); Setattr(node,"classtypes",class_types); /* Pop off all of the typemap scopes we added */ cplus_walk_inherit(node,inherit_typemaps, (void *) 1); current_class = 0; construct_name = 0; class_name = 0; return 0; } /* ----------------------------------------------------------------------------- * swig11_classdecl() * * Empty class declaration. Used to register classes with language modules. * ----------------------------------------------------------------------------- */ int swig11_classdecl(DOH *node, void *clientdata) { if (WrapExtern) return 0; set_scriptname(node); lang->cpp_class_decl(node); return 0; } int swig11_addmethods(DOH *node, void *clientdata) { DOH *c; int oldaddmethods = AddMethods; if (WrapExtern) return 0; if (!current_class) { Printf(stderr,"%s:%d. %%addmethods ignored (does not appear inside a class).\n", Getfile(node),Getline(node)); return 0; } AddMethods = 1; c = Getchild(node); Swig_emit_all(c,clientdata); AddMethods = oldaddmethods;; return 0; } /* ----------------------------------------------------------------------------- * swig11_destructor() * * C++ Destructor * ----------------------------------------------------------------------------- */ int swig11_destructor(DOH *node, void *clientdata) { if (WrapExtern) return 0; if (Access != PUBLIC) return 0; if (!current_class) return 0; set_scriptname(node); lang->cpp_destructor(node); have_destructor = 1; return 0; } /* ----------------------------------------------------------------------------- * swig11_access() * * Handle an access specifier (public, private, protected) * ----------------------------------------------------------------------------- */ int swig11_access(DOH *node, void *clientdata) { String *name = Getname(node); if (Cmp(name,"public") == 0) Access = PUBLIC; else if (Cmp(name,"private") == 0) Access = PRIVATE; else if (Cmp(name,"protected") == 0) Access = PROTECTED; return 0; } /* ----------------------------------------------------------------------------- * swig11_types() * * Handle the types directive. * ----------------------------------------------------------------------------- */ int swig11_types(DOH *node, void *clientdata) { Parm *p; p = Getparms(node); while (p) { SwigType *t = Gettype(p); SwigType_remember(t); p = Getnext(p); } return 0; } static SwigRule rules[] = { { "file", swig11_file}, { "scope", swig11_scope}, { "insert", swig11_insert}, { "pragma", swig11_pragma}, { "typemap", swig11_typemap}, { "apply", swig11_apply}, { "exception", swig11_exception}, { "clear", swig11_clear}, { "addmethods", swig11_addmethods}, { "constant", swig11_constant}, { "function", swig11_function}, { "variable", swig11_variable}, { "typedef", swig11_typedef}, { "enum", swig11_enum}, { "enumvalue", swig11_enumvalue}, { "class", swig11_class}, { "classdecl", swig11_classdecl}, { "destructor", swig11_destructor}, { "access", swig11_access}, { "types", swig11_types}, { "module", swig11_nil}, { "*", swig11_unknown}, { 0 } }; } /* ----------------------------------------------------------------------------- * generate() * * Called by the SWIG1.1 system to emit code * ----------------------------------------------------------------------------- */ void generate(DOH *node) { DOH *c; extern String *swig_module; /* Initialize globals */ class_hash = NewHash(); Swig_add_rules(rules); c = Getattr(node,"child"); /* Find the module name */ if (!swig_module) { swig_module = find_module(c); } if (!swig_module) { Printf(stderr,"SWIG: No module name specified! Please use %%module or -module.\n"); Swig_exit(EXIT_FAILURE); } lang->initialize(swig_module); Swig_emit_all(c,0); lang->close(); /* Swig_dump_tags(node,0); */ }