blob: 555d0269acb3fcf5dc8c003d43ce61c1607c8f8b [file] [log] [blame]
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* modula3.cxx
*
* Modula3 language module for SWIG.
* ----------------------------------------------------------------------------- */
/*
Text formatted with
indent -sob -br -ce -nut -npsl
*/
/*
Report:
- It's not a good concept to use member variables or global variables
for passing parameters to functions.
It's not a good concept to use functions of superclasses for specific services.
E.g. For SWIG this means: Generating accessor functions for member variables
is the most common but no general task to be processed in membervariableHandler.
Better provide a service function which generates accessor function code
and equip this service function with all parameters needed for input (parse node)
and output (generated code).
- How can I make globalvariableHandler not to generate
interface functions to two accessor functions
(that don't exist) ?
- How can I generate a typemap that turns every C reference argument into
its Modula 3 counterpart, that is
void test(Complex &z);
PROCEDURE test(VAR z:Complex);
- neither $*n_mangle nor $*n_type nor $*n_ltype return the type without
pointer converted to Modula3 equivalent,
$*n_mangle is the variant closest to what I expect
- using a typemap like
typemap(m3wrapintype) int * %{VAR $1_name: INTEGER%}
has the advantages:
- one C parameter can be turned into multiple M3 parameters
- the argument can be renamed
- using typemaps like
typemap(m3wrapinmode) int * "VAR"
typemap(m3wrapintype) int * "INTEGER"
has the advantages:
- multiple parameters with same type and default value can be bundled
- more conform to the other language modules
- Where takes the reduction of multi-typemaps place?
How can I preserve all parameters for functions of the intermediary class?
The answer is Getattrs(n,"tmap:m3rawintype:next")
- Char() can be used to transform a String to (char *)
which can be used for output with printf
- What is the while (checkAttribute()) loop in functionWrapper good for?
Appearently for skipping (numinputs=0) typemaps.
- SWIGTYPE const * - typemap is ignored, whereas
SWIGTYPE * - typemap is invoked, why?
Had it been (const SWIGTYPE *) instead?
- enumeration items should definitely be equipped
with its plain numerical value
One could add tag 'numvalue' in CParse/parser.y,
but it is still possible that someone declares an
enumeration using a symbolic constant.
I have quickly hacked
that the successive number is assigned
if "enumvalue" has suffix "+1".
The ultimate solution would be to generate a C program
which includes the header and outputs all constants.
This program might be compiled and run
by 'make' or by SWIG and the resulting output is fed back to SWIG.
- It's a bad idea to interpret feature value ""
'disable feature' because the value ""
might be sensible in case of feature:modula3:oldprefix.
- What's the difference between "sym:name" and "name" ?
"name" is the original name and
"sym:name" is probably modified by the user using %rename
- Is it possible for 'configure' to find out if m3pp is installed
and to invoke it for generated Modula3 files?
- It would be better to separate an arguments purpose and its name,
because an output variable with name "OUTPUT" is not very descriptive.
In case of PLPlot this could be solved by typedefs
that assign special purposes to the array types.
- Can one interpret $n_basetype as the identifier matched with SWIGTYPE ?
SWIG's odds:
- arguments of type (Node *) for SWIG functions
should be most often better (const Node *):
Swig_symbol_qualified, Getattr, nodeType, parentNode
- unique identifier style instead of
NewString, Getattr, firstChild
- 'class'.name is qualified,
'enum'.name and 'enumitem'.name is not
- Swig_symbol_qualified() returns NIL for enumeration nodes
- Is there a function that creates a C representation of a SWIG type string?
ToDo:
- create WeakRefs only for resources returned by function marked with %newobject
-> part of output conversion
- clean typemap conception
- should a multi-typemap for m3wrapouttype skip the corresponding input parameters?
when yes - How to handle inout-arguments? In this case like in-argument.
- C++ classes
- C++ exceptions
- allow for moving RECORD and OBJECT definitions
to separate files, with the main type called T
- call-back functions
- special option: fast access to class members by pointer arithmetic,
member offsets can be determined by a C++ program that print them.
- emit enumeration definitions when its first item is declared,
currently enumerations are emitted at the beginning of the file
Done:
- addThrow should convert the typemap by itself
- not possible because routine for attaching mapped types to parameter nodes
won't work for the function node
- turning error codes into exceptions
-> part of output value checking
- create WeakRefs for resources allocated by the library
-> part of output conversion
- TRY..FINALLY..END; can be omitted
- if there is no m3wrapfreearg
- no exception can be raised in the body (empty RAISES) list
*/
#include "swigmod.h"
#include <limits.h> // for INT_MAX
#include <ctype.h>
#define USAGE_ARG_DIR "m3wrapargdir typemap expect values: in, out, inout\n"
class MODULA3:public Language {
public:
enum block_type { no_block, constant, variable, blocktype, revelation };
private:
struct M3File {
String *f;
Hash *import;
block_type bt;
/* VC++ 6 doesn't allow the access to 'no_block'
if it is a private member of MODULA3 class */
M3File():f(NewString("")), import(NewHash()), bt(no_block) {
}
~M3File() {
Delete(f);
Delete(import);
}
/* -----------------------------------------------------------------------------
* enterBlock()
*
* Make sure that a given declaration is written to the right declaration block,
* that is constants are written after "CONST" and so on ...
* ----------------------------------------------------------------------------- */
void enterBlock(block_type newbt) {
static const char *ident[] = { "", "\nCONST\n", "\nVAR\n", "\nTYPE\n", "\nREVEAL\n" };
#ifdef DEBUG
if ((bt < 0) || (4 < bt)) {
printf("bt %d out of range\n", bt);
}
#endif
if (newbt != bt) {
Append(f, ident[newbt]);
bt = newbt;
}
}
};
static const char *usage;
const String *empty_string;
Hash *swig_types_hash;
File *f_begin;
File *f_runtime;
File *f_header;
File *f_wrappers;
File *f_init;
bool proxy_flag; // Flag for generating proxy classes
bool have_default_constructor_flag;
bool native_function_flag; // Flag for when wrapping a native function
bool enum_constant_flag; // Flag for when wrapping an enum or constant
bool static_flag; // Flag for when wrapping a static functions or member variables
bool variable_wrapper_flag; // Flag for when wrapping a nonstatic member variable
bool wrapping_member_flag; // Flag for when wrapping a member variable/enum/const
bool global_variable_flag; // Flag for when wrapping a global variable
bool old_variable_names; // Flag for old style variable names in the intermediary class
bool unsafe_module;
String *m3raw_name; // raw interface name
M3File m3raw_intf; // raw interface
M3File m3raw_impl; // raw implementation (usually empty)
String *m3wrap_name; // wrapper module
M3File m3wrap_intf;
M3File m3wrap_impl;
String *m3makefile;
String *targetlibrary;
String *proxy_class_def;
String *proxy_class_code;
String *proxy_class_name;
String *variable_name; //Name of a variable being wrapped
String *variable_type; //Type of this variable
Hash *enumeration_coll; //Collection of all enumerations.
/* The items are nodes with members:
"items" - hash of with key 'itemname' and content 'itemvalue'
"max" - maximum value in item list
*/
String *constant_values;
String *constantfilename;
String *renamefilename;
String *typemapfilename;
String *m3raw_imports; //intermediary class imports from %pragma
String *module_imports; //module imports from %pragma
String *m3raw_baseclass; //inheritance for intermediary class class from %pragma
String *module_baseclass; //inheritance for module class from %pragma
String *m3raw_interfaces; //interfaces for intermediary class class from %pragma
String *module_interfaces; //interfaces for module class from %pragma
String *m3raw_class_modifiers; //class modifiers for intermediary class overridden by %pragma
String *m3wrap_modifiers; //class modifiers for module class overridden by %pragma
String *upcasts_code; //C++ casts for inheritance hierarchies C++ code
String *m3raw_cppcasts_code; //C++ casts up inheritance hierarchies intermediary class code
String *destructor_call; //C++ destructor call if any
String *outfile;
enum type_additions { none, pointer, reference };
public:
/* -----------------------------------------------------------------------------
* MODULA3()
* ----------------------------------------------------------------------------- */
MODULA3():
empty_string(NewString("")),
swig_types_hash(NULL),
f_begin(NULL),
f_runtime(NULL),
f_header(NULL),
f_wrappers(NULL),
f_init(NULL),
proxy_flag(true),
have_default_constructor_flag(false),
native_function_flag(false),
enum_constant_flag(false),
static_flag(false),
variable_wrapper_flag(false),
wrapping_member_flag(false),
global_variable_flag(false),
old_variable_names(false),
unsafe_module(false),
m3raw_name(NULL),
m3raw_intf(),
m3raw_impl(),
m3wrap_name(NULL),
m3wrap_intf(),
m3wrap_impl(),
m3makefile(NULL),
targetlibrary(NULL),
proxy_class_def(NULL),
proxy_class_code(NULL),
proxy_class_name(NULL),
variable_name(NULL),
variable_type(NULL),
enumeration_coll(NULL),
constant_values(NULL),
constantfilename(NULL),
renamefilename(NULL),
typemapfilename(NULL),
m3raw_imports(NULL),
module_imports(NULL),
m3raw_baseclass(NULL),
module_baseclass(NULL),
m3raw_interfaces(NULL),
module_interfaces(NULL),
m3raw_class_modifiers(NULL),
m3wrap_modifiers(NULL),
upcasts_code(NULL),
m3raw_cppcasts_code(NULL),
destructor_call(NULL),
outfile(NULL) {
}
/************** some utility functions ***************/
/* -----------------------------------------------------------------------------
* getMappedType()
*
* Return the type of 'p' mapped by 'map'.
* Print a standard warning if 'p' can't be mapped.
* ----------------------------------------------------------------------------- */
String *getMappedType(Node *p, const char *map) {
String *mapattr = NewString("tmap:");
Append(mapattr, map);
String *tm = Getattr(p, mapattr);
if (tm == NIL) {
Swig_warning(WARN_MODULA3_TYPEMAP_TYPE_UNDEF, input_file, line_number,
"No '%s' typemap defined for type '%s'\n", map, SwigType_str(Getattr(p, "type"), 0));
}
Delete(mapattr);
return tm;
}
/* -----------------------------------------------------------------------------
* getMappedTypeNew()
*
* Similar to getMappedType but uses Swig_type_lookup_new.
* ----------------------------------------------------------------------------- */
String *getMappedTypeNew(Node *n, const char *map, const char *lname = "", bool warn = true) {
String *tm = Swig_typemap_lookup(map, n, lname, 0);
if ((tm == NIL) && warn) {
Swig_warning(WARN_MODULA3_TYPEMAP_TYPE_UNDEF, input_file, line_number,
"No '%s' typemap defined for type '%s'\n", map, SwigType_str(Getattr(n, "type"), 0));
}
return tm;
}
/* -----------------------------------------------------------------------------
* attachMappedType()
*
* Obtain the type mapped by 'map' and attach it to the node
* ----------------------------------------------------------------------------- */
void attachMappedType(Node *n, const char *map, const char *lname = "") {
String *tm = Swig_typemap_lookup(map, n, lname, 0);
if (tm != NIL) {
String *attr = NewStringf("tmap:%s", map);
Setattr(n, attr, tm);
Delete(attr);
}
}
/* -----------------------------------------------------------------------------
* skipIgnored()
*
* Skip all parameters that have 'numinputs=0'
* with respect to a given typemap.
* ----------------------------------------------------------------------------- */
Node *skipIgnored(Node *p, const char *map) {
String *niattr = NewStringf("tmap:%s:numinputs", map);
String *nextattr = NewStringf("tmap:%s:next", map);
while ((p != NIL) && checkAttribute(p, niattr, "0")) {
p = Getattr(p, nextattr);
}
Delete(nextattr);
Delete(niattr);
return p;
}
/* -----------------------------------------------------------------------------
* isInParam()
* isOutParam()
*
* Check if the parameter is intended for input or for output.
* ----------------------------------------------------------------------------- */
bool isInParam(Node *p) {
String *dir = Getattr(p, "tmap:m3wrapargdir");
//printf("dir for %s: %s\n", Char(Getattr(p,"name")), Char(dir));
if ((dir == NIL) || (Strcmp(dir, "in") == 0)
|| (Strcmp(dir, "inout") == 0)) {
return true;
} else if (Strcmp(dir, "out") == 0) {
return false;
} else {
printf("%s", USAGE_ARG_DIR);
return false;
}
}
bool isOutParam(Node *p) {
String *dir = Getattr(p, "tmap:m3wrapargdir");
if ((dir == NIL) || (Strcmp(dir, "in") == 0)) {
return false;
} else if ((Strcmp(dir, "out") == 0) || (Strcmp(dir, "inout") == 0)) {
return true;
} else {
printf("%s", USAGE_ARG_DIR);
return false;
}
}
/* -----------------------------------------------------------------------------
* printAttrs()
*
* For debugging: Show all attributes of a node and their values.
* ----------------------------------------------------------------------------- */
void printAttrs(Node *n) {
Iterator it;
for (it = First(n); it.key != NIL; it = Next(it)) {
printf("%s = %s\n", Char(it.key), Char(Getattr(n, it.key)));
}
}
/* -----------------------------------------------------------------------------
* hasPrefix()
*
* Check if a string have a given prefix.
* ----------------------------------------------------------------------------- */
bool hasPrefix(const String *str, const String *prefix) {
int len_prefix = Len(prefix);
return (Len(str) > len_prefix)
&& (Strncmp(str, prefix, len_prefix) == 0);
}
/* -----------------------------------------------------------------------------
* getQualifiedName()
*
* Return fully qualified identifier of n.
* ----------------------------------------------------------------------------- */
#if 0
// Swig_symbol_qualified returns NIL for enumeration nodes
String *getQualifiedName(Node *n) {
String *qual = Swig_symbol_qualified(n);
String *name = Getattr(n, "name");
if (hasContent(qual)) {
return NewStringf("%s::%s", qual, name);
} else {
return name;
}
}
#else
String *getQualifiedName(Node *n) {
String *name = Copy(Getattr(n, "name"));
n = parentNode(n);
while (n != NIL) {
const String *type = nodeType(n);
if ((Strcmp(type, "class") == 0) || (Strcmp(type, "struct") == 0) || (Strcmp(type, "namespace") == 0)) {
String *newname = NewStringf("%s::%s", Getattr(n, "name"), name);
Delete(name);
//name = newname;
// Hmpf, the class name is already qualified.
return newname;
}
n = parentNode(n);
}
//printf("qualified name: %s\n", Char(name));
return name;
}
#endif
/* -----------------------------------------------------------------------------
* nameToModula3()
*
* Turn usual C identifiers like "this_is_an_identifier"
* into usual Modula 3 identifier like "thisIsAnIdentifier"
* ----------------------------------------------------------------------------- */
String *nameToModula3(const String *sym, bool leadingCap) {
int len_sym = Len(sym);
char *csym = Char(sym);
char *m3sym = new char[len_sym + 1];
int i, j;
bool cap = leadingCap;
for (i = 0, j = 0; j < len_sym; j++) {
char c = csym[j];
if ((c == '_') || (c == ':')) {
cap = true;
} else {
if (isdigit(c)) {
m3sym[i] = c;
cap = true;
} else {
if (cap) {
m3sym[i] = (char)toupper(c);
} else {
m3sym[i] = (char)tolower(c);
}
cap = false;
}
i++;
}
}
m3sym[i] = 0;
String *result = NewString(m3sym);
delete[]m3sym;
return result;
}
/* -----------------------------------------------------------------------------
* capitalizeFirst()
*
* Make the first character upper case.
* ----------------------------------------------------------------------------- */
String *capitalizeFirst(const String *str) {
return NewStringf("%c%s", toupper(*Char(str)), Char(str) + 1);
}
/* -----------------------------------------------------------------------------
* prefixedNameToModula3()
*
* If feature modula3:oldprefix and modula3:newprefix is present
* and the C identifier has leading 'oldprefix'
* then it is replaced by the 'newprefix'.
* The rest is converted to Modula style.
* ----------------------------------------------------------------------------- */
String *prefixedNameToModula3(Node *n, const String *sym, bool leadingCap) {
String *oldPrefix = Getattr(n, "feature:modula3:oldprefix");
String *newPrefix = Getattr(n, "feature:modula3:newprefix");
String *result = NewString("");
char *short_sym = Char(sym);
// if at least one prefix feature is present
// the replacement takes place
if ((oldPrefix != NIL) || (newPrefix != NIL)) {
if ((oldPrefix == NIL) || hasPrefix(sym, oldPrefix)) {
short_sym += Len(oldPrefix);
if (newPrefix != NIL) {
Append(result, newPrefix);
}
}
}
String *suffix = nameToModula3(short_sym, leadingCap || hasContent(newPrefix));
Append(result, suffix);
Delete(suffix);
return result;
}
/* -----------------------------------------------------------------------------
* hasContent()
*
* Check if the string exists and contains something.
* ----------------------------------------------------------------------------- */
bool hasContent(const String *str) {
return (str != NIL) && (Strcmp(str, "") != 0);
}
/* -----------------------------------------------------------------------------
* openWriteFile()
*
* Caution: The file must be freshly allocated and will be destroyed
* by this routine.
* ----------------------------------------------------------------------------- */
File *openWriteFile(String *name) {
File *file = NewFile(name, "w", SWIG_output_files());
if (!file) {
FileErrorDisplay(name);
SWIG_exit(EXIT_FAILURE);
}
Delete(name);
return file;
}
/* -----------------------------------------------------------------------------
* aToL()
*
* like atol but with additional user warning
* ----------------------------------------------------------------------------- */
long aToL(const String *value) {
char *endptr;
long numvalue = strtol(Char(value), &endptr, 0);
if (*endptr != 0) {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "The string <%s> does not denote a numeric value.\n", value);
}
return numvalue;
}
/* -----------------------------------------------------------------------------
* strToL()
*
* like strtol but returns if the conversion was successful
* ----------------------------------------------------------------------------- */
bool strToL(const String *value, long &numvalue) {
char *endptr;
numvalue = strtol(Char(value), &endptr, 0);
return (*endptr == 0);
}
/* -----------------------------------------------------------------------------
* evalExpr()
*
* Evaluate simple expression as they may occur in "enumvalue" attributes.
* ----------------------------------------------------------------------------- */
bool evalExpr(String *value, long &numvalue) {
// Split changes file status of String and thus cannot receive 'const' strings
//printf("evaluate <%s>\n", Char(value));
List *summands = Split(value, '+', INT_MAX);
Iterator sm = First(summands);
numvalue = 0;
for (; sm.item != NIL; sm = Next(sm)) {
String *smvalue = Getattr(constant_values, sm.item);
long smnumvalue;
if (smvalue != NIL) {
if (!strToL(smvalue, smnumvalue)) {
//printf("evaluation: abort 0 <%s>\n", Char(smvalue));
return false;
}
} else {
if (!strToL(sm.item, smnumvalue)) {
//printf("evaluation: abort 1 <%s>\n", Char(sm));
return false;
}
}
numvalue += smnumvalue;
}
//printf("evaluation: return %ld\n", numvalue);
return true;
}
/* -----------------------------------------------------------------------------
* log2()
*
* Determine the position of the single bit of a power of two.
* Returns true if the given number is a power of two.
* ----------------------------------------------------------------------------- */
bool log2(long n, long &exp) {
exp = 0;
while (n > 0) {
if ((n & 1) != 0) {
return n == 1;
}
exp++;
n >>= 1;
}
return false;
}
/* -----------------------------------------------------------------------------
* writeArg
*
* Write a function argument or RECORD entry definition.
* Bundles arguments of same type and default value.
* 'name.next==NIL' denotes the end of the entry or argument list.
* ----------------------------------------------------------------------------- */
bool equalNilStr(const String *str0, const String *str1) {
if (str0 == NIL) {
return (str1 == NIL);
//return (str0==NIL) == (str1==NIL);
} else {
return (str1 != NIL) && (Cmp(str0, str1) == 0);
//return Cmp(str0,str1)==0;
}
}
struct writeArgState {
String *mode, *name, *type, *value;
bool hold;
writeArgState():mode(NIL), name(NIL), type(NIL), value(NIL), hold(false) {
}
};
void writeArg(File *f, writeArgState & state, String *mode, String *name, String *type, String *value) {
/* skip the first argument,
only store the information for the next call in this case */
if (state.name != NIL) {
if ((!state.hold) && (state.mode != NIL)) {
Printf(f, "%s ", state.mode);
}
if ((name != NIL) && equalNilStr(state.mode, mode) && equalNilStr(state.type, type) && (state.value == NIL) && (value == NIL)
/* the same expression may have different values
due to side effects of the called function */
/*equalNilStr(state.value,value) */
) {
Printf(f, "%s, ", state.name);
state.hold = true;
} else {
Append(f, state.name);
if (state.type != NIL) {
Printf(f, ": %s", state.type);
}
if (state.value != NIL) {
Printf(f, ":= %s", state.value);
}
Append(f, ";\n");
state.hold = false;
}
}
/* at the next call the current argument will be the previous one */
state.mode = mode;
state.name = name;
state.type = type;
state.value = value;
}
/* -----------------------------------------------------------------------------
* getProxyName()
*
* Test to see if a type corresponds to something wrapped with a proxy class
* Return NULL if not otherwise the proxy class name
* ----------------------------------------------------------------------------- */
String *getProxyName(SwigType *t) {
if (proxy_flag) {
Node *n = classLookup(t);
if (n) {
return Getattr(n, "sym:name");
}
}
return NULL;
}
/*************** language processing ********************/
/* ------------------------------------------------------------
* main()
* ------------------------------------------------------------ */
virtual void main(int argc, char *argv[]) {
SWIG_library_directory("modula3");
// Look for certain command line options
for (int i = 1; i < argc; i++) {
if (argv[i]) {
if (strcmp(argv[i], "-generateconst") == 0) {
if (argv[i + 1]) {
constantfilename = NewString(argv[i + 1]);
Swig_mark_arg(i);
Swig_mark_arg(i + 1);
i++;
} else {
Swig_arg_error();
}
} else if (strcmp(argv[i], "-generaterename") == 0) {
if (argv[i + 1]) {
renamefilename = NewString(argv[i + 1]);
Swig_mark_arg(i);
Swig_mark_arg(i + 1);
i++;
} else {
Swig_arg_error();
}
} else if (strcmp(argv[i], "-generatetypemap") == 0) {
if (argv[i + 1]) {
typemapfilename = NewString(argv[i + 1]);
Swig_mark_arg(i);
Swig_mark_arg(i + 1);
i++;
} else {
Swig_arg_error();
}
} else if (strcmp(argv[i], "-noproxy") == 0) {
Swig_mark_arg(i);
proxy_flag = false;
} else if (strcmp(argv[i], "-oldvarnames") == 0) {
Swig_mark_arg(i);
old_variable_names = true;
} else if (strcmp(argv[i], "-help") == 0) {
Printf(stdout, "%s\n", usage);
}
}
}
// Add a symbol to the parser for conditional compilation
Preprocessor_define("SWIGMODULA3 1", 0);
// Add typemap definitions
SWIG_typemap_lang("modula3");
SWIG_config_file("modula3.swg");
allow_overloading();
}
/* ---------------------------------------------------------------------
* top()
* --------------------------------------------------------------------- */
virtual int top(Node *n) {
if (hasContent(constantfilename) || hasContent(renamefilename) || hasContent(typemapfilename)) {
int result = SWIG_OK;
if (hasContent(constantfilename)) {
result = generateConstantTop(n) && result;
}
if (hasContent(renamefilename)) {
result = generateRenameTop(n) && result;
}
if (hasContent(typemapfilename)) {
result = generateTypemapTop(n) && result;
}
return result;
} else {
return generateM3Top(n);
}
}
void scanConstant(File *file, Node *n) {
Node *child = firstChild(n);
while (child != NIL) {
String *constname = NIL;
String *type = nodeType(child);
if ((Strcmp(type, "enumitem") == 0)
|| (Strcmp(type, "constant") == 0)) {
#if 1
constname = getQualifiedName(child);
#else
constname = Getattr(child, "value");
if ((!hasContent(constname))
|| (('0' <= *Char(constname)) && (*Char(constname) <= '9'))) {
constname = Getattr(child, "name");
}
#endif
}
if (constname != NIL) {
Printf(file, " printf(\"%%%%constnumeric(%%Lg) %s;\\n\", (long double)%s);\n", constname, constname);
}
scanConstant(file, child);
child = nextSibling(child);
}
}
int generateConstantTop(Node *n) {
File *file = openWriteFile(NewStringf("%s.c", constantfilename));
if (CPlusPlus) {
Printf(file, "#include <cstdio>\n");
} else {
Printf(file, "#include <stdio.h>\n");
}
Printf(file, "#include \"%s\"\n", input_file);
Printf(file, "\n");
Printf(file, "int main (int argc, char *argv[]) {\n");
Printf(file, "\
/*This program must work for floating point numbers and integers.\n\
Thus all numbers are converted to double precision floating point format.*/\n");
scanConstant(file, n);
Printf(file, " return 0;\n");
Printf(file, "}\n");
Delete(file);
return SWIG_OK;
}
void scanRename(File *file, Node *n) {
Node *child = firstChild(n);
while (child != NIL) {
String *type = nodeType(child);
if (Strcmp(type, "cdecl") == 0) {
ParmList *p = Getattr(child, "parms");
if (p != NIL) {
String *name = getQualifiedName(child);
String *m3name = nameToModula3(name, true);
/*don't know how to get the original C type identifiers */
//String *arguments = createCSignature (child);
Printf(file, "%%rename(\"%s\") %s;\n", m3name, name);
/*Printf(file, "%%rename(\"%s\") %s %s(%s);\n",
m3name, Getattr(n,"type"), name, arguments); */
Delete(name);
Delete(m3name);
//Delete (arguments);
}
}
scanRename(file, child);
child = nextSibling(child);
}
}
int generateRenameTop(Node *n) {
File *file = openWriteFile(NewStringf("%s.i", renamefilename));
Printf(file, "\
/* This file was generated from %s\n\
by SWIG with option -generaterename. */\n\
\n", input_file);
scanRename(file, n);
Delete(file);
return SWIG_OK;
}
void scanTypemap(File *file, Node *n) {
Node *child = firstChild(n);
while (child != NIL) {
String *type = nodeType(child);
//printf("nodetype %s\n", Char(type));
String *storage = Getattr(child, "storage");
if ((Strcmp(type, "class") == 0) || ((Strcmp(type, "cdecl") == 0) && (storage != NIL)
&& (Strcmp(storage, "typedef") == 0))) {
String *name = getQualifiedName(child);
String *m3name = nameToModula3(name, true);
Printf(file, "%%typemap(\"m3wrapintype\") %s %%{%s%%}\n", name, m3name);
Printf(file, "%%typemap(\"m3rawintype\") %s %%{%s%%}\n", name, m3name);
Printf(file, "\n");
}
scanTypemap(file, child);
child = nextSibling(child);
}
}
int generateTypemapTop(Node *n) {
File *file = openWriteFile(NewStringf("%s.i", typemapfilename));
Printf(file, "\
/* This file was generated from %s\n\
by SWIG with option -generatetypemap. */\n\
\n", input_file);
scanTypemap(file, n);
Delete(file);
return SWIG_OK;
}
int generateM3Top(Node *n) {
/* Initialize all of the output files */
outfile = Getattr(n, "outfile");
f_begin = NewFile(outfile, "w", SWIG_output_files());
if (!f_begin) {
FileErrorDisplay(outfile);
SWIG_exit(EXIT_FAILURE);
}
f_runtime = NewString("");
f_init = NewString("");
f_header = NewString("");
f_wrappers = NewString("");
m3makefile = NewString("");
/* Register file targets with the SWIG file handler */
Swig_register_filebyname("header", f_header);
Swig_register_filebyname("wrapper", f_wrappers);
Swig_register_filebyname("begin", f_begin);
Swig_register_filebyname("runtime", f_runtime);
Swig_register_filebyname("init", f_init);
Swig_register_filebyname("m3rawintf", m3raw_intf.f);
Swig_register_filebyname("m3rawimpl", m3raw_impl.f);
Swig_register_filebyname("m3wrapintf", m3wrap_intf.f);
Swig_register_filebyname("m3wrapimpl", m3wrap_impl.f);
Swig_register_filebyname("m3makefile", m3makefile);
swig_types_hash = NewHash();
String *name = Getattr(n, "name");
// Make the intermediary class and module class names. The intermediary class name can be set in the module directive.
Node *optionsnode = Getattr(Getattr(n, "module"), "options");
if (optionsnode != NIL) {
String *m3raw_name_tmp = Getattr(optionsnode, "m3rawname");
if (m3raw_name_tmp != NIL) {
m3raw_name = Copy(m3raw_name_tmp);
}
}
if (m3raw_name == NIL) {
m3raw_name = NewStringf("%sRaw", name);
}
Setattr(m3wrap_impl.import, m3raw_name, "");
m3wrap_name = Copy(name);
proxy_class_def = NewString("");
proxy_class_code = NewString("");
m3raw_baseclass = NewString("");
m3raw_interfaces = NewString("");
m3raw_class_modifiers = NewString(""); // package access only to the intermediary class by default
m3raw_imports = NewString("");
m3raw_cppcasts_code = NewString("");
m3wrap_modifiers = NewString("public");
module_baseclass = NewString("");
module_interfaces = NewString("");
module_imports = NewString("");
upcasts_code = NewString("");
Swig_banner(f_begin);
Printf(f_runtime, "\n\n#ifndef SWIGMODULA3\n#define SWIGMODULA3\n#endif\n\n");
Swig_name_register("wrapper", "Modula3_%f");
if (old_variable_names) {
Swig_name_register("set", "set_%n%v");
Swig_name_register("get", "get_%n%v");
}
Printf(f_wrappers, "\n#ifdef __cplusplus\n");
Printf(f_wrappers, "extern \"C\" {\n");
Printf(f_wrappers, "#endif\n\n");
constant_values = NewHash();
scanForConstPragmas(n);
enumeration_coll = NewHash();
collectEnumerations(enumeration_coll, n);
/* Emit code */
Language::top(n);
// Generate m3makefile
// This will be unnecessary if SWIG is invoked from Quake.
{
File *file = openWriteFile(NewStringf("%sm3makefile", SWIG_output_directory()));
Printf(file, "%% automatically generated quake file for %s\n\n", name);
/* Write the fragments written by '%insert'
collected while 'top' processed the parse tree */
Printv(file, m3makefile, NIL);
Printf(file, "import(\"libm3\")\n");
//Printf(file, "import_lib(\"%s\",\"/usr/lib\")\n", name);
Printf(file, "module(\"%s\")\n", m3raw_name);
Printf(file, "module(\"%s\")\n\n", m3wrap_name);
if (targetlibrary != NIL) {
Printf(file, "library(\"%s\")\n", targetlibrary);
} else {
Printf(file, "library(\"m3%s\")\n", name);
}
Delete(file);
}
// Generate the raw interface
{
File *file = openWriteFile(NewStringf("%s%s.i3", SWIG_output_directory(), m3raw_name));
emitBanner(file);
Printf(file, "INTERFACE %s;\n\n", m3raw_name);
emitImportStatements(m3raw_intf.import, file);
Printf(file, "\n");
// Write the interface generated within 'top'
Printv(file, m3raw_intf.f, NIL);
Printf(file, "\nEND %s.\n", m3raw_name);
Delete(file);
}
// Generate the raw module
{
File *file = openWriteFile(NewStringf("%s%s.m3", SWIG_output_directory(), m3raw_name));
emitBanner(file);
Printf(file, "MODULE %s;\n\n", m3raw_name);
emitImportStatements(m3raw_impl.import, file);
Printf(file, "\n");
// will be empty usually
Printv(file, m3raw_impl.f, NIL);
Printf(file, "BEGIN\nEND %s.\n", m3raw_name);
Delete(file);
}
// Generate the interface for the comfort wrappers
{
File *file = openWriteFile(NewStringf("%s%s.i3", SWIG_output_directory(), m3wrap_name));
emitBanner(file);
Printf(file, "INTERFACE %s;\n", m3wrap_name);
emitImportStatements(m3wrap_intf.import, file);
Printf(file, "\n");
{
Iterator it = First(enumeration_coll);
if (it.key != NIL) {
Printf(file, "TYPE\n");
}
for (; it.key != NIL; it = Next(it)) {
Printf(file, "\n");
emitEnumeration(file, it.key, it.item);
}
}
// Add the wrapper methods
Printv(file, m3wrap_intf.f, NIL);
// Finish off the class
Printf(file, "\nEND %s.\n", m3wrap_name);
Delete(file);
}
// Generate the wrapper routines implemented in Modula 3
{
File *file = openWriteFile(NewStringf("%s%s.m3", SWIG_output_directory(), m3wrap_name));
emitBanner(file);
if (unsafe_module) {
Printf(file, "UNSAFE ");
}
Printf(file, "MODULE %s;\n\n", m3wrap_name);
emitImportStatements(m3wrap_impl.import, file);
Printf(file, "\n");
// Add the wrapper methods
Printv(file, m3wrap_impl.f, NIL);
Printf(file, "\nBEGIN\nEND %s.\n", m3wrap_name);
Delete(file);
}
if (upcasts_code)
Printv(f_wrappers, upcasts_code, NIL);
Printf(f_wrappers, "#ifdef __cplusplus\n");
Printf(f_wrappers, "}\n");
Printf(f_wrappers, "#endif\n");
// Output a Modula 3 type wrapper class for each SWIG type
for (Iterator swig_type = First(swig_types_hash); swig_type.item != NIL; swig_type = Next(swig_type)) {
emitTypeWrapperClass(swig_type.key, swig_type.item);
}
Delete(swig_types_hash);
swig_types_hash = NULL;
Delete(constant_values);
constant_values = NULL;
Delete(enumeration_coll);
enumeration_coll = NULL;
Delete(m3raw_name);
m3raw_name = NULL;
Delete(m3raw_baseclass);
m3raw_baseclass = NULL;
Delete(m3raw_interfaces);
m3raw_interfaces = NULL;
Delete(m3raw_class_modifiers);
m3raw_class_modifiers = NULL;
Delete(m3raw_imports);
m3raw_imports = NULL;
Delete(m3raw_cppcasts_code);
m3raw_cppcasts_code = NULL;
Delete(proxy_class_def);
proxy_class_def = NULL;
Delete(proxy_class_code);
proxy_class_code = NULL;
Delete(m3wrap_name);
m3wrap_name = NULL;
Delete(m3wrap_modifiers);
m3wrap_modifiers = NULL;
Delete(targetlibrary);
targetlibrary = NULL;
Delete(module_baseclass);
module_baseclass = NULL;
Delete(module_interfaces);
module_interfaces = NULL;
Delete(module_imports);
module_imports = NULL;
Delete(upcasts_code);
upcasts_code = NULL;
Delete(constantfilename);
constantfilename = NULL;
Delete(renamefilename);
renamefilename = NULL;
Delete(typemapfilename);
typemapfilename = NULL;
/* Close all of the files */
Dump(f_runtime, f_begin);
Dump(f_header, f_begin);
Dump(f_wrappers, f_begin);
Wrapper_pretty_print(f_init, f_begin);
Delete(f_header);
Delete(f_wrappers);
Delete(f_init);
Delete(f_runtime);
Delete(f_begin);
return SWIG_OK;
}
/* -----------------------------------------------------------------------------
* emitBanner()
* ----------------------------------------------------------------------------- */
void emitBanner(File *f) {
Printf(f, "(*******************************************************************************\n");
Swig_banner_target_lang(f, " *");
Printf(f, "*******************************************************************************)\n\n");
}
/* ----------------------------------------------------------------------
* nativeWrapper()
* ---------------------------------------------------------------------- */
virtual int nativeWrapper(Node *n) {
String *wrapname = Getattr(n, "wrap:name");
if (!addSymbol(wrapname, n))
return SWIG_ERROR;
if (Getattr(n, "type")) {
Swig_save("nativeWrapper", n, "name", NIL);
Setattr(n, "name", wrapname);
native_function_flag = true;
functionWrapper(n);
Swig_restore(n);
native_function_flag = false;
} else {
Swig_error(input_file, line_number, "No return type for %%native method %s.\n", Getattr(n, "wrap:name"));
}
return SWIG_OK;
}
/* ----------------------------------------------------------------------
* functionWrapper()
* ---------------------------------------------------------------------- */
virtual int functionWrapper(Node *n) {
String *type = nodeType(n);
String *funcType = Getattr(n, "modula3:functype");
String *rawname = Getattr(n, "name");
String *symname = Getattr(n, "sym:name");
String *capname = capitalizeFirst(symname);
//String *wname = Swig_name_wrapper(symname);
//printf("function: %s\n", Char(symname));
//printf(" purpose: %s\n", Char(funcType));
if (Strcmp(type, "cdecl") == 0) {
if (funcType == NIL) {
// no wrapper needed for plain functions
emitM3RawPrototype(n, rawname, symname);
emitM3Wrapper(n, symname);
} else if (Strcmp(funcType, "method") == 0) {
Setattr(n, "modula3:funcname", capname);
emitCWrapper(n, capname);
emitM3RawPrototype(n, capname, capname);
emitM3Wrapper(n, capname);
} else if (Strcmp(funcType, "accessor") == 0) {
/*
* Generate the proxy class properties for public member variables.
* Not for enums and constants.
*/
if (proxy_flag && wrapping_member_flag && !enum_constant_flag) {
// Capitalize the first letter in the function name
Setattr(n, "proxyfuncname", capname);
Setattr(n, "imfuncname", symname);
if (hasPrefix(capname, "Set")) {
Setattr(n, "modula3:setname", capname);
} else {
Setattr(n, "modula3:getname", capname);
}
emitCWrapper(n, capname);
emitM3RawPrototype(n, capname, capname);
emitM3Wrapper(n, capname);
//proxyClassFunctionHandler(n);
}
#ifdef DEBUG
} else {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Function type <%s> unknown.\n", Char(funcType));
#endif
}
} else if ((Strcmp(type, "constructor") == 0) || (Strcmp(type, "destructor") == 0)) {
emitCWrapper(n, capname);
emitM3RawPrototype(n, capname, capname);
emitM3Wrapper(n, capname);
}
// a Java relict
#if 0
if (!(proxy_flag && is_wrapping_class()) && !enum_constant_flag) {
emitM3Wrapper(n, capname);
}
#endif
Delete(capname);
return SWIG_OK;
}
/* ----------------------------------------------------------------------
* emitCWrapper()
*
* Generate the wrapper in C which calls C++ methods.
* ---------------------------------------------------------------------- */
virtual int emitCWrapper(Node *n, const String *wname) {
String *rawname = Getattr(n, "name");
String *c_return_type = NewString("");
String *cleanup = NewString("");
String *outarg = NewString("");
String *body = NewString("");
Hash *throws_hash = NewHash();
ParmList *l = Getattr(n, "parms");
SwigType *t = Getattr(n, "type");
String *symname = Getattr(n, "sym:name");
if (!Getattr(n, "sym:overloaded")) {
if (!addSymbol(wname, n)) {
return SWIG_ERROR;
}
}
// A new wrapper function object
Wrapper *f = NewWrapper();
/* Attach the non-standard typemaps to the parameter list. */
Swig_typemap_attach_parms("ctype", l, f);
/* Get return types */
{
String *tm = getMappedTypeNew(n, "ctype", "");
if (tm != NIL) {
Printf(c_return_type, "%s", tm);
}
}
bool is_void_return = (Cmp(c_return_type, "void") == 0);
if (!is_void_return) {
Wrapper_add_localv(f, "cresult", c_return_type, "cresult = 0", NIL);
}
Printv(f->def, " SWIGEXPORT ", c_return_type, " ", wname, "(", NIL);
// Emit all of the local variables for holding arguments.
emit_parameter_variables(l, f);
/* Attach the standard typemaps */
emit_attach_parmmaps(l, f);
Setattr(n, "wrap:parms", l);
// Generate signature and argument conversion for C wrapper
{
Parm *p;
attachParameterNames(n, "tmap:name", "c:wrapname", "m3arg%d");
bool gencomma = false;
for (p = skipIgnored(l, "in"); p; p = skipIgnored(p, "in")) {
String *arg = Getattr(p, "c:wrapname");
{
/* Get the ctype types of the parameter */
String *c_param_type = getMappedType(p, "ctype");
// Add parameter to C function
Printv(f->def, gencomma ? ", " : "", c_param_type, " ", arg, NIL);
Delete(c_param_type);
gencomma = true;
}
// Get typemap for this argument
String *tm = getMappedType(p, "in");
if (tm != NIL) {
addThrows(throws_hash, "in", p);
Replaceall(tm, "$input", arg);
Setattr(p, "emit:input", arg); /*??? */
Printf(f->code, "%s\n", tm);
p = Getattr(p, "tmap:in:next");
} else {
p = nextSibling(p);
}
}
}
/* Insert constraint checking code */
{
Parm *p;
for (p = l; p;) {
String *tm = Getattr(p, "tmap:check");
if (tm != NIL) {
addThrows(throws_hash, "check", p);
Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */
Replaceall(tm, "$input", Getattr(p, "emit:input"));
Printv(f->code, tm, "\n", NIL);
p = Getattr(p, "tmap:check:next");
} else {
p = nextSibling(p);
}
}
}
/* Insert cleanup code */
{
Parm *p;
for (p = l; p;) {
String *tm = Getattr(p, "tmap:freearg");
if (tm != NIL) {
addThrows(throws_hash, "freearg", p);
Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */
Replaceall(tm, "$input", Getattr(p, "emit:input"));
Printv(cleanup, tm, "\n", NIL);
p = Getattr(p, "tmap:freearg:next");
} else {
p = nextSibling(p);
}
}
}
/* Insert argument output code */
{
Parm *p;
for (p = l; p;) {
String *tm = Getattr(p, "tmap:argout");
if (tm != NIL) {
addThrows(throws_hash, "argout", p);
Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */
Replaceall(tm, "$result", "cresult");
Replaceall(tm, "$input", Getattr(p, "emit:input"));
Printv(outarg, tm, "\n", NIL);
p = Getattr(p, "tmap:argout:next");
} else {
p = nextSibling(p);
}
}
}
// Get any Modula 3 exception classes in the throws typemap
ParmList *throw_parm_list = NULL;
if ((throw_parm_list = Getattr(n, "catchlist"))) {
Swig_typemap_attach_parms("throws", throw_parm_list, f);
Parm *p;
for (p = throw_parm_list; p; p = nextSibling(p)) {
addThrows(throws_hash, "throws", p);
}
}
Setattr(n, "wrap:name", wname);
// Now write code to make the function call
if (!native_function_flag) {
String *actioncode = emit_action(n);
/* Return value if necessary */
String *tm;
if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) {
addThrows(throws_hash, "out", n);
Replaceall(tm, "$result", "cresult");
Printf(f->code, "%s", tm);
if (hasContent(tm))
Printf(f->code, "\n");
} else {
Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(t, 0), rawname);
}
emit_return_variable(n, t, f);
}
/* Output argument output code */
Printv(f->code, outarg, NIL);
/* Output cleanup code */
Printv(f->code, cleanup, NIL);
/* Look to see if there is any newfree cleanup code */
if (GetFlag(n, "feature:new")) {
String *tm = Swig_typemap_lookup("newfree", n, Swig_cresult_name(), 0);
if (tm != NIL) {
addThrows(throws_hash, "newfree", n);
Printf(f->code, "%s\n", tm);
}
}
/* See if there is any return cleanup code */
if (!native_function_flag) {
String *tm = Swig_typemap_lookup("ret", n, Swig_cresult_name(), 0);
if (tm != NIL) {
Printf(f->code, "%s\n", tm);
}
}
/* Finish C wrapper */
Printf(f->def, ") {");
if (!is_void_return)
Printv(f->code, " return cresult;\n", NIL);
Printf(f->code, "}\n");
/* Substitute the cleanup code */
Replaceall(f->code, "$cleanup", cleanup);
/* Substitute the function name */
Replaceall(f->code, "$symname", symname);
if (!is_void_return) {
Replaceall(f->code, "$null", "0");
} else {
Replaceall(f->code, "$null", "");
}
/* Dump the function out */
if (!native_function_flag) {
Wrapper_print(f, f_wrappers);
}
Delete(c_return_type);
Delete(cleanup);
Delete(outarg);
Delete(body);
Delete(throws_hash);
DelWrapper(f);
return SWIG_OK;
}
/* ----------------------------------------------------------------------
* emitM3RawPrototype()
*
* Generate an EXTERNAL procedure declaration in Modula 3
* which is the interface to an existing C routine or a C wrapper.
* ---------------------------------------------------------------------- */
virtual int emitM3RawPrototype(Node *n, const String *cname, const String *m3name) {
String *im_return_type = NewString("");
//String *symname = Getattr(n,"sym:name");
ParmList *l = Getattr(n, "parms");
/* Attach the non-standard typemaps to the parameter list. */
Swig_typemap_attach_parms("m3rawinmode", l, NULL);
Swig_typemap_attach_parms("m3rawintype", l, NULL);
/* Get return types */
bool has_return;
{
String *tm = getMappedTypeNew(n, "m3rawrettype", "");
if (tm != NIL) {
Printf(im_return_type, "%s", tm);
}
has_return = hasContent(tm);
}
/* cname is the original name if 'n' denotes a C function
and it is the relabeled name (sym:name) if 'n' denotes a C++ method or similar */
m3raw_intf.enterBlock(no_block);
Printf(m3raw_intf.f, "\n<* EXTERNAL %s *>\nPROCEDURE %s (", cname, m3name);
// Generate signature for raw interface
{
Parm *p;
writeArgState state;
attachParameterNames(n, "tmap:rawinname", "modula3:rawname", "arg%d");
for (p = skipIgnored(l, "m3rawintype"); p; p = skipIgnored(p, "m3rawintype")) {
/* Get argument passing mode, should be one of VALUE, VAR, READONLY */
String *mode = Getattr(p, "tmap:m3rawinmode");
String *argname = Getattr(p, "modula3:rawname");
String *im_param_type = getMappedType(p, "m3rawintype");
addImports(m3raw_intf.import, "m3rawintype", p);
writeArg(m3raw_intf.f, state, mode, argname, im_param_type, NIL);
if (im_param_type != NIL) {
p = Getattr(p, "tmap:m3rawintype:next");
} else {
p = nextSibling(p);
}
}
writeArg(m3raw_intf.f, state, NIL, NIL, NIL, NIL);
}
/* Finish M3 raw prototype */
Printf(m3raw_intf.f, ")");
// neither a C wrapper nor a plain C function may throw an exception
//generateThrowsClause(throws_hash, m3raw_intf.f);
if (has_return) {
Printf(m3raw_intf.f, ": %s", im_return_type);
}
Printf(m3raw_intf.f, ";\n");
Delete(im_return_type);
return SWIG_OK;
}
/* -----------------------------------------------------------------------
* variableWrapper()
* ----------------------------------------------------------------------- */
virtual int variableWrapper(Node *n) {
Language::variableWrapper(n);
return SWIG_OK;
}
/* -----------------------------------------------------------------------
* globalvariableHandler()
* ----------------------------------------------------------------------- */
virtual int globalvariableHandler(Node *n) {
SwigType *t = Getattr(n, "type");
String *tm;
// Get the variable type
if ((tm = getMappedTypeNew(n, "m3wraptype", ""))) {
substituteClassname(t, tm);
}
variable_name = Getattr(n, "sym:name");
variable_type = Copy(tm);
// Get the variable type expressed in terms of Modula 3 equivalents of C types
if ((tm = getMappedTypeNew(n, "m3rawtype", ""))) {
m3raw_intf.enterBlock(no_block);
Printf(m3raw_intf.f, "\n<* EXTERNAL *> VAR %s: %s;\n", variable_name, tm);
}
// Output the property's accessor methods
/*
global_variable_flag = true;
int ret = Language::globalvariableHandler(n);
global_variable_flag = false;
*/
Printf(m3wrap_impl.f, "\n\n");
//return ret;
return 1;
}
long getConstNumeric(Node *n) {
String *constnumeric = Getfeature(n, "constnumeric");
String *name = Getattr(n, "name");
long numvalue;
if (constnumeric == NIL) {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Feature 'constnumeric' is necessary to obtain value of %s.\n", name);
return 0;
} else if (!strToL(constnumeric, numvalue)) {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number,
"The feature 'constnumeric' of %s specifies value <%s> which is not an integer constant.\n", name, constnumeric);
return 0;
} else {
return numvalue;
}
}
/* ------------------------------------------------------------------------
* generateIntConstant()
*
* Considers node as an integer constant definition
* and generate a Modula 3 constant definition.
* ------------------------------------------------------------------------ */
void generateIntConstant(Node *n, String *name) {
String *value = Getattr(n, "value");
String *type = Getfeature(n, "modula3:constint:type");
String *conv = Getfeature(n, "modula3:constint:conv");
if (name == NIL) {
name = Getattr(n, "sym:name");
}
long numvalue;
bool isSimpleNum = strToL(value, numvalue);
if (!isSimpleNum) {
numvalue = getConstNumeric(n);
}
String *m3value;
if ((conv == NIL) || ((Strcmp(conv, "set:int") != 0) && (Strcmp(conv, "int:set") != 0))) {
/* The original value of the constant has precedence over
'constnumeric' feature since we like to keep
the style (that is the base) of simple numeric constants */
if (isSimpleNum) {
if (hasPrefix(value, "0x")) {
m3value = NewStringf("16_%s", Char(value) + 2);
} else if ((Len(value) > 1) && (*Char(value) == '0')) {
m3value = NewStringf("8_%s", Char(value) + 1);
} else {
m3value = Copy(value);
}
/* If we cannot easily obtain the value of a numeric constant,
we use the results given by a C compiler. */
} else {
m3value = Copy(Getfeature(n, "constnumeric"));
}
} else {
// if the value can't be converted, it is ignored
if (convertInt(numvalue, numvalue, conv)) {
m3value = NewStringf("%d", numvalue);
} else {
m3value = NIL;
}
}
if (m3value != NIL) {
m3wrap_intf.enterBlock(constant);
Printf(m3wrap_intf.f, "%s", name);
if (hasContent(type)) {
Printf(m3wrap_intf.f, ": %s", type);
}
Printf(m3wrap_intf.f, " = %s;\n", m3value);
Delete(m3value);
}
}
/* -----------------------------------------------------------------------
* generateSetConstant()
*
* Considers node as a set constant definition
* and generate a Modula 3 constant definition.
* ------------------------------------------------------------------------ */
void generateSetConstant(Node *n, String *name) {
String *value = Getattr(n, "value");
String *type = Getfeature(n, "modula3:constset:type");
String *setname = Getfeature(n, "modula3:constset:set");
String *basename = Getfeature(n, "modula3:constset:base");
String *conv = Getfeature(n, "modula3:constset:conv");
m3wrap_intf.enterBlock(constant);
Printf(m3wrap_intf.f, "%s", name);
if (type != NIL) {
Printf(m3wrap_intf.f, ":%s ", type);
}
Printf(m3wrap_intf.f, " = %s{", setname);
long numvalue = 0;
if (!strToL(value, numvalue)) {
numvalue = getConstNumeric(n);
}
convertInt(numvalue, numvalue, conv);
bool isIntType = Strcmp(basename, "CARDINAL") == 0;
Hash *items = NIL;
if (!isIntType) {
Hash *enumeration = Getattr(enumeration_coll, basename);
if (enumeration == NIL) {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "There is no enumeration <%s> as needed for the set.\n", setname);
isIntType = true;
} else {
items = Getattr(enumeration, "items");
}
}
bool gencomma = false;
int bitpos = 0;
while (numvalue > 0) {
if ((numvalue & 1) != 0) {
if (isIntType) {
if (gencomma) {
Printv(m3wrap_intf.f, ",", NIL);
}
gencomma = true;
Printf(m3wrap_intf.f, "%d", bitpos);
} else {
char bitval[15];
sprintf(bitval, "%d", bitpos);
String *bitname = Getattr(items, bitval);
if (bitname == NIL) {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Enumeration <%s> has no value <%s>.\n", setname, bitval);
} else {
if (gencomma) {
Printv(m3wrap_intf.f, ",", NIL);
}
gencomma = true;
Printf(m3wrap_intf.f, "%s.%s", basename, bitname);
}
}
}
numvalue >>= 1;
bitpos++;
}
Printf(m3wrap_intf.f, "};\n");
}
void generateConstant(Node *n) {
// any of the special interpretation disables the default behaviour
String *enumitem = Getfeature(n, "modula3:enumitem:name");
String *constset = Getfeature(n, "modula3:constset:name");
String *constint = Getfeature(n, "modula3:constint:name");
if (hasContent(enumitem) || hasContent(constset) || hasContent(constint)) {
if (hasContent(constset)) {
generateSetConstant(n, constset);
}
if (hasContent(constint)) {
generateIntConstant(n, constint);
}
} else {
String *value = Getattr(n, "value");
String *name = Getattr(n, "sym:name");
if (name == NIL) {
name = Getattr(n, "name");
}
m3wrap_intf.enterBlock(constant);
Printf(m3wrap_intf.f, "%s = %s;\n", name, value);
}
}
void emitEnumeration(File *file, String *name, Node *n) {
Printf(file, "%s = {", name);
int i;
bool gencomma = false;
int max = aToL(Getattr(n, "max"));
Hash *items = Getattr(n, "items");
for (i = 0; i <= max; i++) {
if (gencomma) {
Printf(file, ",");
}
Printf(file, "\n");
gencomma = true;
char numstr[15];
sprintf(numstr, "%d", i);
String *name = Getattr(items, numstr);
if (name != NIL) {
Printv(file, name, NIL);
} else {
Printf(file, "Dummy%d", i);
}
}
Printf(file, "\n};\n");
}
/* -----------------------------------------------------------------------
* constantWrapper()
*
* Handles constants and enumeration items.
* ------------------------------------------------------------------------ */
virtual int constantWrapper(Node *n) {
generateConstant(n);
return SWIG_OK;
}
#if 0
// enumerations are handled like constant definitions
/* -----------------------------------------------------------------------------
* enumDeclaration()
* ----------------------------------------------------------------------------- */
virtual int enumDeclaration(Node *n) {
String *symname = nameToModula3(Getattr(n, "sym:name"), true);
enumerationStart(symname);
int result = Language::enumDeclaration(n);
enumerationStop();
Delete(symname);
return result;
}
#endif
/* -----------------------------------------------------------------------------
* enumvalueDeclaration()
* ----------------------------------------------------------------------------- */
virtual int enumvalueDeclaration(Node *n) {
generateConstant(n);
/*
This call would continue processing in the constantWrapper
which cannot handle values like "RED+1".
return Language::enumvalueDeclaration(n);
*/
return SWIG_OK;
}
/* -----------------------------------------------------------------------------
* pragmaDirective()
*
* Valid Pragmas:
* imclassbase - base (extends) for the intermediary class
* imclassclassmodifiers - class modifiers for the intermediary class
* imclasscode - text (Modula 3 code) is copied verbatim to the intermediary class
* imclassimports - import statements for the intermediary class
* imclassinterfaces - interface (implements) for the intermediary class
*
* modulebase - base (extends) for the module class
* moduleclassmodifiers - class modifiers for the module class
* modulecode - text (Modula 3 code) is copied verbatim to the module class
* moduleimports - import statements for the module class
* moduleinterfaces - interface (implements) for the module class
*
* ----------------------------------------------------------------------------- */
virtual int pragmaDirective(Node *n) {
if (!ImportMode) {
String *lang = Getattr(n, "lang");
String *code = Getattr(n, "name");
String *value = Getattr(n, "value");
if (Strcmp(lang, "modula3") == 0) {
String *strvalue = NewString(value);
Replaceall(strvalue, "\\\"", "\"");
/*
bool isEnumItem = Strcmp(code, "enumitem") == 0;
bool isSetItem = Strcmp(code, "setitem") == 0;
*/
if (Strcmp(code, "imclassbase") == 0) {
Delete(m3raw_baseclass);
m3raw_baseclass = Copy(strvalue);
} else if (Strcmp(code, "imclassclassmodifiers") == 0) {
Delete(m3raw_class_modifiers);
m3raw_class_modifiers = Copy(strvalue);
} else if (Strcmp(code, "imclasscode") == 0) {
Printf(m3raw_intf.f, "%s\n", strvalue);
} else if (Strcmp(code, "imclassimports") == 0) {
Delete(m3raw_imports);
m3raw_imports = Copy(strvalue);
} else if (Strcmp(code, "imclassinterfaces") == 0) {
Delete(m3raw_interfaces);
m3raw_interfaces = Copy(strvalue);
} else if (Strcmp(code, "modulebase") == 0) {
Delete(module_baseclass);
module_baseclass = Copy(strvalue);
} else if (Strcmp(code, "moduleclassmodifiers") == 0) {
Delete(m3wrap_modifiers);
m3wrap_modifiers = Copy(strvalue);
} else if (Strcmp(code, "modulecode") == 0) {
Printf(m3wrap_impl.f, "%s\n", strvalue);
} else if (Strcmp(code, "moduleimports") == 0) {
Delete(module_imports);
module_imports = Copy(strvalue);
} else if (Strcmp(code, "moduleinterfaces") == 0) {
Delete(module_interfaces);
module_interfaces = Copy(strvalue);
} else if (Strcmp(code, "unsafe") == 0) {
unsafe_module = true;
} else if (Strcmp(code, "library") == 0) {
if (targetlibrary) {
Delete(targetlibrary);
}
targetlibrary = Copy(strvalue);
} else if (Strcmp(code, "enumitem") == 0) {
} else if (Strcmp(code, "constset") == 0) {
} else if (Strcmp(code, "constint") == 0) {
} else if (Strcmp(code, "makesetofenum") == 0) {
m3wrap_intf.enterBlock(blocktype);
Printf(m3wrap_intf.f, "%sSet = SET OF %s;\n", value, value);
} else {
Swig_warning(WARN_MODULA3_UNKNOWN_PRAGMA, input_file, line_number, "Unrecognized pragma <%s>.\n", code);
}
Delete(strvalue);
}
}
return Language::pragmaDirective(n);
}
void Setfeature(Node *n, const char *feature, const String *value, bool warn = false) {
//printf("tag feature <%s> with value <%s>\n", feature, Char(value));
String *attr = NewStringf("feature:%s", feature);
if ((Setattr(n, attr, value) != 0) && warn) {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Feature <%s> of %s did already exist.\n", feature, Getattr(n, "name"));
}
Delete(attr);
}
String *Getfeature(Node *n, const char *feature) {
//printf("retrieve feature <%s> with value <%s>\n", feature, Char(value));
String *attr = NewStringf("feature:%s", feature);
String *result = Getattr(n, attr);
Delete(attr);
return result;
}
bool convertInt(long in, long &out, const String *mode) {
if ((mode == NIL) || (Strcmp(mode, "int:int") == 0) || (Strcmp(mode, "set:set") == 0)) {
out = in;
return true;
} else if (Strcmp(mode, "set:int") == 0) {
return log2(in, out);
} else if (Strcmp(mode, "int:set") == 0) {
out = 1L << in;
return unsigned (in) < (sizeof(out) * 8);
} else {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Unknown integer conversion method <%s>.\n", mode);
return false;
}
}
void collectEnumerations(Hash *enums, Node *n) {
Node *child = firstChild(n);
while (child != NIL) {
String *name = Getattr(child, "name");
const bool isConstant = Strcmp(nodeType(child), "constant") == 0;
const bool isEnumItem = Strcmp(nodeType(child), "enumitem") == 0;
if (isConstant || isEnumItem) {
//printf("%s%s name %s\n", isConstant?"constant":"", isEnumItem?"enumitem":"", Char(name));
{
String *m3name = Getfeature(child, "modula3:enumitem:name");
String *m3enum = Getfeature(child, "modula3:enumitem:enum");
String *conv = Getfeature(child, "modula3:enumitem:conv");
if (m3enum != NIL) {
//printf("m3enum %s\n", Char(m3enum));
if (m3name == NIL) {
m3name = name;
}
long max = -1;
Hash *items;
Hash *enumnode = Getattr(enums, m3enum);
if (enumnode == NIL) {
enumnode = NewHash();
items = NewHash();
Setattr(enumnode, "items", items);
Setattr(enums, m3enum, enumnode);
} else {
String *maxstr = Getattr(enumnode, "max");
if (maxstr != NIL) {
max = aToL(maxstr);
}
items = Getattr(enumnode, "items");
}
long numvalue;
String *value = Getattr(child, "value");
//printf("value: %s\n", Char(value));
if ((value == NIL) || (!strToL(value, numvalue))) {
value = Getattr(child, "enumvalue");
if ((value == NIL) || (!evalExpr(value, numvalue))) {
numvalue = getConstNumeric(child);
}
//printf("constnumeric: %s\n", Char(value));
}
Setattr(constant_values, name, NewStringf("%d", numvalue));
if (convertInt(numvalue, numvalue, conv)) {
String *newvalue = NewStringf("%d", numvalue);
String *oldname = Getattr(items, newvalue);
if (oldname != NIL) {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "The value <%s> is already assigned to <%s>.\n", value, oldname);
}
//printf("items %p, set %s = %s\n", items, Char(newvalue), Char(m3name));
Setattr(items, newvalue, m3name);
if (max < numvalue) {
max = numvalue;
}
Setattr(enumnode, "max", NewStringf("%d", max));
}
}
}
}
collectEnumerations(enums, child);
child = nextSibling(child);
}
}
enum const_pragma_type { cpt_none, cpt_constint, cpt_constset, cpt_enumitem };
struct const_id_pattern {
String *prefix, *parentEnum;
};
void tagConstants(Node *first, String *parentEnum, const const_id_pattern & pat, const String *pragma, List *convdesc) {
Node *n = first;
while (n != NIL) {
String *name = getQualifiedName(n);
bool isConstant = Strcmp(nodeType(n), "constant") == 0;
bool isEnumItem = Strcmp(nodeType(n), "enumitem") == 0;
if ((isConstant || isEnumItem) && ((pat.prefix == NIL) || (hasPrefix(name, pat.prefix))) && ((pat.parentEnum == NIL) || ((parentEnum != NIL)
&&
(Strcmp
(pat.parentEnum, parentEnum)
== 0)))) {
//printf("tag %s\n", Char(name));
String *srctype = Getitem(convdesc, 1);
String *relationstr = Getitem(convdesc, 3);
List *relationdesc = Split(relationstr, ',', 2);
// transform name from C to Modula3 style
String *srcstyle = NIL;
String *newprefix = NIL;
{
//printf("name conversion <%s>\n", Char(Getitem(convdesc,2)));
List *namedesc = Split(Getitem(convdesc, 2), ',', INT_MAX);
Iterator nameit = First(namedesc);
for (; nameit.item != NIL; nameit = Next(nameit)) {
List *nameassign = Split(nameit.item, '=', 2);
String *tag = Getitem(nameassign, 0);
String *data = Getitem(nameassign, 1);
//printf("name conv <%s> = <%s>\n", Char(tag), Char(data));
if (Strcmp(tag, "srcstyle") == 0) {
srcstyle = Copy(data);
} else if (Strcmp(tag, "prefix") == 0) {
newprefix = Copy(data);
} else {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Unknown name conversion tag <%s> with value <%s>.\n", tag, data);
}
Delete(nameassign);
}
Delete(namedesc);
}
const char *stem = Char(name);
if (pat.prefix != NIL) {
//printf("pat.prefix %s for %s\n", Char(pat.prefix), Char(name));
stem += Len(pat.prefix);
}
String *newname;
if (srcstyle && Strcmp(srcstyle, "underscore") == 0) {
if (newprefix != NIL) {
String *newstem = nameToModula3(stem, true);
newname = NewStringf("%s%s", newprefix, newstem);
Delete(newstem);
} else {
newname = nameToModula3(stem, true);
}
} else {
if (srcstyle != NIL) {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Unknown C identifier style <%s>.\n", srcstyle);
}
newname = Copy(name);
}
if (Strcmp(pragma, "enumitem") == 0) {
if (Len(relationdesc) != 1) {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Expected <enumeration>, got <%s>.\n", relationstr);
}
Setfeature(n, "modula3:enumitem:name", newname, true);
Setfeature(n, "modula3:enumitem:enum", relationstr, true);
Setfeature(n, "modula3:enumitem:conv", NewStringf("%s:int", srctype), true);
} else if (Strcmp(pragma, "constint") == 0) {
if (Len(relationdesc) != 1) {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Expected <ordinal type>, got <%s>.\n", relationstr);
}
Setfeature(n, "modula3:constint:name", newname, true);
Setfeature(n, "modula3:constint:type", Getitem(relationdesc, 0), true);
Setfeature(n, "modula3:constint:conv", NewStringf("%s:int", srctype), true);
} else if (Strcmp(pragma, "constset") == 0) {
if (Len(relationdesc) != 2) {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Expected <set type,base type>, got <%s>.\n", relationstr);
}
String *settype = Getitem(relationdesc, 0);
Setfeature(n, "modula3:constset:name", newname, true);
//Setfeature(n,"modula3:constset:type",settype,true);
Setfeature(n, "modula3:constset:set", settype, true);
Setfeature(n, "modula3:constset:base", Getitem(relationdesc, 1), true);
Setfeature(n, "modula3:constset:conv", NewStringf("%s:set", srctype), true);
}
Delete(newname);
Delete(relationdesc);
}
if (Strcmp(nodeType(n), "enum") == 0) {
//printf("explore enum %s, qualification %s\n", Char(name), Char(Swig_symbol_qualified(n)));
tagConstants(firstChild(n), name, pat, pragma, convdesc);
} else {
tagConstants(firstChild(n), NIL, pat, pragma, convdesc);
}
n = nextSibling(n);
}
}
void scanForConstPragmas(Node *n) {
Node *child = firstChild(n);
while (child != NIL) {
const String *type = nodeType(child);
if (Strcmp(type, "pragma") == 0) {
const String *lang = Getattr(child, "lang");
const String *code = Getattr(child, "name");
String *value = Getattr(child, "value");
if (Strcmp(lang, "modula3") == 0) {
const_pragma_type cpt = cpt_none;
if (Strcmp(code, "constint") == 0) {
cpt = cpt_constint;
} else if (Strcmp(code, "constset") == 0) {
cpt = cpt_constset;
} else if (Strcmp(code, "enumitem") == 0) {
cpt = cpt_enumitem;
}
if (cpt != cpt_none) {
const_id_pattern pat = { NIL, NIL };
List *convdesc = Split(value, ';', 4);
List *patterndesc = Split(Getitem(convdesc, 0), ',', INT_MAX);
Iterator patternit;
for (patternit = First(patterndesc); patternit.item != NIL; patternit = Next(patternit)) {
List *patternassign = Split(patternit.item, '=', 2);
String *tag = Getitem(patternassign, 0);
String *data = Getitem(patternassign, 1);
if (Strcmp(tag, "prefix") == 0) {
pat.prefix = Copy(data);
} else if (Strcmp(tag, "enum") == 0) {
pat.parentEnum = Copy(data);
} else {
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Unknown identification tag <%s> with value <%s>.\n", tag, data);
}
Delete(patternassign);
}
tagConstants(child, NIL, pat, code, convdesc);
Delete(patterndesc);
}
}
}
scanForConstPragmas(child);
child = nextSibling(child);
}
}
/* -----------------------------------------------------------------------------
* emitProxyClassDefAndCPPCasts()
* ----------------------------------------------------------------------------- */
void emitProxyClassDefAndCPPCasts(Node *n) {
String *c_classname = SwigType_namestr(Getattr(n, "name"));
String *c_baseclass = NULL;
String *baseclass = NULL;
String *c_baseclassname = NULL;
String *name = Getattr(n, "name");
/* Deal with inheritance */
List *baselist = Getattr(n, "bases");
if (baselist) {
Iterator base = First(baselist);
while (base.item) {
if (!GetFlag(base.item, "feature:ignore")) {
String *baseclassname = Getattr(base.item, "name");
if (!c_baseclassname) {
c_baseclassname = baseclassname;
baseclass = Copy(getProxyName(baseclassname));
if (baseclass)
c_baseclass = SwigType_namestr(baseclassname);
} else {
/* Warn about multiple inheritance for additional base class(es) */
String *proxyclassname = Getattr(n, "classtypeobj");
Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, Getfile(n), Getline(n),
"Warning for %s, base %s ignored. Multiple inheritance is not supported in Modula 3.\n", SwigType_namestr(proxyclassname), SwigType_namestr(baseclassname));
}
}
base = Next(base);
}
}
bool derived = baseclass && getProxyName(c_baseclassname);
if (!baseclass)
baseclass = NewString("");
// Inheritance from pure Modula 3 classes
const String *pure_baseclass = typemapLookup(n, "m3base", name, WARN_NONE);
if (hasContent(pure_baseclass) && hasContent(baseclass)) {
Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, Getfile(n), Getline(n),
"Warning for %s, base %s ignored. Multiple inheritance is not supported in Modula 3.\n", name, pure_baseclass);
}
// Pure Modula 3 interfaces
const String *pure_interfaces = typemapLookup(n, derived ? "m3interfaces_derived" : "m3interfaces",
name, WARN_NONE);
// Start writing the proxy class
Printv(proxy_class_def, typemapLookup(n, "m3imports", name, WARN_NONE), // Import statements
"\n", typemapLookup(n, "m3classmodifiers", name, WARN_MODULA3_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers
" class $m3classname", // Class name and bases
(derived || *Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", baseclass, pure_baseclass, ((derived || *Char(pure_baseclass)) && *Char(pure_interfaces)) ? // Interfaces
", " : "", pure_interfaces, " {\n", " private IntPtr swigCPtr;\n", // Member variables for memory handling
derived ? "" : " protected bool swigCMemOwn;\n", "\n", " ", typemapLookup(n, "m3ptrconstructormodifiers", name, WARN_MODULA3_TYPEMAP_PTRCONSTMOD_UNDEF), // pointer constructor modifiers
" $m3classname(IntPtr cPtr, bool cMemoryOwn) ", // Constructor used for wrapping pointers
derived ?
": base($imclassname.$m3classnameTo$baseclass(cPtr), cMemoryOwn) {\n"
: "{\n swigCMemOwn = cMemoryOwn;\n", " swigCPtr = cPtr;\n", " }\n", NIL);
if (!have_default_constructor_flag) { // All proxy classes need a constructor
Printv(proxy_class_def, "\n", " protected $m3classname() : this(IntPtr.Zero, false) {\n", " }\n", NIL);
}
// C++ destructor is wrapped by the Dispose method
// Note that the method name is specified in a typemap attribute called methodname
String *destruct = NewString("");
const String *tm = NULL;
Node *attributes = NewHash();
String *destruct_methodname = NULL;
if (derived) {
tm = typemapLookup(n, "m3destruct_derived", name, WARN_NONE, attributes);
destruct_methodname = Getattr(attributes, "tmap:m3destruct_derived:methodname");
} else {
tm = typemapLookup(n, "m3destruct", name, WARN_NONE, attributes);
destruct_methodname = Getattr(attributes, "tmap:m3destruct:methodname");
}
if (!destruct_methodname) {
Swig_error(Getfile(n), Getline(n), "No methodname attribute defined in m3destruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name);
}
// Emit the Finalize and Dispose methods
if (tm) {
// Finalize method
if (*Char(destructor_call)) {
Printv(proxy_class_def, typemapLookup(n, "m3finalize", name, WARN_NONE), NIL);
}
// Dispose method
Printv(destruct, tm, NIL);
if (*Char(destructor_call))
Replaceall(destruct, "$imcall", destructor_call);
else
Replaceall(destruct, "$imcall", "throw new MethodAccessException(\"C++ destructor does not have public access\")");
if (*Char(destruct))
Printv(proxy_class_def, "\n public ", derived ? "override" : "virtual", " void ", destruct_methodname, "() ", destruct, "\n", NIL);
}
Delete(attributes);
Delete(destruct);
// Emit various other methods
Printv(proxy_class_def, typemapLookup(n, "m3getcptr", name, WARN_MODULA3_TYPEMAP_GETCPTR_UNDEF), // getCPtr method
typemapLookup(n, "m3code", name, WARN_NONE), // extra Modula 3 code
"\n", NIL);
// Substitute various strings into the above template
Replaceall(proxy_class_def, "$m3classname", proxy_class_name);
Replaceall(proxy_class_code, "$m3classname", proxy_class_name);
Replaceall(proxy_class_def, "$baseclass", baseclass);
Replaceall(proxy_class_code, "$baseclass", baseclass);
Replaceall(proxy_class_def, "$imclassname", m3raw_name);
Replaceall(proxy_class_code, "$imclassname", m3raw_name);
// Add code to do C++ casting to base class (only for classes in an inheritance hierarchy)
if (derived) {
Printv(m3raw_cppcasts_code, "\n [DllImport(\"", m3wrap_name, "\", EntryPoint=\"Modula3_", proxy_class_name, "To", baseclass, "\")]\n", NIL);
Printv(m3raw_cppcasts_code, " public static extern IntPtr ", "$m3classnameTo$baseclass(IntPtr objectRef);\n", NIL);
Replaceall(m3raw_cppcasts_code, "$m3classname", proxy_class_name);
Replaceall(m3raw_cppcasts_code, "$baseclass", baseclass);
Printv(upcasts_code,
"SWIGEXPORT long Modula3_$imclazznameTo$imbaseclass",
"(long objectRef) {\n",
" long baseptr = 0;\n" " *($cbaseclass **)&baseptr = *($cclass **)&objectRef;\n" " return baseptr;\n" "}\n", "\n", NIL);
Replaceall(upcasts_code, "$imbaseclass", baseclass);
Replaceall(upcasts_code, "$cbaseclass", c_baseclass);
Replaceall(upcasts_code, "$imclazzname", proxy_class_name);
Replaceall(upcasts_code, "$cclass", c_classname);
}
Delete(baseclass);
}
/* ----------------------------------------------------------------------
* getAttrString()
*
* If necessary create and return the string
* associated with a certain attribute of 'n'.
* ---------------------------------------------------------------------- */
String *getAttrString(Node *n, const char *attr) {
String *str = Getattr(n, attr);
if (str == NIL) {
str = NewString("");
Setattr(n, attr, str);
}
return str;
}
/* ----------------------------------------------------------------------
* getMethodDeclarations()
*
* If necessary create and return the handle
* where the methods of the current access can be written to.
* 'n' must be a member of a struct or a class.
* ---------------------------------------------------------------------- */
String *getMethodDeclarations(Node *n) {
String *acc_str = Getattr(n, "access");
String *methodattr;
if (acc_str == NIL) {
methodattr = NewString("modula3:method:public");
} else {
methodattr = NewStringf("modula3:method:%s", acc_str);
}
String *methods = getAttrString(parentNode(n), Char(methodattr));
Delete(methodattr);
return methods;
}
/* ----------------------------------------------------------------------
* classHandler()
* ---------------------------------------------------------------------- */
virtual int classHandler(Node *n) {
File *f_proxy = NULL;
proxy_class_name = Copy(Getattr(n, "sym:name"));
//String *rawname = Getattr(n,"name");
if (proxy_flag) {
if (!addSymbol(proxy_class_name, n))
return SWIG_ERROR;
if (Cmp(proxy_class_name, m3raw_name) == 0) {
Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name);
SWIG_exit(EXIT_FAILURE);
}
if (Cmp(proxy_class_name, m3wrap_name) == 0) {
Printf(stderr, "Class name cannot be equal to module class name: %s\n", proxy_class_name);
SWIG_exit(EXIT_FAILURE);
}
String *filen = NewStringf("%s%s.m3", SWIG_output_directory(), proxy_class_name);
f_proxy = NewFile(filen, "w", SWIG_output_files());
if (!f_proxy) {
FileErrorDisplay(filen);
SWIG_exit(EXIT_FAILURE);
}
Delete(filen);
filen = NULL;
emitBanner(f_proxy);
Clear(proxy_class_def);
Clear(proxy_class_code);
have_default_constructor_flag = false;
destructor_call = NewString("");
}
/* This will invoke memberfunctionHandler, membervariableHandler ...
and finally it may invoke functionWrapper
for wrappers and member variable accessors.
It will invoke Language:constructorDeclaration
which decides whether to call MODULA3::constructorHandler */
Language::classHandler(n);
{
String *kind = Getattr(n, "kind");
if (Cmp(kind, "struct") == 0) {
String *entries = NewString("");
Node *child;
writeArgState state;
for (child = firstChild(n); child != NIL; child = nextSibling(child)) {
String *childType = nodeType(child);
if (Strcmp(childType, "cdecl") == 0) {
String *member = Getattr(child, "sym:name");
ParmList *pl = Getattr(child, "parms");
if (pl == NIL) {
// Get the variable type in Modula 3 type equivalents
String *m3ct = getMappedTypeNew(child, "m3rawtype", "");
writeArg(entries, state, NIL, member, m3ct, NIL);
}
}
}
writeArg(entries, state, NIL, NIL, NIL, NIL);
m3raw_intf.enterBlock(blocktype);
Printf(m3raw_intf.f, "%s =\nRECORD\n%sEND;\n", proxy_class_name, entries);
Delete(entries);
} else if (Cmp(kind, "class") == 0) {
enum access_privilege { acc_public, acc_protected, acc_private };
int max_acc = acc_public;
const char *acc_name[3] = { "public", "protected", "private" };
String *methods[3];
int acc;
for (acc = acc_public; acc <= acc_private; acc++) {
String *methodattr = NewStringf("modula3:method:%s", acc_name[acc]);
methods[acc] = Getattr(n, methodattr);
Delete(methodattr);
max_acc = max_acc > acc ? max_acc : acc;
}
/* Determine the name of the base class */
String *baseclassname = NewString("");
{
List *baselist = Getattr(n, "bases");
if (baselist) {
/* Look for the first (principal?) base class -
Modula 3 does not support multiple inheritance */
Iterator base = First(baselist);
if (base.item) {
Append(baseclassname, Getattr(base.item, "sym:name"));
base = Next(base);
if (base.item) {
Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, Getfile(n), Getline(n),
"Warning for %s, base %s ignored. Multiple inheritance is not supported in Modula 3.\n",
proxy_class_name, Getattr(base.item, "name"));
}
}
}
}
/* the private class of the base class and only this
need a pointer to the C++ object */
bool need_private = !hasContent(baseclassname);
max_acc = need_private ? acc_private : max_acc;
/* Declare C++ object as abstract pointer in Modula 3 */
/* The revelation system does not allow us
to imitate the whole class hierarchy of the C++ library,
but at least we can distinguish between classes of different roots. */
if (hasContent(baseclassname)) {
m3raw_intf.enterBlock(blocktype);
Printf(m3raw_intf.f, "%s = %s;\n", proxy_class_name, baseclassname);
} else {
m3raw_intf.enterBlock(blocktype);
Printf(m3raw_intf.f, "%s <: ADDRESS;\n", proxy_class_name);
m3raw_impl.enterBlock(revelation);
Printf(m3raw_impl.f, "%s = UNTRACED BRANDED REF RECORD (*Dummy*) END;\n", proxy_class_name);
}
String *superclass;
m3wrap_intf.enterBlock(blocktype);
if (hasContent(methods[acc_public])) {
superclass = NewStringf("%sPublic", proxy_class_name);
} else if (hasContent(baseclassname)) {
superclass = Copy(baseclassname);
} else {
superclass = NewString("ROOT");
}
Printf(m3wrap_intf.f, "%s <: %s;\n", proxy_class_name, superclass);
Delete(superclass);
{
static const char *acc_m3suffix[] = { "Public", "Protected", "Private" };
int acc;
for (acc = acc_public; acc <= acc_private; acc++) {
bool process_private = (acc == acc_private) && need_private;
if (hasContent(methods[acc]) || process_private) {
String *subclass = NewStringf("%s%s", proxy_class_name, acc_m3suffix[acc]);
/*
m3wrap_intf.enterBlock(revelation);
Printf(m3wrap_intf.f, "%s <: %s;\n", proxy_class_name, subclass);
*/
if (acc == max_acc) {
m3wrap_intf.enterBlock(revelation);
Printf(m3wrap_intf.f, "%s =\n", proxy_class_name);
} else {
m3wrap_intf.enterBlock(blocktype);
Printf(m3wrap_intf.f, "%s =\n", subclass);
}
Printf(m3wrap_intf.f, "%s BRANDED OBJECT\n", baseclassname);
if (process_private) {
Setattr(m3wrap_intf.import, m3raw_name, "");
Printf(m3wrap_intf.f, "cxxObj:%s.%s;\n", m3raw_name, proxy_class_name);
}
if (hasContent(methods[acc])) {
Printf(m3wrap_intf.f, "METHODS\n%s", methods[acc]);