c90f71dd8c
special cases and other things in wxPython, and since I plan on making several more, I've decided to put the SWIG sources in wxPython's CVS instead of relying on maintaining patches. This effectivly becomes a fork of an obsolete version of SWIG, :-( but since SWIG 1.3 still doesn't have some things I rely on in 1.1, not to mention that my custom patches would all have to be redone, I felt that this is the easier road to take. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@15307 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2683 lines
77 KiB
C++
2683 lines
77 KiB
C++
/*******************************************************************************
|
|
* Simplified Wrapper and Interface Generator (SWIG)
|
|
*
|
|
* Author : David Beazley
|
|
*
|
|
* Department of Computer Science
|
|
* University of Chicago
|
|
* 1100 E 58th Street
|
|
* Chicago, IL 60637
|
|
* beazley@cs.uchicago.edu
|
|
*
|
|
* Please read the file LICENSE for the copyright and terms by which SWIG
|
|
* can be used and distributed.
|
|
*******************************************************************************/
|
|
|
|
#include "internal.h"
|
|
|
|
/*******************************************************************************
|
|
* $Header$
|
|
*
|
|
* File : cplus.cxx
|
|
*
|
|
* This module defines parser entry points for supporting C++. Primarily
|
|
* this module is in charge of keeping track of the contents of C++ classes,
|
|
* organizing inheritance, and other things.
|
|
*
|
|
* Eventually this module will be merged with the type handling mechanism
|
|
* in SWIG 2.0 so it's a little messy right now.
|
|
*
|
|
* General comments :
|
|
*
|
|
* 1. The words "simple" and "C++" are rarely used in the same
|
|
* sentence. Therefore this module is going to be some sort
|
|
* of compromise.
|
|
*
|
|
* 2. I'm using the "Annotated C++ Reference Manual" (ARM) as my
|
|
* reference for handling certain cases. Of course, there
|
|
* is a high probability that I have misinterpreted or overlooked
|
|
* certain cases.
|
|
*
|
|
* 3. It is not my intent to write a full C++ compiler.
|
|
*
|
|
* My goals are simple :
|
|
* - Support simple ANSI C-like class member functions and data.
|
|
* - Support constructors and destructors.
|
|
* - static member functions.
|
|
* - basic inheritance.
|
|
* - virtual functions.
|
|
* - References
|
|
*
|
|
* I do not plan to support the following anytime in the near future
|
|
* - Operator overloading
|
|
* - templates
|
|
*
|
|
* Caution :
|
|
*
|
|
* The control flow in this module is completely insane. But here's the
|
|
* rough outline.
|
|
*
|
|
* Stage 1 : SWIG Parsing
|
|
* cplus_open_class() - Open up a new class
|
|
* cplus_* - Add members to class
|
|
* cplus_inherit() - Inherit from base classes
|
|
* cplus_class_close() - Close class
|
|
*
|
|
* ...
|
|
* cplus_open_class()
|
|
* ...
|
|
* cplus_class_close()
|
|
*
|
|
* ... and so on, until the end of the file
|
|
*
|
|
* After stage 1, all classes have been read, but nothing has been
|
|
* sent to the language module yet.
|
|
*
|
|
* Stage 2 : Code generation
|
|
* For each class we've saved, do this :
|
|
* lang->cpp_open_class() - Open class
|
|
* lang->cpp_* - Emit members
|
|
* lang->cpp_inherit() - Inherit
|
|
* lang->cpp_close_class() - Close class
|
|
*
|
|
* This two-stage approach solves a number of problems related to working
|
|
* with multiple files, mutually referenced classes, add adding methods.
|
|
* Just keep in mind that all C++ code is emitted *after* an entire SWIG
|
|
* file has been parsed.
|
|
*
|
|
* Improved code generation and inheritance of added methods (2/18/97):
|
|
*
|
|
* Each C++ declaration now has an associated function name attached to it.
|
|
* For example :
|
|
*
|
|
* class Foo {
|
|
* void bar();
|
|
* }
|
|
*
|
|
* Generates a member function "bar()" with a accessor function named
|
|
* "Foo_bar()". We will use this recorded accessor function to generate
|
|
* better code for inheritance. For example :
|
|
*
|
|
* class Foo2 : public Foo {
|
|
*
|
|
* ...
|
|
* }
|
|
*
|
|
* Will create a function called "Foo2_bar()" that is really mapped
|
|
* onto the base-class method "Foo_bar()". This should improve
|
|
* code generation substantially.
|
|
*
|
|
* Tricky stuff :
|
|
* - Each target language is responsible for naming wrapper
|
|
* functions.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
// Some status variables
|
|
|
|
static int Inherit_mode = 0; // Set if we're inheriting members
|
|
static char *ccode = 0; // Set to optional C code (if available)
|
|
static Hash *localtypes; // Localtype hash
|
|
static int abstract =0; // Status bit set during code generation
|
|
|
|
static int cpp_id = 0;
|
|
|
|
// Forward references
|
|
|
|
void cplus_member_func(char *, char *, DataType *, ParmList *, int);
|
|
void cplus_constructor(char *, char *, ParmList *);
|
|
void cplus_destructor(char *, char *);
|
|
void cplus_variable(char *, char *, DataType *);
|
|
void cplus_static_func(char *, char *, DataType *, ParmList *);
|
|
void cplus_declare_const(char *, char *, DataType *, char *);
|
|
void cplus_static_var(char *, char *, DataType *);
|
|
void cplus_inherit_decl(char **);
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void add_local_type(char *type, char *classname)
|
|
// void add_local_type(DataType *type, char *classname)
|
|
//
|
|
// Adds a new datatype to the local datatype hash. This is used to handle
|
|
// datatypes defined within a class.
|
|
//
|
|
// Inputs : Datatype to place in hash
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects : Updates localtypes hash.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
static void add_local_type(char *type, char *classname) {
|
|
String str;
|
|
|
|
if (!localtypes) return; // No hash table initialized, ignore this
|
|
|
|
str << classname << "::" << type;
|
|
localtypes->add(type,copy_string(str));
|
|
}
|
|
|
|
void add_local_type(DataType *type, char *classname) {
|
|
add_local_type(type->name,classname);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void update_local_type(DataType *type)
|
|
//
|
|
// Checks to see whether this datatype is part of a class definition. If so,
|
|
// we update the type-name by appending the class prefix to it. Uses the
|
|
// name stored in current_class unless unavailable.
|
|
//
|
|
// Inputs : type = Datatype
|
|
//
|
|
// Output : type is updated with a new name.
|
|
//
|
|
// Side Effects : None
|
|
// -----------------------------------------------------------------------------
|
|
|
|
static void update_local_type(DataType *type) {
|
|
|
|
char *newname = 0;
|
|
|
|
// Lookup the datatype in the hash table
|
|
|
|
if (!localtypes) return;
|
|
|
|
newname = (char *) localtypes->lookup(type->name);
|
|
if (newname) {
|
|
strcpy(type->name, newname);
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void update_parms(ParmList *l)
|
|
//
|
|
// Updates all of the parameters in a parameter list with the proper C++ prefix
|
|
// (if neccessary).
|
|
//
|
|
// Inputs : l = Parameter list
|
|
//
|
|
// Output : Parameter list l is updated (make sure its a copy!)
|
|
//
|
|
// Side Effects : None
|
|
// -----------------------------------------------------------------------------
|
|
|
|
static void update_parms(ParmList *l) {
|
|
Parm *p;
|
|
p = l->get_first();
|
|
while (p) {
|
|
update_local_type(p->t);
|
|
|
|
// Check for default arguments
|
|
|
|
if ((p->defvalue) && (localtypes)) {
|
|
char *s;
|
|
s = (char *) localtypes->lookup(p->defvalue);
|
|
if (s) {
|
|
delete p->defvalue;
|
|
p->defvalue = copy_string(s);
|
|
}
|
|
}
|
|
p = l->get_next();
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// class CPP_member
|
|
//
|
|
// Base class for various kinds of C++ members
|
|
// -----------------------------------------------------------------------
|
|
class CPP_member {
|
|
public:
|
|
char *name; // Name of the member
|
|
char *iname; // Name of member in the interpreter
|
|
int is_static; // Is this a static member?
|
|
int new_method; // Is this a new method (added by SWIG)?
|
|
int line; // What line number was this member on
|
|
char *file; // What file was this in?
|
|
char *code; // Was there any supplied code?
|
|
char *base; // Base class where this was defined
|
|
int inherited; // Was this member inherited?
|
|
DocEntry *de; // Documentation entry
|
|
CPP_member *next; // Next member (for building linked lists)
|
|
int id; // type id when created
|
|
|
|
virtual void inherit(int) { }; // Inheritance rule (optional)
|
|
virtual void emit() = 0; // Emit rule
|
|
};
|
|
|
|
// ----------------------------------------------------------------------
|
|
// class CPP_function : public CPP_member
|
|
//
|
|
// Structure for handling a C++ member function
|
|
// ----------------------------------------------------------------------
|
|
|
|
class CPP_function : public CPP_member {
|
|
public:
|
|
DataType *ret_type;
|
|
ParmList *parms;
|
|
int new_object;
|
|
int is_virtual;
|
|
|
|
CPP_function(char *n, char *i, DataType *t, ParmList *l, int s, int v = 0) {
|
|
name = copy_string(n);
|
|
iname = copy_string(i);
|
|
ret_type = new DataType(t);
|
|
parms = new ParmList(l);
|
|
is_static = s;
|
|
is_virtual = v;
|
|
new_method = AddMethods;
|
|
new_object = NewObject;
|
|
inherited = Inherit_mode;
|
|
de = 0;
|
|
next = 0;
|
|
line = line_number;
|
|
file = input_file;
|
|
if (Inherit_mode) {
|
|
id = cpp_id;
|
|
} else {
|
|
id = type_id;
|
|
}
|
|
if (AddMethods) {
|
|
if (strlen(CCode.get()))
|
|
code = copy_string(CCode.get());
|
|
else
|
|
code = 0;
|
|
} else {
|
|
code = 0;
|
|
}
|
|
}
|
|
void inherit(int mode) {
|
|
doc_entry = 0; // No documentation for an inherited member
|
|
if (mode & INHERIT_FUNC) {
|
|
// Set up the proper addmethods mode and provide C code (if provided)
|
|
int oldaddmethods = AddMethods;
|
|
int oldnewobject = NewObject;
|
|
AddMethods = new_method;
|
|
NewObject = new_object;
|
|
CCode = code;
|
|
if (is_static) {
|
|
cplus_static_func(name, iname, ret_type, parms);
|
|
} else {
|
|
cplus_member_func(name, iname, ret_type, parms, is_virtual);
|
|
}
|
|
AddMethods = oldaddmethods;
|
|
NewObject = oldnewobject;
|
|
CCode = "";
|
|
}
|
|
}
|
|
void emit() {
|
|
ParmList *l;
|
|
DataType *t;
|
|
AddMethods = new_method;
|
|
NewObject = new_object;
|
|
doc_entry = de; // Restore documentation entry
|
|
line_number = line; // Restore line and file
|
|
input_file = file;
|
|
ccode = code;
|
|
|
|
// Make a copy of the parameter list and upgrade its types
|
|
|
|
l = new ParmList(parms);
|
|
t = new DataType(ret_type);
|
|
update_parms(l);
|
|
update_local_type(t);
|
|
if (is_static) {
|
|
lang->cpp_static_func(name, iname, t, l);
|
|
} else {
|
|
lang->cpp_member_func(name, iname, t, l);
|
|
}
|
|
l->check_defined();
|
|
t->check_defined();
|
|
delete l;
|
|
delete t;
|
|
}
|
|
};
|
|
|
|
// --------------------------------------------------------------------------
|
|
// class CPP_constructor : public CPP_member
|
|
//
|
|
// Class for holding a C++ constructor definition.
|
|
// --------------------------------------------------------------------------
|
|
|
|
class CPP_constructor : public CPP_member {
|
|
public:
|
|
ParmList *parms;
|
|
CPP_constructor(char *n, char *i, ParmList *l) {
|
|
name = copy_string(n);
|
|
iname = copy_string(i);
|
|
parms = new ParmList(l);
|
|
new_method = AddMethods;
|
|
inherited = 0;
|
|
de = 0;
|
|
next = 0;
|
|
line = line_number;
|
|
file = input_file;
|
|
id = type_id;
|
|
if (AddMethods) {
|
|
if (strlen(CCode.get()))
|
|
code = copy_string(CCode.get());
|
|
else
|
|
code = 0;
|
|
} else {
|
|
code = 0;
|
|
}
|
|
}
|
|
void emit() {
|
|
if (1) {
|
|
ParmList *l;
|
|
AddMethods = new_method;
|
|
doc_entry = de;
|
|
line_number = line;
|
|
input_file = file;
|
|
ccode = code;
|
|
|
|
// Make a copy of the parameter list and upgrade its types
|
|
|
|
l = new ParmList(parms);
|
|
update_parms(l);
|
|
lang->cpp_constructor(name,iname,l);
|
|
l->check_defined();
|
|
delete l;
|
|
} else {
|
|
if (Verbose) {
|
|
fprintf(stderr,"%s:%d: Constructor for abstract base class ignored.\n",
|
|
file,line);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
// class CPP_destructor : public CPP_member
|
|
//
|
|
// Class for holding a destructor definition
|
|
// --------------------------------------------------------------------------
|
|
|
|
class CPP_destructor : public CPP_member {
|
|
public:
|
|
|
|
CPP_destructor(char *n, char *i) {
|
|
name = copy_string(n);
|
|
iname = copy_string(i);
|
|
new_method = AddMethods;
|
|
de = 0;
|
|
next = 0;
|
|
inherited = 0;
|
|
line = line_number;
|
|
file = input_file;
|
|
id = type_id;
|
|
if (AddMethods) {
|
|
if (strlen(CCode.get()))
|
|
code = copy_string(CCode.get());
|
|
else
|
|
code = 0;
|
|
} else {
|
|
code = 0;
|
|
}
|
|
|
|
}
|
|
void emit() {
|
|
AddMethods = new_method;
|
|
doc_entry = de;
|
|
line_number = line;
|
|
input_file = file;
|
|
ccode = code;
|
|
lang->cpp_destructor(name, iname);
|
|
}
|
|
};
|
|
|
|
// -------------------------------------------------------------------------
|
|
// class CPP_variable : public CPP_member
|
|
//
|
|
// Class for a managing a data member
|
|
// -------------------------------------------------------------------------
|
|
|
|
class CPP_variable : public CPP_member {
|
|
public:
|
|
DataType *type;
|
|
int status;
|
|
CPP_variable(char *n, char *i, DataType *t, int s) {
|
|
name = copy_string(n);
|
|
iname = copy_string(i);
|
|
type = new DataType(t);
|
|
is_static = s;
|
|
status = Status;
|
|
de = 0;
|
|
next = 0;
|
|
new_method = AddMethods;
|
|
line = line_number;
|
|
file = input_file;
|
|
if (Inherit_mode) {
|
|
id = cpp_id;
|
|
} else {
|
|
id = type_id;
|
|
}
|
|
code = 0;
|
|
inherited = 0;
|
|
}
|
|
|
|
// Emit code for this
|
|
|
|
void emit() {
|
|
DataType *t;
|
|
int old_status = Status;
|
|
doc_entry = de;
|
|
AddMethods = new_method;
|
|
Status = status;
|
|
line_number = line;
|
|
input_file = file;
|
|
ccode = code;
|
|
|
|
t = new DataType(type);
|
|
if (t->qualifier) {
|
|
// if (strcmp(t->qualifier,"const") == 0) Status = Status | STAT_READONLY;
|
|
}
|
|
update_local_type(t);
|
|
if (!is_static) {
|
|
lang->cpp_variable(name,iname,t);
|
|
} else {
|
|
lang->cpp_static_var(name,iname,t);
|
|
}
|
|
t->check_defined();
|
|
Status = old_status;
|
|
delete t;
|
|
}
|
|
|
|
// Inherit into another class
|
|
|
|
void inherit(int mode) {
|
|
int oldstatus = Status;
|
|
Status = status;
|
|
doc_entry = 0;
|
|
if (mode & INHERIT_VAR) {
|
|
if (!is_static) {
|
|
int oldaddmethods = AddMethods;
|
|
AddMethods = new_method;
|
|
CCode = code;
|
|
cplus_variable(name,iname,type);
|
|
AddMethods = oldaddmethods;
|
|
CCode = "";
|
|
} else {
|
|
cplus_static_var(name,iname,type);
|
|
}
|
|
}
|
|
Status = oldstatus;
|
|
}
|
|
};
|
|
|
|
// -------------------------------------------------------------------------
|
|
// class CPP_constant : public CPP_member
|
|
//
|
|
// Class for managing constant values
|
|
// -------------------------------------------------------------------------
|
|
|
|
class CPP_constant : public CPP_member {
|
|
public:
|
|
char *value;
|
|
DataType *type;
|
|
CPP_constant(char *n, char *i, DataType *t, char *v) {
|
|
name = copy_string(n);
|
|
iname = copy_string(i);
|
|
type = new DataType(t);
|
|
value = copy_string(v);
|
|
de = 0;
|
|
new_method = AddMethods;
|
|
next = 0;
|
|
line = line_number;
|
|
file = input_file;
|
|
if (Inherit_mode)
|
|
id = cpp_id;
|
|
else
|
|
id = type_id;
|
|
code = 0;
|
|
inherited = 0;
|
|
}
|
|
|
|
void emit() {
|
|
doc_entry = de;
|
|
AddMethods = new_method;
|
|
line_number = line;
|
|
input_file = file;
|
|
ccode = code;
|
|
lang->cpp_declare_const(name,iname,type,value);
|
|
type->check_defined();
|
|
}
|
|
|
|
void inherit(int mode) {
|
|
doc_entry = 0;
|
|
if (mode & INHERIT_CONST)
|
|
cplus_declare_const(name, iname, type, value);
|
|
}
|
|
};
|
|
|
|
// ----------------------------------------------------------------------
|
|
// class CPP_class
|
|
//
|
|
// Class for managing class members (internally)
|
|
// ----------------------------------------------------------------------
|
|
|
|
static char *inherit_base_class = 0;
|
|
|
|
class CPP_class {
|
|
public:
|
|
char *classname; // Real class name
|
|
char *classrename; // New name of class (if applicable)
|
|
char *classtype; // class type (struct, union, class)
|
|
int strip; // Strip off class declarator
|
|
int wextern; // Value of extern wrapper variable for this class
|
|
int have_constructor; // Status bit indicating if we've seen a constructor
|
|
int have_destructor; // Status bit indicating if a destructor has been seen
|
|
int is_abstract; // Status bit indicating if this is an abstract class
|
|
int generate_default; // Generate default constructors
|
|
int objective_c; // Set if this is an objective C class
|
|
int error; // Set if this class can't be generated
|
|
int line; // Line number
|
|
char **baseclass; // Base classes (if any)
|
|
Hash *local; // Hash table for local types
|
|
Hash *scope; // Local scope hash table
|
|
DocEntry *de; // Documentation entry of class
|
|
CPP_member *members; // Linked list of members
|
|
CPP_class *next; // Next class
|
|
static CPP_class *classlist; // List of all classes stored
|
|
Pragma *pragmas; // Class pragmas
|
|
|
|
CPP_class(char *name, char *ctype) {
|
|
CPP_class *c;
|
|
classname = copy_string(name);
|
|
classtype = copy_string(ctype);
|
|
classrename = 0;
|
|
baseclass = 0;
|
|
de = doc_entry;
|
|
local = new Hash; // Create hash table for storing local datatypes
|
|
scope = 0;
|
|
error = 0;
|
|
pragmas = 0;
|
|
line = line_number;
|
|
|
|
// Walk down class list and add to end
|
|
|
|
c = classlist;
|
|
if (c) {
|
|
while (c->next) {
|
|
c = c->next;
|
|
}
|
|
c->next = this;
|
|
} else {
|
|
classlist = this;
|
|
}
|
|
next = 0;
|
|
members = 0;
|
|
strip = 0;
|
|
wextern = WrapExtern;
|
|
have_constructor = 0;
|
|
have_destructor = 0;
|
|
is_abstract = 0;
|
|
generate_default = GenerateDefault;
|
|
objective_c = ObjCClass;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Add a new C++ member to this class
|
|
// ------------------------------------------------------------------------------
|
|
|
|
void add_member(CPP_member *m) {
|
|
CPP_member *cm;
|
|
|
|
// Set base class where this was defined
|
|
if (inherit_base_class)
|
|
m->base = inherit_base_class;
|
|
else
|
|
m->base = classname;
|
|
if (!members) {
|
|
members = m;
|
|
return;
|
|
}
|
|
cm = members;
|
|
while (cm->next) {
|
|
cm = cm->next;
|
|
}
|
|
cm->next = m;
|
|
}
|
|
// ------------------------------------------------------------------------------
|
|
// Search for a member with the given name. Returns the member on success, 0 on failure
|
|
// ------------------------------------------------------------------------------
|
|
|
|
CPP_member *search_member(char *name) {
|
|
CPP_member *m;
|
|
char *c;
|
|
m = members;
|
|
while (m) {
|
|
c = m->iname ? m->iname : m->name;
|
|
if (strcmp(c,name) == 0) return m;
|
|
m = m->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Inherit. Put all the declarations associated with this class into the current
|
|
// ------------------------------------------------------------------------------
|
|
|
|
void inherit_decls(int mode) {
|
|
CPP_member *m;
|
|
m = members;
|
|
while (m) {
|
|
inherit_base_class = m->base;
|
|
cpp_id = m->id;
|
|
m->inherit(mode);
|
|
m = m->next;
|
|
}
|
|
inherit_base_class = 0;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Emit all of the declarations associated with this class
|
|
// ------------------------------------------------------------------------------
|
|
|
|
void emit_decls() {
|
|
CPP_member *m = members;
|
|
int last_scope = name_scope(0);
|
|
abstract = is_abstract;
|
|
while (m) {
|
|
cpp_id = m->id;
|
|
name_scope(cpp_id); // Set proper naming scope
|
|
m->emit();
|
|
m = m->next;
|
|
}
|
|
name_scope(last_scope);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Search for a given class in the list
|
|
// ------------------------------------------------------------------------------
|
|
|
|
static CPP_class *search(char *name) {
|
|
CPP_class *c;
|
|
c = classlist;
|
|
if (!name) return 0;
|
|
while (c) {
|
|
if (strcmp(name,c->classname) == 0) return c;
|
|
c = c->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Add default constructors and destructors
|
|
//
|
|
// ------------------------------------------------------------------------------
|
|
|
|
void create_default() {
|
|
if (!generate_default) return;
|
|
|
|
// Try to generate a constructor if not available.
|
|
CCode = "";
|
|
AddMethods = 0;
|
|
if ((!have_constructor) && (1)) {
|
|
ParmList *l;
|
|
l = new ParmList();
|
|
doc_entry = new DocDecl(classname,this->de);
|
|
cplus_constructor(classname,0,l);
|
|
};
|
|
|
|
if (!have_destructor) {
|
|
doc_entry = new DocDecl(classname,this->de);
|
|
cplus_destructor(classname,0);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// Dump *all* of the classes saved out to the various
|
|
// language modules (this does what cplus_close_class used to do)
|
|
// ------------------------------------------------------------------------------
|
|
static void create_all();
|
|
};
|
|
|
|
CPP_class *CPP_class::classlist = 0;
|
|
static CPP_class *current_class;
|
|
|
|
void CPP_class::create_all() {
|
|
CPP_class *c;
|
|
c = classlist;
|
|
while (c) {
|
|
if (!c->error) {
|
|
current_class = c;
|
|
localtypes = c->local;
|
|
if ((!c->wextern) && (c->classtype)) {
|
|
ObjCClass = c->objective_c;
|
|
doc_entry = c->de;
|
|
lang->cpp_open_class(c->classname,c->classrename,c->classtype,c->strip);
|
|
lang->cpp_pragma(c->pragmas);
|
|
c->create_default();
|
|
if (c->baseclass)
|
|
cplus_inherit_decl(c->baseclass);
|
|
c->emit_decls();
|
|
doc_entry = c->de;
|
|
lang->cpp_close_class();
|
|
}
|
|
}
|
|
c = c->next;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// char *cplus_base_class(char *name)
|
|
//
|
|
// Given a member name, return the base class that it belongs to.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
char *cplus_base_class(char *name) {
|
|
CPP_member *m = current_class->search_member(name);
|
|
if (m) {
|
|
return m->base;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_open_class(char *name, char *rname, char *ctype)
|
|
//
|
|
// Opens up a new C++ class. If rname is given, we'll be renaming the
|
|
// class. This also sets up some basic type equivalence for the
|
|
// type checker.
|
|
//
|
|
// Inputs :
|
|
// name = Name of the class
|
|
// rname = New name of the class (using %name() directive)
|
|
// ctype = Class type ("class","struct", or "union")
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Creates a new class obect internally.
|
|
// Added type-mappings to the SWIG type-checker module.
|
|
// Sets a number of internal state variables for later use.
|
|
//
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_open_class(char *name, char *rname, char *ctype) {
|
|
|
|
extern void typeeq_derived(char *, char *, char *cast=0);
|
|
char temp[256];
|
|
CPP_class *c;
|
|
|
|
// Add some symbol table management here
|
|
|
|
// Search for a previous class definition
|
|
|
|
c = CPP_class::search(name);
|
|
if (c) {
|
|
if (c->classtype) {
|
|
// Hmmm. We already seem to have defined this class so we'll
|
|
// create a new class object for whatever reason
|
|
current_class = new CPP_class(name, ctype);
|
|
} else {
|
|
// Looks like a reference was made to this class earlier
|
|
// somehow, but no other information is known. We'll
|
|
// make it our current class and fix it up a bit
|
|
current_class = c;
|
|
c->classtype = copy_string(ctype);
|
|
}
|
|
} else {
|
|
// Create a new class
|
|
current_class = new CPP_class(name, ctype);
|
|
current_class->de = doc_entry;
|
|
}
|
|
|
|
// Set localtypes hash to our current class
|
|
|
|
localtypes = current_class->local;
|
|
|
|
// If renaming the class, set the new name
|
|
|
|
if (rname) {
|
|
current_class->classrename = copy_string(rname);
|
|
}
|
|
|
|
// Make a typedef for both long and short versions of this datatype
|
|
|
|
if (name) {
|
|
if (strlen(name)) {
|
|
if (strlen(ctype) > 0 && strcmp(ctype, "class") != 0) {
|
|
sprintf(temp,"%s %s", ctype, name);
|
|
typeeq_derived(temp,name); // Map "struct foo" to "foo"
|
|
typeeq_derived(name,temp); // Map "foo" to "struct foo"
|
|
}
|
|
}
|
|
}
|
|
|
|
AddMethods = 0; // Reset add methods flag
|
|
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// DocEntry *cplus_set_class(char *name)
|
|
//
|
|
// This function sets the current class to a given name. If the class
|
|
// doesn't exist, this function will create one. If it already exists,
|
|
// we'll just use that.
|
|
//
|
|
// This function is used primarily to add or manipulate an already
|
|
// existing class, but in a different location. For example :
|
|
//
|
|
// %include "class.h" // Grab some classes
|
|
// ...
|
|
// %addmethods MyClass { // Add some members for shadow classes
|
|
// ... members ...
|
|
// }
|
|
//
|
|
// Sounds weird, but returns the documentation entry to class if it exists.
|
|
// The parser needs this so we can generate documentation correctly.
|
|
//
|
|
// Inputs : name = Name of the class
|
|
//
|
|
// Output : Documentation entry of class or NULL if it doesn't exist.
|
|
// The parser needs the documentation entry to properly associate
|
|
// new members.
|
|
//
|
|
// Side Effects :
|
|
// Changes the current class object. Resets a number of internal
|
|
// state variables. Should not be called inside of a open class
|
|
// declaration.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
DocEntry *cplus_set_class(char *name) {
|
|
|
|
CPP_class *c;
|
|
|
|
// Look for a previous class definition
|
|
|
|
c = CPP_class::search(name);
|
|
if (c) {
|
|
current_class = c;
|
|
localtypes = c->local;
|
|
return c->de;
|
|
} else {
|
|
fprintf(stderr,"%s:%d: Warning class %s undefined.\n",input_file,line_number,name);
|
|
current_class = new CPP_class(name,0);
|
|
localtypes = current_class->local;
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
// This function closes a class open with cplus_set_class()
|
|
|
|
void cplus_unset_class() {
|
|
current_class = 0;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_class_close(char *name)
|
|
//
|
|
// Close a C++ class definition. Up to this point, we've only been collecting
|
|
// member definitions. This function merely closes the class object and
|
|
// stores it in a list. All classes are dumped after processing has completed.
|
|
//
|
|
// If name is non-null, it means that the name of the class has actually been
|
|
// set after all of the definitions. For example :
|
|
//
|
|
// typedef struct {
|
|
// double x,y,z
|
|
// } Vector;
|
|
//
|
|
// If this is the case, we'll use that as our classname and datatype.
|
|
// Otherwise, we'll just go with the classname and classtype set earlier.
|
|
//
|
|
// Inputs : name = optional "new name" for the class.
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects : Resets internal variables. Saves class in internal list.
|
|
// Registers the class with the language module, but doesn't
|
|
// emit any code.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_class_close(char *name) {
|
|
|
|
if (name) {
|
|
// The name of our class suddenly changed by typedef. Fix things up
|
|
current_class->classname = copy_string(name);
|
|
|
|
// This flag indicates that the class needs to have it's type stripped off
|
|
current_class->strip = 1;
|
|
}
|
|
|
|
// If we're in C++ or Objective-C mode. We're going to drop the class specifier
|
|
|
|
if ((CPlusPlus) || (ObjCClass)) {
|
|
current_class->strip = 1;
|
|
}
|
|
|
|
// Register our class with the target language module, but otherwise
|
|
// don't do anything yet.
|
|
|
|
char *iname;
|
|
if (current_class->classrename) iname = current_class->classrename;
|
|
else iname = current_class->classname;
|
|
|
|
lang->cpp_class_decl(current_class->classname, iname, current_class->classtype);
|
|
|
|
// Clear current class variable and reset
|
|
current_class = 0;
|
|
localtypes = 0;
|
|
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_abort(void)
|
|
//
|
|
// Voids the current class--some kind of unrecoverable parsing error occurred.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_abort(void) {
|
|
current_class->error = 1;
|
|
current_class = 0;
|
|
localtypes = 0;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_cleanup(void)
|
|
//
|
|
// This function is called after all parsing has been completed. It dumps all
|
|
// of the stored classes out to the language module.
|
|
//
|
|
// Inputs : None
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects : Emits all C++ wrapper code.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_cleanup(void) {
|
|
|
|
// Dump all classes created at once (yikes!)
|
|
|
|
CPP_class::create_all();
|
|
lang->cpp_cleanup();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_inherit(int count, char **baseclass)
|
|
//
|
|
// Inherit from a baseclass. This function only really registers
|
|
// the inheritance, but doesn't do anything with it yet.
|
|
//
|
|
// Inputs : baseclass = A NULL terminated array of strings with the names
|
|
// of baseclasses. For multiple inheritance, there
|
|
// will be multiple entries in this list.
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects : Sets the baseclass variable of the current class.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_inherit(int count, char **baseclass) {
|
|
int i;
|
|
|
|
// printf("Inheriting : count = %d, baseclass = %x\n",count,baseclass);
|
|
// If there are baseclasses, make copy of them
|
|
if (count) {
|
|
current_class->baseclass = (char **) new char*[count+1];
|
|
for (i = 0; i < count; i++)
|
|
current_class->baseclass[i] = copy_string(baseclass[i]);
|
|
current_class->baseclass[i] = 0;
|
|
} else {
|
|
baseclass = 0;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// cplus_generate_types(char **baseclass)
|
|
//
|
|
// Generates the type-mappings between the current class and any associated
|
|
// base classes. This is done by performing a depth first search of the
|
|
// class hierarchy. Functions for performing correct type-casting are
|
|
// generated for each base-derived class pair.
|
|
//
|
|
// Inputs : baseclass = NULL terminated list of base classes
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects : Emits pointer conversion functions. Registers type-mappings
|
|
// with the type checking module.
|
|
//
|
|
// -----------------------------------------------------------------------------
|
|
|
|
static Hash convert; // Hash table of conversion functions
|
|
|
|
void cplus_generate_types(char **baseclass) {
|
|
CPP_class *bc;
|
|
int i;
|
|
String cfunc, temp1, temp2, temp3;
|
|
extern void typeeq_derived(char *, char *, char *);
|
|
|
|
if (!baseclass) {
|
|
return;
|
|
}
|
|
|
|
// Generate type-conversion functions and type-equivalence
|
|
|
|
i = 0;
|
|
while(baseclass[i]) {
|
|
cfunc = "";
|
|
|
|
bc = CPP_class::search(baseclass[i]);
|
|
if (bc) {
|
|
// Generate a conversion function (but only for C++)
|
|
|
|
if (!current_class->objective_c) {
|
|
temp3 = "";
|
|
temp3 << "Swig" << current_class->classname << "To" << bc->classname;
|
|
|
|
if (convert.add(temp3,(void *) 1) != -1) {
|
|
|
|
// Write a function for casting derived type to parent class
|
|
|
|
cfunc << "static void *Swig" << current_class->classname << "To" << bc->classname
|
|
<< "(void *ptr) {\n"
|
|
<< tab4 << current_class->classname << " *src;\n"
|
|
<< tab4 << bc->classname << " *dest;\n"
|
|
<< tab4 << "src = (" << current_class->classname << " *) ptr;\n"
|
|
<< tab4 << "dest = (" << bc->classname << " *) src;\n"
|
|
// << tab4 << "printf(\"casting...\\n\");\n"
|
|
<< tab4 << "return (void *) dest;\n"
|
|
<< "}\n";
|
|
|
|
fprintf(f_wrappers,"%s\n",cfunc.get());
|
|
}
|
|
} else {
|
|
temp3 = "0";
|
|
}
|
|
|
|
// Make a type-equivalence allowing derived classes to be used in functions of the
|
|
|
|
if (strlen(current_class->classtype) > 0 &&
|
|
strcmp(current_class->classtype, "class") != 0) {
|
|
temp1 = "";
|
|
temp1 << current_class->classtype << " " << current_class->classname;
|
|
temp2 = "";
|
|
temp2 << bc->classtype << " " << bc->classname;
|
|
// Add various equivalences to the pointer table
|
|
|
|
typeeq_derived(bc->classname, current_class->classname,temp3.get());
|
|
typeeq_derived(temp2.get(), current_class->classname,temp3.get());
|
|
typeeq_derived(temp2.get(), temp1.get(),temp3.get());
|
|
typeeq_derived(bc->classname, temp1.get(),temp3.get());
|
|
} else {
|
|
typeeq_derived(bc->classname, current_class->classname,temp3.get());
|
|
}
|
|
// Now traverse the hierarchy some more
|
|
cplus_generate_types(bc->baseclass);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_inherit_decl(char **baseclass)
|
|
//
|
|
// This function is called internally to handle inheritance between classes.
|
|
// Basically, we're going to generate type-checking information and call
|
|
// out to the target language to handle the inheritance.
|
|
//
|
|
// This function is only called when emitting classes to the language modules
|
|
// (after all parsing has been complete).
|
|
//
|
|
// Inputs : baseclass = NULL terminated list of base-class names.
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects : Generates type-mappings. Calls the language-specific
|
|
// inheritance function.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_inherit_decl(char **baseclass) {
|
|
|
|
// If not base-classes, bail out
|
|
|
|
if (!baseclass) return;
|
|
|
|
Inherit_mode = 1;
|
|
lang->cpp_inherit(baseclass); // Pass inheritance onto the various languages
|
|
Inherit_mode = 0;
|
|
|
|
// Create type-information for class hierarchy
|
|
|
|
cplus_generate_types(baseclass);
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_inherit_members(char *baseclass, int mode)
|
|
//
|
|
// Inherits members from a class. This is called by specific language modules
|
|
// to bring in members from base classes. It may or may not be called.
|
|
//
|
|
// This function is called with a *single* base-class, not multiple classes
|
|
// like other functions. To do multiple inheritance, simply call this
|
|
// with each of the associated base classes.
|
|
//
|
|
// Inputs :
|
|
// baseclass = Name of baseclass
|
|
// mode = Inheritance handling flags
|
|
// INHERIT_FUNC - Import functions in base class
|
|
// INHERIT_VAR - Import variables in base class
|
|
// INHERIT_CONST - Inherit constants
|
|
// INHERIT_ALL - Inherit everything (grossly inefficient)
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects : Imports methods from base-classes into derived classes.
|
|
//
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_inherit_members(char *baseclass, int mode) {
|
|
CPP_class *bc;
|
|
|
|
bc = CPP_class::search(baseclass);
|
|
if (bc) {
|
|
bc->inherit_decls(mode);
|
|
} else {
|
|
fprintf(stderr,"%s:%d: Warning. Base class %s undefined (ignored).\n", input_file, current_class->line, baseclass);
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_member_func(char *name, char *iname, DataType *type, ParmList *, is_virtual)
|
|
//
|
|
// Parser entry point to creating a C++ member function. This function primarily
|
|
// just records the function and does a few symbol table checks.
|
|
//
|
|
// Inputs :
|
|
// name = Real name of the member function
|
|
// iname = Renamed version (may be NULL)
|
|
// type = Return datatype
|
|
// l = Parameter list
|
|
// is_virtual = Set if this is a pure virtual function (ignored)
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Adds member function to current class.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_member_func(char *name, char *iname, DataType *type, ParmList *l,
|
|
int is_virtual) {
|
|
|
|
CPP_function *f;
|
|
char *temp_iname;
|
|
|
|
// First, figure out if we're renaming this function or not
|
|
|
|
if (!iname)
|
|
temp_iname = name;
|
|
else
|
|
temp_iname = iname;
|
|
|
|
// If we're in inherit mode, we need to check for duplicates.
|
|
// Issue a warning.
|
|
|
|
if (Inherit_mode) {
|
|
if (current_class->search_member(temp_iname)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Add it to our C++ class list
|
|
|
|
f = new CPP_function(name,temp_iname,type,l,0,is_virtual);
|
|
f->de = doc_entry;
|
|
current_class->add_member(f);
|
|
|
|
// If this is a pure virtual function, the class is abstract
|
|
|
|
if (is_virtual)
|
|
current_class->is_abstract = 1;
|
|
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_constructor(char *name, char *iname, ParmList *l)
|
|
//
|
|
// Parser entry point for creating a constructor.
|
|
//
|
|
// Inputs :
|
|
// name = Real name of the constructor (usually the same as the class)
|
|
// iname = Renamed version (may be NULL)
|
|
// l = Parameter list
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Adds a constructor to the current class.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_constructor(char *name, char *iname, ParmList *l) {
|
|
|
|
CPP_constructor *c;
|
|
|
|
// May want to check the naming scheme here
|
|
|
|
c = new CPP_constructor(name,iname,l);
|
|
c->de = doc_entry;
|
|
current_class->add_member(c);
|
|
current_class->have_constructor = 1;
|
|
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_destructor(char *name, char *iname)
|
|
//
|
|
// Parser entry point for adding a destructor.
|
|
//
|
|
// Inputs :
|
|
// name = Real name of the destructor (usually same as class name)
|
|
// iname = Renamed version (may be NULL)
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Adds a destructor to the current class
|
|
//
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_destructor(char *name, char *iname) {
|
|
|
|
CPP_destructor *d;
|
|
|
|
d = new CPP_destructor(name,iname);
|
|
d->de = doc_entry;
|
|
current_class->add_member(d);
|
|
current_class->have_destructor = 1;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_variable(char *name, char *iname, DataType *t)
|
|
//
|
|
// Parser entry point for creating a new member variable.
|
|
//
|
|
// Inputs :
|
|
// name = name of the variable
|
|
// iname = Renamed version (may be NULL)
|
|
// t = Datatype
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Adds a member variable to the current class
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_variable(char *name, char *iname, DataType *t) {
|
|
|
|
CPP_variable *v;
|
|
char *temp_iname;
|
|
|
|
// If we're in inherit mode, we need to check for duplicates.
|
|
|
|
if (iname)
|
|
temp_iname = iname;
|
|
else
|
|
temp_iname = name;
|
|
|
|
if (Inherit_mode) {
|
|
if (current_class->search_member(temp_iname)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
v = new CPP_variable(name,iname,t,0);
|
|
v->de = doc_entry;
|
|
current_class->add_member(v);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_static_func(char *name, char *iname, DataType *type, ParmList *l)
|
|
//
|
|
// Parser entry point for creating a new static member function.
|
|
//
|
|
// Inputs :
|
|
// name = Real name of the function
|
|
// iname = Renamed version (may be NULL)
|
|
// type = Return datatype
|
|
// l = Parameter list
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Adds a static function to the current class.
|
|
//
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_static_func(char *name, char *iname, DataType *type, ParmList *l) {
|
|
|
|
char *temp_iname;
|
|
|
|
// If we're in inherit mode, we need to check for duplicates.
|
|
|
|
if (iname) temp_iname = iname;
|
|
else temp_iname = name;
|
|
|
|
if (Inherit_mode) {
|
|
if (current_class->search_member(iname)) {
|
|
// Have a duplication
|
|
return;
|
|
}
|
|
}
|
|
|
|
CPP_function *f = new CPP_function(name, temp_iname, type, l, 1);
|
|
f->de = doc_entry;
|
|
current_class->add_member(f);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_declare_const(char *name, char *iname, DataType *type, char *value)
|
|
//
|
|
// Parser entry point for creating a C++ constant (usually contained in an
|
|
// enum).
|
|
//
|
|
// Inputs :
|
|
// name = Real name of the constant
|
|
// iname = Renamed constant (may be NULL)
|
|
// type = Datatype of the constant
|
|
// value = String representation of the value
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Adds a constant to the current class.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_declare_const(char *name, char *iname, DataType *type, char *value) {
|
|
|
|
char *temp_iname;
|
|
|
|
if (iname) temp_iname = iname;
|
|
else temp_iname = name;
|
|
|
|
// If we're in inherit mode, we need to check for duplicates.
|
|
// Possibly issue a warning or perhaps a remapping
|
|
|
|
if (Inherit_mode) {
|
|
if (current_class->search_member(temp_iname)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
CPP_constant *c = new CPP_constant(name, temp_iname, type, value);
|
|
c->de = doc_entry;
|
|
current_class->add_member(c);
|
|
|
|
// Update this symbol in the symbol table
|
|
update_symbol(name, type, value);
|
|
|
|
// Add this symbol to local scope of a class
|
|
add_local_type(name, current_class->classname);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_static_var(char *name, char *iname, DataType *type)
|
|
//
|
|
// Parser entry point for adding a static variable
|
|
//
|
|
// Inputs :
|
|
// name = Name of the member
|
|
// iname = Renamed version (may be NULL)
|
|
// type = Datatype
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Adds a static variable to the current class.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_static_var(char *name, char *iname, DataType *type) {
|
|
|
|
char *temp_iname;
|
|
|
|
if (iname) temp_iname = iname;
|
|
else temp_iname = name;
|
|
|
|
// If we're in inherit mode, we need to check for duplicates.
|
|
// Possibly issue a warning or perhaps a remapping
|
|
|
|
if (Inherit_mode) {
|
|
if (current_class->search_member(temp_iname)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
CPP_variable *v = new CPP_variable(name, temp_iname, type, 1);
|
|
v->de = doc_entry;
|
|
current_class->add_member(v);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// cplus_add_pragma(char *lang, char *name, char *value)
|
|
//
|
|
// Add a pragma to a class
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_add_pragma(char *lang, char *name, char *value)
|
|
{
|
|
Pragma *pp;
|
|
Pragma *p = new Pragma;
|
|
p->filename = input_file;
|
|
p->lineno = line_number;
|
|
p->lang = lang;
|
|
p->name = name;
|
|
p->value = value;
|
|
|
|
if (!current_class->pragmas) {
|
|
current_class->pragmas = p;
|
|
return;
|
|
}
|
|
pp = current_class->pragmas;
|
|
while (pp->next) {
|
|
pp = pp->next;
|
|
}
|
|
pp->next = p;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// C++/Objective-C code generation functions
|
|
//
|
|
// The following functions are responsible for generating the wrapper functions
|
|
// for C++ and Objective-C methods and variables. These functions are usually
|
|
// called by specific language modules, but individual language modules can
|
|
// choose to do something else.
|
|
//
|
|
// The C++ module sets a number of internal state variables before emitting various
|
|
// pieces of code. These variables are often checked implicitly by these
|
|
// procedures even though nothing is passed on the command line.
|
|
//
|
|
// The code generator tries to be somewhat intelligent about what its doing.
|
|
// The member_hash Hash table keeps track of wrapped members and is used for
|
|
// sharing code between base and derived classes.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
static Hash member_hash; // Hash wrapping member function wrappers to scripting wrappers
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_emit_member_func(char *classname, char *classtype, char *classrename,
|
|
// char *mname, char *mrename, DataType *type,
|
|
// ParmList *l, int mode)
|
|
//
|
|
// This is a generic function to produce a C wrapper around a C++ member function.
|
|
// This function does the following :
|
|
//
|
|
// 1. Create a C wrapper function
|
|
// 2. Wrap the C wrapper function like a normal C function in SWIG
|
|
// 3. Add the function to the scripting language
|
|
// 4. Fill in the documentation entry
|
|
//
|
|
// Specific languages can choose to provide a different mechanism, but this
|
|
// function is used to provide a low-level C++ interface.
|
|
//
|
|
// The mode variable determines whether to create a new function or only to
|
|
// add it to the interpreter. This is used to support the %addmethods directive
|
|
//
|
|
// mode = 0 : Create a wrapper and add it (the normal mode)
|
|
// mode = 1 : Assume wrapper was already made and add it to the
|
|
// interpreter (%addmethods mode)
|
|
//
|
|
// Wrapper functions are usually created as follows :
|
|
//
|
|
// class Foo {
|
|
// int bar(args)
|
|
// }
|
|
//
|
|
// becomes ....
|
|
// Foo_bar(Foo *obj, args) {
|
|
// obj->bar(args);
|
|
// }
|
|
//
|
|
// if %addmethods mode is set AND there is supporting C code detected, make
|
|
// a function from it. The object is always called 'obj'.
|
|
//
|
|
// Then we wrap Foo_bar(). The name "Foo_bar" is actually contained in the parameter
|
|
// cname. This is so language modules can provide their own names (possibly for
|
|
// function overloading).
|
|
//
|
|
// This function makes no internal checks of the SWIG symbol table. This is
|
|
// up to the caller.
|
|
//
|
|
// Objective-C support (added 5/24/97) :
|
|
//
|
|
// If the class member function is part of an objective-C interface, everything
|
|
// works the same except that we change the calling mechanism to issue an
|
|
// Objective-C message.
|
|
//
|
|
// Optimizations (added 12/31/97) :
|
|
//
|
|
// For automatically generated wrapper functions. We now generate macros such
|
|
// as
|
|
// #define Foo_bar(a,b,c) (a->bar(b,c))
|
|
//
|
|
// This should make the wrappers a little faster as well as reducing the amount
|
|
// of wrapper code.
|
|
//
|
|
// Inputs :
|
|
// classname = Name of C++ class
|
|
// classtype = Type of class (struct, union, class)
|
|
// classrename = Renamed class (if any)
|
|
// mname = Member name
|
|
// mrename = Renamed member
|
|
// type = Return type of the function
|
|
// l = Parameter list
|
|
// mode = addmethods mode
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Creates C accessor function in the wrapper file.
|
|
// Calls the language module to create a wrapper function.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_emit_member_func(char *classname, char *classtype, char *classrename,
|
|
char *mname, char *mrename, DataType *type, ParmList *l,
|
|
int mode) {
|
|
Parm *p;
|
|
ParmList *newparms;
|
|
int i;
|
|
String wrap;
|
|
String cname,iname;
|
|
String key;
|
|
String argname;
|
|
char *prefix;
|
|
char *prev_wrap = 0;
|
|
char *temp_mname;
|
|
|
|
cname = "";
|
|
iname = "";
|
|
key = "";
|
|
|
|
// First generate a proper name for the member function
|
|
|
|
// Get the base class of this member
|
|
if (!mrename) temp_mname = mname;
|
|
else temp_mname = mrename;
|
|
|
|
char *bc = cplus_base_class(temp_mname);
|
|
if (!bc) bc = classname;
|
|
if (strlen(bc) == 0) bc = classname;
|
|
|
|
// Generate the name of the C wrapper function (is always the same, regardless
|
|
// of renaming).
|
|
|
|
cname << name_member(mname,bc);
|
|
|
|
// Generate the scripting name of this function
|
|
if (classrename)
|
|
prefix = classrename;
|
|
else
|
|
prefix = classname;
|
|
|
|
if (mrename)
|
|
iname << name_member(mrename,prefix);
|
|
else
|
|
iname << name_member(mname,prefix);
|
|
|
|
// Now check to see if we have already wrapped a function like this.
|
|
// If so, we'll just use the existing wrapper.
|
|
|
|
key << cname << "+";
|
|
l->print_types(key);
|
|
// printf("key = %s\n", (char *) key);
|
|
char *temp = copy_string(iname);
|
|
if ((member_hash.add(key,temp)) == -1) {
|
|
delete [] temp;
|
|
prev_wrap = (char *) member_hash.lookup(key);
|
|
}
|
|
|
|
// Only generate code if an already existing wrapper doesn't exist
|
|
|
|
if (!prev_wrap) {
|
|
|
|
// If mode = 0: Then we go ahead and create a wrapper macro
|
|
|
|
if (!mode) {
|
|
cname = "";
|
|
cname << iname;
|
|
wrap << "#define " << cname << "(_swigobj";
|
|
|
|
// Walk down the parameter list and Spit out arguments
|
|
|
|
i = 0;
|
|
p = l->get_first();
|
|
while (p != 0) {
|
|
if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
|
|
wrap << ",_swigarg" << i;
|
|
i++;
|
|
}
|
|
p = l->get_next();
|
|
}
|
|
|
|
wrap << ") (";
|
|
|
|
if (!ObjCClass) {
|
|
wrap << "_swigobj->" << mname << "("; // C++ invocation
|
|
} else {
|
|
wrap << "[ _swigobj " << mname; // Objective C invocation
|
|
}
|
|
i = 0;
|
|
p = l->get_first();
|
|
while(p != 0) {
|
|
if (ObjCClass) wrap << " " << p->objc_separator;
|
|
if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
|
|
wrap << "_swigarg" << i;
|
|
i++;
|
|
}
|
|
p = l->get_next();
|
|
if ((p != 0) && (!ObjCClass))
|
|
wrap << ",";
|
|
}
|
|
if (!ObjCClass)
|
|
wrap << "))\n";
|
|
else
|
|
wrap << "])\n";
|
|
|
|
// Emit it
|
|
fprintf(f_wrappers,"%s",wrap.get());
|
|
} else {
|
|
if (ccode) {
|
|
wrap << "static ";
|
|
if (type->is_reference) {
|
|
type->is_pointer--;
|
|
}
|
|
wrap << type->print_full();
|
|
if (type->is_reference) {
|
|
wrap << "&";
|
|
type->is_pointer++;
|
|
}
|
|
wrap << " " << cname << "(" << classtype << classname << " *self";
|
|
|
|
// Walk down the parameter list and Spit out arguments
|
|
|
|
p = l->get_first();
|
|
while (p != 0) {
|
|
if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
|
|
wrap << ",";
|
|
if ((p->call_type & CALL_REFERENCE) || (p->t->is_reference)) {
|
|
p->t->is_pointer--;
|
|
}
|
|
wrap << p->t->print_full();
|
|
if ((p->call_type & CALL_REFERENCE) || (p->t->is_reference)) {
|
|
p->t->is_pointer++;
|
|
if (p->t->is_reference)
|
|
wrap << "&";
|
|
}
|
|
wrap << " " << p->name;
|
|
}
|
|
p = l->get_next();
|
|
}
|
|
|
|
wrap << ") " << ccode;
|
|
fprintf(f_wrappers,"%s\n",wrap.get());
|
|
}
|
|
}
|
|
|
|
// Now add a parameter to the beginning of the function and call
|
|
// a language specific function to add it.
|
|
|
|
newparms = new ParmList(l);
|
|
p = new Parm(0,0);
|
|
p->t = new DataType;
|
|
p->t->type = T_USER;
|
|
p->t->is_pointer = 1;
|
|
p->t->id = cpp_id;
|
|
p->call_type = 0;
|
|
|
|
sprintf(p->t->name,"%s%s", classtype,classname);
|
|
p->name = "self";
|
|
newparms->insert(p,0); // Attach parameter to beginning of list
|
|
|
|
// Now wrap the thing. The name of the function is iname
|
|
|
|
lang->create_function(cname, iname, type, newparms);
|
|
delete newparms;
|
|
} else {
|
|
// Already wrapped this function. Just patch it up
|
|
lang->create_command(prev_wrap, iname);
|
|
}
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_emit_static_func(char *classname, char *classtype, char *classrename,
|
|
// char *mname, char *mrename, DataType *type,
|
|
// ParmList *l, int mode)
|
|
//
|
|
// This is a generic function to produce a wrapper for a C++ static member function
|
|
// or an Objective-C class method.
|
|
//
|
|
// Specific languages can choose to provide a different mechanism, but this
|
|
// function is used to provide a low-level C++ interface.
|
|
//
|
|
// The mode variable determines whether to create a new function or only to
|
|
// add it to the interpreter. This is used to support the %addmethods directive
|
|
//
|
|
// mode = 0 : Create a wrapper and add it (the normal mode)
|
|
// mode = 1 : Assume wrapper was already made and add it to the
|
|
// interpreter (%addmethods mode)
|
|
//
|
|
// Wrapper functions are usually created as follows :
|
|
//
|
|
// class Foo {
|
|
// static int bar(args)
|
|
// }
|
|
//
|
|
// becomes a command called Foo_bar()
|
|
//
|
|
// if %addmethods mode is set AND there is supporting C code detected, make
|
|
// a function from it.
|
|
//
|
|
// Then we wrap Foo_bar(). The name "Foo_bar" is actually contained in the parameter
|
|
// cname. This is so language modules can provide their own names (possibly for
|
|
// function overloading).
|
|
//
|
|
// This function makes no internal checks of the SWIG symbol table. This is
|
|
// up to the caller.
|
|
//
|
|
// Inputs :
|
|
// classname = Name of C++ class
|
|
// classtype = Type of class (struct, union, class)
|
|
// classrename = Renamed version of class (optional)
|
|
// mname = Member name
|
|
// mrename = Renamed member (optional)
|
|
// type = Return type of the function
|
|
// l = Parameter list
|
|
// mode = addmethods mode
|
|
//
|
|
// Output : None
|
|
//
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_emit_static_func(char *classname, char *, char *classrename,
|
|
char *mname, char *mrename, DataType *type, ParmList *l,
|
|
int mode) {
|
|
Parm *p;
|
|
String wrap;
|
|
String cname, iname, key;
|
|
int i;
|
|
char *prefix;
|
|
char *prev_wrap = 0;
|
|
char *temp_mname;
|
|
|
|
cname = "";
|
|
iname = "";
|
|
key = "";
|
|
|
|
// Generate a function name for the member function
|
|
|
|
if (!mrename) temp_mname = mname;
|
|
else temp_mname = mrename;
|
|
char *bc = cplus_base_class(temp_mname);
|
|
if (!bc) bc = classname;
|
|
if (strlen(bc) == 0) bc = classname;
|
|
|
|
// Generate the name of the C wrapper function
|
|
if ((!mode) && (!ObjCClass)) {
|
|
cname << bc << "::" << mname;
|
|
} else {
|
|
cname << name_member(mname,bc);
|
|
}
|
|
|
|
// Generate the scripting name of this function
|
|
if (classrename)
|
|
prefix = classrename;
|
|
else
|
|
prefix = classname;
|
|
|
|
if (mrename)
|
|
iname << name_member(mrename,prefix);
|
|
else
|
|
iname << name_member(mname,prefix);
|
|
|
|
// Perform a hash table lookup to see if we've wrapped anything like this before
|
|
|
|
key << cname << "+";
|
|
l->print_types(key);
|
|
char *temp = copy_string(iname);
|
|
if ((member_hash.add(key,temp)) == -1) {
|
|
delete [] temp;
|
|
prev_wrap = (char *) member_hash.lookup(key);
|
|
}
|
|
|
|
if (!prev_wrap) {
|
|
if (!((mode) || (ObjCClass))) {
|
|
// Not an added method and not objective C, just wrap it
|
|
lang->create_function(cname,iname, type, l);
|
|
} else {
|
|
// This is either an added method or an objective C class function
|
|
//
|
|
// If there is attached code, use it.
|
|
// Otherwise, assume the function has been written already and
|
|
// wrap it.
|
|
|
|
wrap << "static " << type->print_full() << " " << cname << "(";
|
|
|
|
// Walk down the parameter list and Spit out arguments
|
|
p = l->get_first();
|
|
while (p != 0) {
|
|
if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
|
|
if (p->t->is_reference) {
|
|
p->t->is_pointer--;
|
|
}
|
|
wrap << p->t->print_full();
|
|
if (p->t->is_reference) {
|
|
p->t->is_pointer++;
|
|
wrap << "&";
|
|
}
|
|
wrap << " " << p->name;
|
|
}
|
|
p = l->get_next();
|
|
if (p) wrap << ",";
|
|
}
|
|
wrap << ") ";
|
|
if ((mode) && (ccode)) {
|
|
wrap << ccode;
|
|
} else if (ObjCClass) {
|
|
// This is an objective-C method
|
|
|
|
wrap << "{\n" << tab4;
|
|
|
|
// Emit the function call.
|
|
|
|
if ((type->type != T_VOID) || (type->is_pointer)) {
|
|
// Declare the return value
|
|
|
|
if (type->is_reference) {
|
|
type->is_pointer--;
|
|
wrap << tab4 << type->print_full() << "& _result = ";
|
|
type->is_pointer++;
|
|
} else {
|
|
wrap << tab4 << type->print_type() << " _result = " << type->print_cast();
|
|
}
|
|
} else {
|
|
wrap << tab4;
|
|
}
|
|
wrap << "[ " << classname << " " << mname; // Objective C invocation
|
|
i = 0;
|
|
p = l->get_first();
|
|
while(p != 0) {
|
|
wrap << " " << p->objc_separator;
|
|
if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
|
|
if (p->t->is_reference) {
|
|
wrap << "*";
|
|
}
|
|
wrap << p->name;
|
|
i++;
|
|
}
|
|
p = l->get_next();
|
|
}
|
|
wrap << "];\n";
|
|
|
|
if ((type->type != T_VOID) || (type->is_pointer)) {
|
|
if (type->is_reference) {
|
|
wrap << tab4 << "return " << type->print_cast() << " &_result;\n";
|
|
} else {
|
|
wrap << tab4 << "return _result;\n";
|
|
}
|
|
}
|
|
wrap << "}\n";
|
|
}
|
|
if (ObjCClass || (mode && ccode))
|
|
fprintf(f_wrappers,"%s\n",wrap.get());
|
|
lang->create_function(cname,iname,type,l);
|
|
}
|
|
} else {
|
|
// Already wrapped this function. Just hook up to it.
|
|
lang->create_command(prev_wrap, iname);
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_emit_destructor(char *classname, char *classtype, char *classrename,
|
|
// char *mname, char *mrename, int mode)
|
|
//
|
|
// Emit a C wrapper around a C++ destructor.
|
|
//
|
|
// Usually this function is used to do the following :
|
|
// class Foo {
|
|
// ...
|
|
// ~Foo();
|
|
// }
|
|
//
|
|
// becomes ....
|
|
// void delete_Foo(Foo *f) {
|
|
// delete f;
|
|
// }
|
|
//
|
|
// Then we wrap delete_Foo().
|
|
//
|
|
// Inputs :
|
|
// classname = Name of the C++ class
|
|
// classtype = Type of class (struct,class,union)
|
|
// classrename = Renamed class (optional)
|
|
// mname = Name of the destructor
|
|
// mrename = Name of the function in the interpreter
|
|
// mode = addmethods mode (0 or 1)
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Creates a destructor function and wraps it.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_emit_destructor(char *classname, char *classtype, char *classrename,
|
|
char *mname, char *mrename, int mode)
|
|
{
|
|
Parm *p;
|
|
DataType *type;
|
|
ParmList *l;
|
|
String wrap;
|
|
String cname,iname;
|
|
char *prefix;
|
|
|
|
// Construct names for the function
|
|
|
|
if (classrename)
|
|
prefix = classrename;
|
|
else
|
|
prefix = classname;
|
|
|
|
cname << name_destroy(classname);
|
|
if (mrename)
|
|
iname << name_destroy(mrename);
|
|
else
|
|
iname << name_destroy(prefix);
|
|
|
|
if (!mode) {
|
|
// Spit out a helper function for this member function
|
|
wrap << "#define " << cname << "(_swigobj) (";
|
|
if (ObjCClass) {
|
|
wrap << "[_swigobj " << mname << "])\n"; // Name of the member is the destructor
|
|
} else if (CPlusPlus)
|
|
wrap << "delete _swigobj)\n";
|
|
else
|
|
wrap << "free ((char *) _swigobj))\n";
|
|
fprintf(f_wrappers,"%s", wrap.get());
|
|
} else {
|
|
if (ccode) {
|
|
wrap << "static void " << cname << "(" << classtype << classname << " *self) " << ccode;
|
|
fprintf(f_wrappers,"%s\n",wrap.get());
|
|
}
|
|
}
|
|
|
|
// Make a parameter list for this function
|
|
|
|
l = new ParmList;
|
|
p = new Parm(0,0);
|
|
p->t = new DataType;
|
|
p->t->type = T_USER;
|
|
p->t->is_pointer = 1;
|
|
p->t->id = cpp_id;
|
|
p->call_type = 0;
|
|
sprintf(p->t->name,"%s%s", classtype, classname);
|
|
p->name = "self";
|
|
l->insert(p,0);
|
|
|
|
type = new DataType;
|
|
type->type = T_VOID;
|
|
sprintf(type->name,"void");
|
|
type->is_pointer = 0;
|
|
type->id = cpp_id;
|
|
|
|
// iname is the desired name of the function in the target language
|
|
|
|
lang->create_function(cname,iname,type,l);
|
|
|
|
delete type;
|
|
delete l;
|
|
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_emit_constructor(char *classname, char *classtype, char *classrename,
|
|
// char *mname, char *mrename, ParmList *l, int mode)
|
|
//
|
|
// Creates a C wrapper around a C++ constructor
|
|
//
|
|
// Inputs :
|
|
// classname = name of class
|
|
// classtype = type of class (struct,class,union)
|
|
// classrename = Renamed class (optional)
|
|
// mname = Name of constructor
|
|
// mrename = Renamed constructor (optional)
|
|
// l = Parameter list
|
|
// mode = addmethods mode
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Creates a C wrapper and calls the language module to wrap it.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_emit_constructor(char *classname, char *classtype, char *classrename,
|
|
char *mname, char *mrename, ParmList *l, int mode)
|
|
{
|
|
Parm *p;
|
|
int i;
|
|
DataType *type;
|
|
String wrap;
|
|
String fcall,cname,iname,argname;
|
|
char *prefix;
|
|
|
|
// Construct names for the function
|
|
|
|
if (classrename)
|
|
prefix = classrename;
|
|
else
|
|
prefix = classname;
|
|
|
|
cname << name_construct(classname);
|
|
if (mrename)
|
|
iname << name_construct(mrename);
|
|
else
|
|
iname << name_construct(prefix);
|
|
|
|
// Create a return type
|
|
|
|
type = new DataType;
|
|
type->type = T_USER;
|
|
sprintf(type->name,"%s%s", classtype,classname);
|
|
type->is_pointer = 1;
|
|
type->id = cpp_id;
|
|
|
|
if (!mode) {
|
|
wrap << "#define " << iname << "(";
|
|
cname = "";
|
|
cname << iname;
|
|
if (ObjCClass) {
|
|
fcall << type->print_cast() << "[" << classname << " " << mname;
|
|
} else if (CPlusPlus) {
|
|
fcall << "new " << classname << "(";
|
|
} else {
|
|
fcall << type->print_cast() << " calloc(1,sizeof("
|
|
<< classtype << classname << "))";
|
|
}
|
|
|
|
// Walk down the parameter list and spit out arguments
|
|
|
|
i = 0;
|
|
p = l->get_first();
|
|
while (p != 0) {
|
|
if (ObjCClass) fcall << " " << p->objc_separator;
|
|
if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
|
|
wrap << "_swigarg" << i;
|
|
|
|
// Emit an argument in the function call if in C++ mode
|
|
|
|
if ((CPlusPlus) || (ObjCClass)) {
|
|
fcall << "_swigarg" << i;
|
|
}
|
|
}
|
|
i++;
|
|
p = l->get_next();
|
|
if (p) {
|
|
wrap << ",";
|
|
if ((CPlusPlus) && (!ObjCClass))
|
|
fcall << ",";
|
|
}
|
|
}
|
|
|
|
wrap << ") ";
|
|
if (ObjCClass) fcall << "]";
|
|
else if (CPlusPlus) fcall << ")";
|
|
|
|
wrap << "(" << fcall << ")\n";
|
|
fprintf(f_wrappers,"%s",wrap.get());
|
|
} else {
|
|
if (ccode) {
|
|
wrap << "static " << classtype << classname << " *" << cname << "(";
|
|
|
|
// Walk down the parameter list and spit out arguments
|
|
|
|
p = l->get_first();
|
|
while (p != 0) {
|
|
if ((p->t->type != T_VOID) || (p->t->is_pointer)) {
|
|
if (p->call_type & CALL_REFERENCE) {
|
|
p->t->is_pointer--;
|
|
}
|
|
wrap << p->t->print_real(p->name);
|
|
if (p->call_type & CALL_REFERENCE) {
|
|
p->t->is_pointer++;
|
|
}
|
|
p = l->get_next();
|
|
if (p) {
|
|
wrap << ",";
|
|
}
|
|
} else {
|
|
p = l->get_next();
|
|
}
|
|
}
|
|
wrap << ") " << ccode << "\n";
|
|
fprintf(f_wrappers,"%s\n",wrap.get());
|
|
}
|
|
}
|
|
|
|
// If we had any C++ references, get rid of them now
|
|
|
|
if (!mode) {
|
|
p = l->get_first();
|
|
while (p) {
|
|
// p->t->is_reference = 0;
|
|
p = l->get_next();
|
|
}
|
|
}
|
|
|
|
// We've now created a C wrapper. We're going to add it to the interpreter
|
|
|
|
lang->create_function(cname, iname, type, l);
|
|
delete type;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_emit_variable_get(char *classname, char *classtype, char *classrename,
|
|
// char *mname, char *mrename, DataType *type, int mode)
|
|
//
|
|
// Writes a C wrapper to extract a data member
|
|
//
|
|
// Usually this function works as follows :
|
|
//
|
|
// class Foo {
|
|
// double x;
|
|
// }
|
|
//
|
|
// becomes :
|
|
//
|
|
// double Foo_x_get(Foo *obj) {
|
|
// return obj->x;
|
|
// }
|
|
//
|
|
// Optimization : 12/31/97
|
|
//
|
|
// Now emits a macro like this :
|
|
//
|
|
// #define Foo_x_get(obj) (obj->x)
|
|
//
|
|
// Inputs :
|
|
// classname = name of C++ class
|
|
// classtype = type of class (struct, class, union)
|
|
// classrename = Renamed class
|
|
// mname = Member name
|
|
// mrename = Renamed member
|
|
// type = Datatype of the member
|
|
// mode = Addmethods mode
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Creates a C accessor function and calls the language module
|
|
// to make a wrapper around it.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_emit_variable_get(char *classname, char *classtype, char *classrename,
|
|
char *mname, char *mrename, DataType *type, int mode) {
|
|
|
|
Parm *p;
|
|
ParmList *l;
|
|
String wrap;
|
|
String cname, iname, key;
|
|
char *prefix;
|
|
char *tm;
|
|
String source;
|
|
char *temp_mname;
|
|
char *prev_wrap = 0;
|
|
|
|
cname = "";
|
|
iname = "";
|
|
key = "";
|
|
|
|
// First generate a proper name for the get function
|
|
|
|
// Get the base class of this member
|
|
if (!mrename) temp_mname = mname;
|
|
else temp_mname = mrename;
|
|
|
|
char *bc = cplus_base_class(temp_mname);
|
|
if (!bc) bc = classname;
|
|
if (strlen(bc) == 0) bc = classname;
|
|
|
|
// Generate the name of the C wrapper function (is always the same, regardless
|
|
// of renaming).
|
|
|
|
cname << name_get(name_member(mname,bc));
|
|
|
|
// Generate the scripting name of this function
|
|
if (classrename)
|
|
prefix = classrename;
|
|
else
|
|
prefix = classname;
|
|
|
|
if (mrename)
|
|
iname << name_get(name_member(mrename,prefix));
|
|
else
|
|
iname << name_get(name_member(mname,prefix));
|
|
|
|
// Now check to see if we have already wrapped a variable like this.
|
|
|
|
key << cname;
|
|
char *temp = copy_string(iname);
|
|
if ((member_hash.add(key,temp)) == -1) {
|
|
delete [] temp;
|
|
prev_wrap = (char *) member_hash.lookup(key);
|
|
}
|
|
|
|
// Only generate code if already existing wrapper doesn't exist
|
|
if (!prev_wrap) {
|
|
if (!mode) {
|
|
// Get any sort of typemap that might exist
|
|
|
|
source << "obj->" << mname;
|
|
|
|
// Now write a function to get the value of the variable
|
|
|
|
tm = typemap_lookup("memberout",typemap_lang,type,mname,source,"result");
|
|
|
|
if ((type->type == T_USER) && (!type->is_pointer)) {
|
|
type->is_pointer++;
|
|
if (tm) {
|
|
wrap << "static " << type->print_type() << " " << cname << "("
|
|
<< classtype << classname << " *obj) {\n"
|
|
<< tab4 << type->print_type() << " result;\n"
|
|
<< tm << "\n"
|
|
<< tab4 << "return result;\n"
|
|
<< "}\n";
|
|
} else {
|
|
wrap << "#define " << cname << "(_swigobj) "
|
|
<< "(&_swigobj->" << mname << ")\n";
|
|
}
|
|
type->is_pointer--;
|
|
} else {
|
|
if (tm) {
|
|
wrap << "static " << type->print_type() << " " << cname << "("
|
|
<< classtype << classname << " *obj) {\n"
|
|
<< tab4 << type->print_type() << " result;\n"
|
|
<< tm << "\n"
|
|
<< tab4 << "return result;\n"
|
|
<< "}\n";
|
|
} else {
|
|
wrap << "#define " << cname << "(_swigobj) (";
|
|
if (!type->is_reference) wrap << type->print_cast();
|
|
else
|
|
wrap << "&";
|
|
wrap << " _swigobj->" << mname << ")\n";
|
|
}
|
|
}
|
|
fprintf(f_wrappers,"%s",wrap.get());
|
|
}
|
|
|
|
// Wrap this function
|
|
|
|
l = new ParmList;
|
|
p = new Parm(0,0);
|
|
p->t = new DataType;
|
|
p->t->type = T_USER;
|
|
p->t->is_pointer = 1;
|
|
p->t->id = cpp_id;
|
|
p->call_type = 0;
|
|
p->name = "self";
|
|
sprintf(p->t->name,"%s%s", classtype,classname);
|
|
l->insert(p,0);
|
|
|
|
if ((type->type == T_USER) && (!type->is_pointer)) {
|
|
type->is_pointer++;
|
|
lang->create_function(cname,iname, type, l);
|
|
type->is_pointer--;
|
|
} else {
|
|
int is_ref = type->is_reference;
|
|
type->is_reference = 0;
|
|
lang->create_function(cname,iname, type, l);
|
|
type->is_reference = is_ref;
|
|
}
|
|
delete l;
|
|
} else {
|
|
// Already wrapped this function. Just patch it up
|
|
lang->create_command(prev_wrap,iname);
|
|
}
|
|
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_emit_variable_set(char *classname, char *classtype, char *mname,
|
|
// char *cname, char *iname, DataType *type, int mode)
|
|
//
|
|
// Writes a C wrapper to set a data member
|
|
//
|
|
// Usually this function works as follows :
|
|
//
|
|
// class Foo {
|
|
// double x;
|
|
// }
|
|
//
|
|
// becomes :
|
|
//
|
|
// double Foo_x_set(Foo *obj, double value) {
|
|
// return (obj->x = value);
|
|
// }
|
|
//
|
|
// Need to handle special cases for char * and for user defined types.
|
|
//
|
|
// 1. char *
|
|
//
|
|
// Will free previous contents (if any) and allocate
|
|
// new storage. Could be risky, but it's a reasonably
|
|
// natural thing to do.
|
|
//
|
|
// 2. User_Defined
|
|
// Will assign value from a pointer.
|
|
// Will return a pointer to current value.
|
|
//
|
|
//
|
|
// Optimization, now defined as a C preprocessor macro
|
|
//
|
|
// Inputs :
|
|
// classname = name of C++ class
|
|
// classtype = type of class (struct, class, union)
|
|
// mname = Member name
|
|
// cname = Name of the C function for this (ie. Foo_bar_get)
|
|
// iname = Interpreter name of ths function
|
|
// type = Datatype of the member
|
|
// mode = Addmethods mode
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Creates a C accessor function and calls the language module
|
|
// to wrap it.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_emit_variable_set(char *classname, char *classtype, char *classrename,
|
|
char *mname, char *mrename, DataType *type, int mode) {
|
|
|
|
Parm *p;
|
|
ParmList *l;
|
|
String wrap;
|
|
int is_user = 0;
|
|
char *tm;
|
|
String target;
|
|
String cname, iname, key;
|
|
char *temp_mname;
|
|
char *prefix;
|
|
char *prev_wrap = 0;
|
|
|
|
cname = "";
|
|
iname = "";
|
|
key = "";
|
|
|
|
// First generate a proper name for the get function
|
|
|
|
// Get the base class of this member
|
|
if (!mrename) temp_mname = mname;
|
|
else temp_mname = mrename;
|
|
|
|
char *bc = cplus_base_class(temp_mname);
|
|
if (!bc) bc = classname;
|
|
if (strlen(bc) == 0) bc = classname;
|
|
|
|
// Generate the name of the C wrapper function (is always the same, regardless
|
|
// of renaming).
|
|
|
|
cname << name_set(name_member(mname,bc));
|
|
|
|
// Generate the scripting name of this function
|
|
if (classrename)
|
|
prefix = classrename;
|
|
else
|
|
prefix = classname;
|
|
|
|
if (mrename)
|
|
iname << name_set(name_member(mrename,prefix));
|
|
else
|
|
iname << name_set(name_member(mname,prefix));
|
|
|
|
// Now check to see if we have already wrapped a variable like this.
|
|
|
|
key << cname;
|
|
char *temp = copy_string(iname);
|
|
if ((member_hash.add(key,temp)) == -1) {
|
|
delete [] temp;
|
|
prev_wrap = (char *) member_hash.lookup(key);
|
|
}
|
|
|
|
// Only generate code if already existing wrapper doesn't exist
|
|
|
|
if (!prev_wrap) {
|
|
if (!mode) {
|
|
|
|
target << "obj->" << mname;
|
|
|
|
// Lookup any typemaps that might exist
|
|
tm = typemap_lookup("memberin",typemap_lang,type,mname,"val",target);
|
|
|
|
// First write a function to set the variable
|
|
|
|
if (tm) {
|
|
if ((type->type == T_USER) && (!type->is_pointer)) {
|
|
type->is_pointer++;
|
|
is_user = 1;
|
|
}
|
|
wrap << "static " << type->print_type() << " " << cname << "("
|
|
<< classtype << classname << " *obj, " << type->print_real("val") << ") {\n";
|
|
if (is_user) {
|
|
type->is_pointer--;
|
|
}
|
|
wrap << tm << "\n";
|
|
// Return the member
|
|
if (is_user) type->is_pointer++;
|
|
wrap << tab4 << "return " << type->print_cast() << " val;\n";
|
|
if (is_user) type->is_pointer--;
|
|
wrap << "}\n";
|
|
|
|
} else {
|
|
if ((type->type != T_VOID) || (type->is_pointer)){
|
|
if (!type->is_pointer) {
|
|
|
|
wrap << "#define " << cname << "(_swigobj,_swigval) (";
|
|
// Have a real value here (ie. not a pointer).
|
|
// If it's a user defined type, we'll do something special.
|
|
// Otherwise, just assign it.
|
|
|
|
if (type->type != T_USER) {
|
|
wrap << "_swigobj->" << mname << " = _swigval";
|
|
} else {
|
|
wrap << "_swigobj->" << mname << " = *(_swigval)";
|
|
}
|
|
wrap << ",_swigval)\n";
|
|
} else {
|
|
// Is a pointer type here. If string, we do something
|
|
// special. Otherwise. No problem.
|
|
if ((type->type == T_CHAR) && (type->is_pointer == 1)) {
|
|
String temp;
|
|
wrap << "static " << type->print_type() << " " << cname << "("
|
|
<< classtype << classname << " *obj, " << type->print_real("val") << ") {\n";
|
|
temp << "obj->" << mname;
|
|
if (CPlusPlus) {
|
|
wrap << tab4 << "if (" << temp << ") delete [] " << temp << ";\n"
|
|
<< tab4 << temp << " = new char[strlen(val)+1];\n"
|
|
<< tab4 << "strcpy((char *)" << temp << ",val);\n";
|
|
} else {
|
|
wrap << tab4 << "if (obj->" << mname << ") free(obj->" << mname << ");\n"
|
|
<< tab4 << "obj->" << mname << " = (char *) malloc(strlen(val)+1);\n"
|
|
<< tab4 << "strcpy((char *)obj->" << mname << ",val);\n";
|
|
}
|
|
wrap << tab4 << "return (char *) val;\n";
|
|
wrap << "}\n";
|
|
} else {
|
|
// A normal pointer type of some sort
|
|
wrap << "#define " << cname << "(_swigobj,_swigval) (";
|
|
if (type->is_reference) {
|
|
wrap << "_swigobj->" << mname << " = *_swigval, _swigval)\n";
|
|
} else {
|
|
wrap << "_swigobj->" << mname << " = _swigval,_swigval)\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fprintf(f_wrappers,"%s",wrap.get());
|
|
// Now wrap it.
|
|
|
|
l = new ParmList;
|
|
p = new Parm(0,0);
|
|
p->t = new DataType(type);
|
|
p->t->is_reference = 0;
|
|
p->call_type = 0;
|
|
p->t->id = cpp_id;
|
|
if ((type->type == T_USER) && (!type->is_pointer)) p->t->is_pointer++;
|
|
if (mrename)
|
|
p->name = mrename;
|
|
else
|
|
p->name = mname;
|
|
l->insert(p,0);
|
|
p = new Parm(0,0);
|
|
p->t = new DataType;
|
|
p->t->type = T_USER;
|
|
p->call_type = 0;
|
|
p->t->is_pointer = 1;
|
|
p->t->id = cpp_id;
|
|
sprintf(p->t->name,"%s%s", classtype,classname);
|
|
p->name = "self";
|
|
l->insert(p,0);
|
|
|
|
if ((type->type == T_USER) && (!type->is_pointer)) {
|
|
type->is_pointer++;
|
|
lang->create_function(cname,iname, type, l);
|
|
type->is_pointer--;
|
|
} else {
|
|
int is_ref = type->is_reference;
|
|
type->is_reference = 0;
|
|
lang->create_function(cname,iname, type, l);
|
|
type->is_reference = is_ref;
|
|
}
|
|
delete l;
|
|
} else {
|
|
lang->create_command(prev_wrap,iname);
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_support_doc(String &f)
|
|
//
|
|
// This function adds a supporting documentation entry to the
|
|
// end of a class. This should only be used if there is an
|
|
// alternative interface available or if additional information is needed.
|
|
//
|
|
// doc_entry should be set to the class entry before calling this. Otherwise,
|
|
// who knows where this text is going to end up!
|
|
//
|
|
// Inputs : f = String with additional text
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects :
|
|
// Adds a text block to the current documentation entry.
|
|
//
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_support_doc(String &f) {
|
|
|
|
DocEntry *de;
|
|
if (doc_entry) {
|
|
de = new DocText(f.get(),doc_entry);
|
|
de->format = 0;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_register_type(char *typename)
|
|
//
|
|
// Registers a datatype name to be associated with the current class. This
|
|
// typename is placed into a local hash table for later use. For example :
|
|
//
|
|
// class foo {
|
|
// public:
|
|
// enum ENUM { ... };
|
|
// typedef double Real;
|
|
// void bar(ENUM a, Real b);
|
|
// }
|
|
//
|
|
// Then we need to access bar using fully qualified type names such as
|
|
//
|
|
// void wrap_bar(foo::ENUM a, foo::Real b) {
|
|
// bar(a,b);
|
|
// }
|
|
//
|
|
// Inputs : name of the datatype.
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects : Adds datatype to localtypes.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_register_type(char *tname) {
|
|
if (current_class)
|
|
add_local_type(tname, current_class->classname);
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_register_scope(Hash *h)
|
|
//
|
|
// Saves the scope associated with a particular class. It will be needed
|
|
// later if anything inherits from us.
|
|
//
|
|
// Inputs : Hash table h containing the scope
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects : Saves h with current class
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_register_scope(Hash *h) {
|
|
if (current_class) {
|
|
current_class->scope = h;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// void cplus_inherit_scope(int count, char **baseclass)
|
|
//
|
|
// Given a list of base classes, this function extracts their former scopes
|
|
// and merges them with the current scope. This is needed to properly handle
|
|
// inheritance.
|
|
//
|
|
// Inputs : baseclass = NULL terminated array of base-class names
|
|
//
|
|
// Output : None
|
|
//
|
|
// Side Effects : Updates current scope with new symbols.
|
|
//
|
|
// Copies any special symbols if needed.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void cplus_inherit_scope(int count, char **baseclass) {
|
|
CPP_class *bc;
|
|
int i;
|
|
char *key, *val;
|
|
String str;
|
|
|
|
if (count && current_class) {
|
|
for (i = 0; i < count; i++) {
|
|
bc = CPP_class::search(baseclass[i]);
|
|
if (bc) {
|
|
if (bc->scope)
|
|
DataType::merge_scope(bc->scope);
|
|
|
|
if (bc->local) {
|
|
// Copy local symbol table
|
|
key = bc->local->firstkey();
|
|
while (key) {
|
|
val = (char *) bc->local->lookup(key);
|
|
str = val;
|
|
// str.replace(bc->classname,current_class->classname);
|
|
localtypes->add(key,copy_string(str));
|
|
key = bc->local->nextkey();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|