diff options
Diffstat (limited to 'Source/Modules/modula3.cxx')
-rw-r--r-- | Source/Modules/modula3.cxx | 3987 |
1 files changed, 3987 insertions, 0 deletions
diff --git a/Source/Modules/modula3.cxx b/Source/Modules/modula3.cxx new file mode 100644 index 0000000..40f275a --- /dev/null +++ b/Source/Modules/modula3.cxx @@ -0,0 +1,3987 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * modula3.cxx + * + * Modula3 language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_modula3_cxx[] = "$Id: modula3.cxx 11584 2009-08-16 00:04:29Z wsfulton $"; + +/* + 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 + String *enumeration_name; //Name of the current enumeration type + Hash *enumeration_items; //and its members + int enumeration_max; + 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 overriden by %pragma + String *m3wrap_modifiers; //class modifiers for module class overriden 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_name(NULL), + enumeration_items(NULL), + enumeration_max(0), + 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 progam 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"); + Close(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); + Close(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); + Close(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"); + Printf(f_runtime, "#define SWIGMODULA3\n"); + Printf(f_runtime, "\n"); + + Swig_name_register((char *) "wrapper", (char *) "Modula3_%f"); + if (old_variable_names) { + Swig_name_register((char *) "set", (char *) "set_%v"); + Swig_name_register((char *) "get", (char *) "get_%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_file_dirname(outfile))); + + 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); + } + Close(file); + } + + // Generate the raw interface + { + File *file = openWriteFile(NewStringf("%s%s.i3", Swig_file_dirname(outfile), 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); + Close(file); + } + + // Generate the raw module + { + File *file = openWriteFile(NewStringf("%s%s.m3", Swig_file_dirname(outfile), 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); + Close(file); + } + + // Generate the interface for the comfort wrappers + { + File *file = openWriteFile(NewStringf("%s%s.i3", Swig_file_dirname(outfile), 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); + Close(file); + } + + // Generate the wrapper routines implemented in Modula 3 + { + File *file = openWriteFile(NewStringf("%s%s.m3", Swig_file_dirname(outfile), 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); + Close(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); + Close(f_begin); + 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 { + Printf(stderr, "%s : Line %d. No return type for %%native method %s.\n", input_file, line_number, 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 != NULL; 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, "$target", Getattr(p, "lname")); /* deprecated */ + 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, "$source", Getattr(p, "emit:input")); /* deprecated */ + 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, "$source", Getattr(p, "emit:input")); /* deprecated */ + Replaceall(tm, "$target", Getattr(p, "lname")); /* deprecated */ + 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); + } + } + + if (Cmp(nodeType(n), "constant") == 0) { + // Wrapping a constant hack + Swig_save("functionWrapper", n, "wrap:action", NIL); + + // below based on Swig_VargetToFunction() + SwigType *ty = Swig_wrapped_var_type(Getattr(n, "type"), use_naturalvar_mode(n)); + Setattr(n, "wrap:action", NewStringf("result = (%s) %s;", SwigType_lstr(ty, 0), Getattr(n, "value"))); + } + + Setattr(n, "wrap:name", wname); + + // Now write code to make the function call + if (!native_function_flag) { + String *actioncode = emit_action(n); + + if (Cmp(nodeType(n), "constant") == 0) { + Swig_restore(n); + } + + /* Return value if necessary */ + String *tm; + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + addThrows(throws_hash, "out", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Replaceall(tm, "$target", "cresult"); /* deprecated */ + 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, "result", 0); + if (tm != NIL) { + addThrows(throws_hash, "newfree", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + 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, "result", 0); + if (tm != NIL) { + Replaceall(tm, "$source", "result"); /* deprecated */ + 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 != NULL; 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); + } + } + +#if 0 + void generateEnumerationItem(const String *name, const String *value, int numvalue) { + String *oldsymname = Getattr(enumeration_items, value); + if (oldsymname != NIL) { + Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "The value <%s> is already assigned to <%s>.\n", value, oldsymname); + } + Setattr(enumeration_items, value, name); + if (enumeration_max < numvalue) { + enumeration_max = numvalue; + } + } +#endif + + 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 != NULL) { + 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 %lx, set %s = %s\n", (long) 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 (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 *classDeclarationName = Getattr(n, "classDeclaration:name"); + + /* Deal with inheritance */ + List *baselist = Getattr(n, "bases"); + if (baselist != NIL) { + Iterator base = First(baselist); + c_baseclassname = Getattr(base.item, "name"); + baseclass = Copy(getProxyName(c_baseclassname)); + if (baseclass) { + c_baseclass = SwigType_namestr(Getattr(base.item, "name")); + } + base = Next(base); + if (base.item != NIL) { + Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, input_file, + line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Modula 3.\n", + classDeclarationName, Getattr(base.item, "name")); + } + } + + bool derived = baseclass && getProxyName(c_baseclassname); + if (!baseclass) + baseclass = NewString(""); + + // Inheritance from pure Modula 3 classes + const String *pure_baseclass = typemapLookup(n, "m3base", classDeclarationName, WARN_NONE); + if (hasContent(pure_baseclass) && hasContent(baseclass)) { + Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, input_file, + line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Modula 3.\n", classDeclarationName, pure_baseclass); + } + // Pure Modula 3 interfaces + const String *pure_interfaces = typemapLookup(n, derived ? "m3interfaces_derived" : "m3interfaces", + classDeclarationName, WARN_NONE); + + // Start writing the proxy class + Printv(proxy_class_def, typemapLookup(n, "m3imports", classDeclarationName, WARN_NONE), // Import statements + "\n", typemapLookup(n, "m3classmodifiers", classDeclarationName, 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", classDeclarationName, 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", classDeclarationName, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:m3destruct_derived:methodname"); + } else { + tm = typemapLookup(n, "m3destruct", classDeclarationName, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:m3destruct:methodname"); + } + if (!destruct_methodname) { + Swig_error(input_file, line_number, "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", classDeclarationName, 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", classDeclarationName, WARN_MODULA3_TYPEMAP_GETCPTR_UNDEF), // getCPtr method + typemapLookup(n, "m3code", classDeclarationName, 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_file_dirname(outfile), 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); + Append(baseclassname, Getattr(base.item, "sym:name")); + base = Next(base); + if (base.item != NIL) { + Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, input_file, + line_number, + "Warning for %s proxy: 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]); + } + if (acc == max_acc) { + String *overrides = Getattr(n, "modula3:override"); + Printf(m3wrap_intf.f, "OVERRIDES\n%s", overrides); + } + Printf(m3wrap_intf.f, "END;\n"); + Delete(baseclassname); + baseclassname = subclass; + } + } + } + + Delete(methods[acc_public]); + Delete(methods[acc_protected]); + Delete(methods[acc_private]); + + } else { + Swig_warning(WARN_MODULA3_TYPECONSTRUCTOR_UNKNOWN, input_file, line_number, "Unknown type constructor %s\n", kind); + } + } + + if (proxy_flag) { + + emitProxyClassDefAndCPPCasts(n); + + Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + + Printf(f_proxy, "}\n"); + Close(f_proxy); + f_proxy = NULL; + + Delete(proxy_class_name); + proxy_class_name = NULL; + Delete(destructor_call); + destructor_call = NULL; + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int memberfunctionHandler(Node *n) { + //printf("begin memberfunctionHandler(%s)\n", Char(Getattr(n,"name"))); + Setattr(n, "modula3:functype", "method"); + Language::memberfunctionHandler(n); + + { + /* Language::memberfunctionHandler will remove the mapped types + that emitM3Wrapper may attach */ + ParmList *pl = Getattr(n, "parms"); + Swig_typemap_attach_parms("m3wrapinmode", pl, NULL); + Swig_typemap_attach_parms("m3wrapinname", pl, NULL); + Swig_typemap_attach_parms("m3wrapintype", pl, NULL); + Swig_typemap_attach_parms("m3wrapindefault", pl, NULL); + attachParameterNames(n, "tmap:m3wrapinname", "autoname", "arg%d"); + String *rettype = getMappedTypeNew(n, "m3wrapouttype", ""); + + String *methodname = Getattr(n, "sym:name"); +/* + if (methodname==NIL) { + methodname = Getattr(n,"name"); + } +*/ + String *arguments = createM3Signature(n); + String *storage = Getattr(n, "storage"); + String *overridden = Getattr(n, "override"); + bool isVirtual = (storage != NIL) && (Strcmp(storage, "virtual") == 0); + bool isOverridden = (overridden != NIL) + && (Strcmp(overridden, "1") == 0); + if ((!isVirtual) || (!isOverridden)) { + { + String *methods = getMethodDeclarations(n); + Printf(methods, "%s(%s)%s%s;%s\n", + methodname, arguments, + hasContent(rettype) ? ": " : "", hasContent(rettype) ? (const String *) rettype : "", isVirtual ? " (* base method *)" : ""); + } + { + /* this was attached by functionWrapper + invoked by Language::memberfunctionHandler */ + String *fname = Getattr(n, "modula3:funcname"); + String *overrides = getAttrString(parentNode(n), "modula3:override"); + Printf(overrides, "%s := %s;\n", methodname, fname); + } + } + } + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(proxy_class_name, overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + //printf("end memberfunctionHandler(%s)\n", Char(Getattr(n,"name"))); + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmemberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + + static_flag = true; + Language::staticmemberfunctionHandler(n); + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(proxy_class_name, overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + static_flag = false; + + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * proxyClassFunctionHandler() + * + * Function called for creating a Modula 3 wrapper function around a c++ function in the + * proxy class. Used for both static and non-static C++ class functions. + * C++ class static functions map to Modula 3 static functions. + * Two extra attributes in the Node must be available. These are "proxyfuncname" - + * the name of the Modula 3 class proxy function, which in turn will call "imfuncname" - + * the intermediary (PInvoke) function name in the intermediary class. + * ----------------------------------------------------------------------------- */ + + void proxyClassFunctionHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + Hash *throws_hash = NewHash(); + String *intermediary_function_name = Getattr(n, "imfuncname"); + String *proxy_function_name = Getattr(n, "proxyfuncname"); + String *tm; + Parm *p; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + bool setter_flag = false; + + if (!proxy_flag) + return; + + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("m3wraptype", l, NULL); + Swig_typemap_attach_parms("m3in", l, NULL); + + /* Get return types */ + if ((tm = getMappedTypeNew(n, "m3wraptype", ""))) { + substituteClassname(t, tm); + Printf(return_type, "%s", tm); + } + + if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { + // Properties + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(Swig_name_member(proxy_class_name, variable_name))) + == 0); + } + + /* Start generating the proxy function */ + Printf(function_code, " %s ", Getattr(n, "feature:modula3:methodmodifiers")); + if (static_flag) + Printf(function_code, "static "); + if (Getattr(n, "override")) + Printf(function_code, "override "); + else if (checkAttribute(n, "storage", "virtual")) + Printf(function_code, "virtual "); + + Printf(function_code, "%s %s(", return_type, proxy_function_name); + + Printv(imcall, m3raw_name, ".", intermediary_function_name, "(", NIL); + if (!static_flag) + Printv(imcall, "swigCPtr", NIL); + + emit_mark_varargs(l); + + int gencomma = !static_flag; + + /* Output each parameter */ + for (i = 0, p = l; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + /* Ignore the 'this' argument for variable wrappers */ + if (!(variable_wrapper_flag && i == 0)) { + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + /* Get the Modula 3 parameter type */ + if ((tm = getMappedType(p, "m3wraptype"))) { + substituteClassname(pt, tm); + Printf(param_type, "%s", tm); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = variable_wrapper_flag ? NewString("value") : makeParameterName(n, + p, + i); + + // Use typemaps to transform type used in Modula 3 wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = getMappedType(p, "in"))) { + addThrows(throws_hash, "in", p); + substituteClassname(pt, tm); + Replaceall(tm, "$input", arg); + Printv(imcall, tm, NIL); + } + + /* Add parameter to proxy function */ + if (gencomma >= 2) + Printf(function_code, ", "); + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + + Delete(arg); + Delete(param_type); + } + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + Printf(function_code, ")"); + + // Transform return type used in PInvoke function (in intermediary class) to type used in Modula 3 wrapper function (in proxy class) + if ((tm = getMappedTypeNew(n, "m3out", ""))) { + addThrows(throws_hash, "m3out", n); + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + } + + generateThrowsClause(throws_hash, function_code); + Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); + + if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { + // Properties + if (setter_flag) { + // Setter method + if ((tm = getMappedTypeNew(n, "m3varin", ""))) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + Printf(proxy_class_code, "%s", tm); + } + } else { + // Getter method + if ((tm = getMappedTypeNew(n, "m3varout", ""))) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + Printf(proxy_class_code, "%s", tm); + } + } + } else { + // Normal function call + Printv(proxy_class_code, function_code, NIL); + } + + Delete(function_code); + Delete(return_type); + Delete(imcall); + Delete(throws_hash); + } + + /* ---------------------------------------------------------------------- + * constructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int constructorHandler(Node *n) { + // this invokes functionWrapper + Language::constructorHandler(n); + + if (proxy_flag) { + ParmList *l = Getattr(n, "parms"); + + Hash *throws_hash = NewHash(); + String *overloaded_name = getOverloadedName(n); + String *imcall = NewString(""); + + Printf(proxy_class_code, " %s %s(", Getattr(n, "feature:modula3:methodmodifiers"), proxy_class_name); + Printv(imcall, " : this(", m3raw_name, ".", Swig_name_construct(overloaded_name), "(", NIL); + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("m3wraptype", l, NULL); + Swig_typemap_attach_parms("m3in", l, NULL); + + emit_mark_varargs(l); + + int gencomma = 0; + + String *tm; + Parm *p = l; + int i; + + /* Output each parameter */ + for (i = 0; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + /* Get the Modula 3 parameter type */ + if ((tm = getMappedType(p, "m3wraptype"))) { + substituteClassname(pt, tm); + Printf(param_type, "%s", tm); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i); + + // Use typemaps to transform type used in Modula 3 wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = getMappedType(p, "in"))) { + addThrows(throws_hash, "in", p); + substituteClassname(pt, tm); + Replaceall(tm, "$input", arg); + Printv(imcall, tm, NIL); + } + + /* Add parameter to proxy function */ + if (gencomma) + Printf(proxy_class_code, ", "); + Printf(proxy_class_code, "%s %s", param_type, arg); + gencomma = 1; + + Delete(arg); + Delete(param_type); + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, "), true)"); + + Printf(proxy_class_code, ")"); + Printf(proxy_class_code, "%s", imcall); + generateThrowsClause(throws_hash, proxy_class_code); + Printf(proxy_class_code, " {\n"); + Printf(proxy_class_code, " }\n\n"); + + if (!gencomma) // We must have a default constructor + have_default_constructor_flag = true; + + Delete(overloaded_name); + Delete(imcall); + Delete(throws_hash); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * destructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int destructorHandler(Node *n) { + Language::destructorHandler(n); + String *symname = Getattr(n, "sym:name"); + + if (proxy_flag) { + Printv(destructor_call, m3raw_name, ".", Swig_name_destroy(symname), "(swigCPtr)", NIL); + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * membervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int membervariableHandler(Node *n) { + //printf("begin membervariableHandler(%s)\n", Char(Getattr(n,"name"))); + 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"); + //printf("member variable: %s\n", Char(variable_name)); + + // Output the property's field declaration and accessor methods + Printf(proxy_class_code, " public %s %s {", tm, variable_name); + + Setattr(n, "modula3:functype", "accessor"); + wrapping_member_flag = true; + variable_wrapper_flag = true; + Language::membervariableHandler(n); + wrapping_member_flag = false; + variable_wrapper_flag = false; + + Printf(proxy_class_code, "\n }\n\n"); + + { + String *methods = getMethodDeclarations(n); + String *overrides = getAttrString(parentNode(n), "modula3:override"); + SwigType *type = Getattr(n, "type"); + String *m3name = capitalizeFirst(variable_name); + //String *m3name = nameToModula3(variable_name,true); + if (!SwigType_isconst(type)) { + { + String *inmode = getMappedTypeNew(n, "m3wrapinmode", "", false); + String *intype = getMappedTypeNew(n, "m3wrapintype", ""); + Printf(methods, "set%s(%s val:%s);\n", m3name, (inmode != NIL) ? (const String *) inmode : "", intype); + } + { + /* this was attached by functionWrapper + invoked by Language::memberfunctionHandler */ + String *fname = Getattr(n, "modula3:setname"); + Printf(overrides, "set%s := %s;\n", m3name, fname); + } + } + { + { + String *outtype = getMappedTypeNew(n, "m3wrapouttype", ""); + Printf(methods, "get%s():%s;\n", m3name, outtype); + } + { + /* this was attached by functionWrapper + invoked by Language::memberfunctionHandler */ + String *fname = Getattr(n, "modula3:getname"); + Printf(overrides, "get%s := %s;\n", m3name, fname); + } + } + Delete(m3name); + } + //printf("end membervariableHandler(%s)\n", Char(Getattr(n,"name"))); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmembervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + + bool static_const_member_flag = (Getattr(n, "value") == 0); + if (static_const_member_flag) { + SwigType *t = Getattr(n, "type"); + String *tm; + + // Get the variable type + if ((tm = getMappedTypeNew(n, "m3wraptype", ""))) { + substituteClassname(t, tm); + } + // Output the property's field declaration and accessor methods + Printf(proxy_class_code, " public static %s %s {", tm, Getattr(n, "sym:name")); + } + + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + static_flag = true; + Language::staticmembervariableHandler(n); + wrapping_member_flag = false; + static_flag = false; + + if (static_const_member_flag) + Printf(proxy_class_code, "\n }\n\n"); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberconstantHandler() + * ---------------------------------------------------------------------- */ + + virtual int memberconstantHandler(Node *n) { + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + Language::memberconstantHandler(n); + wrapping_member_flag = false; + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * getOverloadedName() + * ----------------------------------------------------------------------------- */ + + String *getOverloadedName(Node *n) { + String *overloaded_name = Copy(Getattr(n, "sym:name")); + + if (Getattr(n, "sym:overloaded")) { + Printv(overloaded_name, Getattr(n, "sym:overname"), NIL); + } + + return overloaded_name; + } + + /* ----------------------------------------------------------------------------- + * emitM3Wrapper() + * It is also used for set and get methods of global variables. + * ----------------------------------------------------------------------------- */ + + void emitM3Wrapper(Node *n, const String *func_name) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + Hash *throws_hash = NewHash(); + int num_exceptions = 0; + int num_returns = 0; + String *rawcall = NewString(""); + String *reccall = NewString(""); + String *local_variables = NewString(""); + String *local_constants = NewString(""); + String *incheck = NewString(""); + String *outcheck = NewString(""); + String *setup = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); /* don't mix up with 'autark' :-] */ + String *storeout = NewString(""); + String *result_name = NewString(""); + String *return_variables = NewString(""); + const char *result_return = "ret"; + String *function_code = NewString(""); + /*several names for the same function */ + String *raw_name = Getattr(n, "name"); /*original C function name */ + //String *func_name = Getattr(n,"sym:name"); /*final Modula3 name chosen by the user*/ + bool setter_flag = false; + int multiretval = GetFlag(n, "feature:modula3:multiretval"); + + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("m3wrapargvar", l, NULL); + Swig_typemap_attach_parms("m3wrapargconst", l, NULL); + Swig_typemap_attach_parms("m3wrapargraw", l, NULL); + Swig_typemap_attach_parms("m3wrapargdir", l, NULL); + Swig_typemap_attach_parms("m3wrapinmode", l, NULL); + Swig_typemap_attach_parms("m3wrapinname", l, NULL); + Swig_typemap_attach_parms("m3wrapintype", l, NULL); + Swig_typemap_attach_parms("m3wrapindefault", l, NULL); + Swig_typemap_attach_parms("m3wrapinconv", l, NULL); + Swig_typemap_attach_parms("m3wrapincheck", l, NULL); + Swig_typemap_attach_parms("m3wrapoutname", l, NULL); + Swig_typemap_attach_parms("m3wrapouttype", l, NULL); + Swig_typemap_attach_parms("m3wrapoutconv", l, NULL); + Swig_typemap_attach_parms("m3wrapoutcheck", l, NULL); + + attachMappedType(n, "m3wrapretraw"); + attachMappedType(n, "m3wrapretname"); + attachMappedType(n, "m3wraprettype"); + attachMappedType(n, "m3wrapretvar"); + attachMappedType(n, "m3wrapretconv"); + attachMappedType(n, "m3wrapretcheck"); + + Swig_typemap_attach_parms("m3wrapfreearg", l, NULL); + +/* + Swig_typemap_attach_parms("m3wrapargvar:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapargraw:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapinconv:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapincheck:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapoutconv:throws", l, NULL); + Swig_typemap_attach_parms("m3wrapoutcheck:throws", l, NULL); + + attachMappedType(n, "m3wrapretvar:throws"); + attachMappedType(n, "m3wrapretconv:throws"); + attachMappedType(n, "m3wrapretcheck:throws"); + + Swig_typemap_attach_parms("m3wrapfreearg:throws", l, NULL); +*/ + + /* Attach argument names to the parameter list */ + /* should be a separate procedure making use of hashes */ + attachParameterNames(n, "tmap:m3wrapinname", "autoname", "arg%d"); + + /* Get return types */ + String *result_m3rawtype = Copy(getMappedTypeNew(n, "m3rawrettype", "")); + String *result_m3wraptype = Copy(getMappedTypeNew(n, "m3wraprettype", "")); + bool has_return_raw = hasContent(result_m3rawtype); + bool has_return_m3 = hasContent(result_m3wraptype); + if (has_return_m3) { + num_returns++; + //printf("%s: %s\n", Char(func_name),Char(result_m3wraptype)); + } + + String *arguments = createM3Signature(n); + + /* Create local variables or RECORD fields for return values + and determine return type that might result from a converted VAR argument. */ + { + writeArgState state; + if (multiretval && has_return_m3) { + writeArg(return_variables, state, NIL, NewString(result_return), result_m3wraptype, NIL); + } + + Parm *p = skipIgnored(l, "m3wrapouttype"); + while (p != NIL) { + + String *arg = Getattr(p, "tmap:m3wrapoutname"); + if (arg == NIL) { + arg = Getattr(p, "name"); + } + + String *tm = Getattr(p, "tmap:m3wrapouttype"); + if (tm != NIL) { + if (isOutParam(p)) { + if (!multiretval) { + if (num_returns == 0) { + Printv(result_name, arg, NIL); + Clear(result_m3wraptype); + Printv(result_m3wraptype, tm, NIL); + } else { + Swig_warning(WARN_MODULA3_TYPEMAP_MULTIPLE_RETURN, input_file, line_number, + "Typemap m3wrapargdir set to 'out' for %s implies a RETURN value, but the routine %s has already one.\nUse %%multiretval feature.\n", + SwigType_str(Getattr(p, "type"), 0), raw_name); + } + } + num_returns++; + addImports(m3wrap_intf.import, "m3wrapouttype", p); + writeArg(return_variables, state, NIL, arg, tm, NIL); + } + p = skipIgnored(Getattr(p, "tmap:m3wrapouttype:next"), "m3wrapouttype"); + } else { + p = nextSibling(p); + } + } + writeArg(return_variables, state, NIL, NIL, NIL, NIL); + + if (multiretval) { + Printv(result_name, "result", NIL); + Printf(result_m3wraptype, "%sResult", func_name); + m3wrap_intf.enterBlock(blocktype); + Printf(m3wrap_intf.f, "%s =\nRECORD\n%sEND;\n", result_m3wraptype, return_variables); + Printf(local_variables, "%s: %s;\n", result_name, result_m3wraptype); + } else { + Append(local_variables, return_variables); + } + } + + /* Declare local constants e.g. for storing argument names. */ + { + Parm *p = l; + while (p != NIL) { + + String *arg = Getattr(p, "autoname"); + + String *tm = Getattr(p, "tmap:m3wrapargconst"); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapargconst", p); + Replaceall(tm, "$input", arg); + Printv(local_constants, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapargconst:next"); + } else { + p = nextSibling(p); + } + + } + } + + /* Declare local variables e.g. for converted input values. */ + { + String *tm = getMappedTypeNew(n, "m3wrapretvar", "", false); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapretvar", n); + addThrows(throws_hash, "m3wrapretvar", n); + Printv(local_variables, tm, "\n", NIL); + } + + Parm *p = l; + while (p != NIL) { + + String *arg = Getattr(p, "autoname"); + + tm = Getattr(p, "tmap:m3wrapargvar"); + if (tm != NIL) { + /* exceptions that may be raised but can't be catched, + thus we won't count them in num_exceptions */ + addImports(m3wrap_impl.import, "m3wrapargvar", p); + addThrows(throws_hash, "m3wrapargvar", p); + Replaceall(tm, "$input", arg); + Printv(local_variables, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapargvar:next"); + } else { + p = nextSibling(p); + } + + } + } + + /* Convert input values from Modula 3 to C. */ + { + Parm *p = l; + while (p != NIL) { + + String *arg = Getattr(p, "autoname"); + + String *tm = Getattr(p, "tmap:m3wrapinconv"); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapinconv", p); + num_exceptions += addThrows(throws_hash, "m3wrapinconv", p); + Replaceall(tm, "$input", arg); + Printv(setup, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapinconv:next"); + } else { + p = nextSibling(p); + } + + } + } + + /* Generate checks for input value integrity. */ + { + Parm *p = l; + while (p != NIL) { + + String *arg = Getattr(p, "autoname"); + + String *tm = Getattr(p, "tmap:m3wrapincheck"); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapincheck", p); + num_exceptions += addThrows(throws_hash, "m3wrapincheck", p); + Replaceall(tm, "$input", arg); + Printv(incheck, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapincheck:next"); + } else { + p = nextSibling(p); + } + + } + } + + Printv(rawcall, m3raw_name, ".", func_name, "(", NIL); + /* Arguments to the raw C function */ + { + bool gencomma = false; + Parm *p = l; + while (p != NIL) { + if (gencomma) { + Printf(rawcall, ", "); + } + gencomma = true; + addImports(m3wrap_impl.import, "m3wrapargraw", p); + num_exceptions += addThrows(throws_hash, "m3wrapargraw", p); + + String *arg = Getattr(p, "autoname"); + String *qualarg = NewString(""); + if (!isInParam(p)) { + String *tmparg = Getattr(p, "tmap:m3wrapoutname"); + if (tmparg != NIL) { + arg = tmparg; + } + if (multiretval /*&& isOutParam(p) - automatically fulfilled */ ) { + Printf(qualarg, "%s.", result_name); + } + } + Append(qualarg, arg); + Setattr(p, "m3outarg", qualarg); + + String *tm = Getattr(p, "tmap:m3wrapargraw"); + if (tm != NIL) { + Replaceall(tm, "$input", arg); + Replaceall(tm, "$output", qualarg); + Printv(rawcall, tm, NIL); + p = Getattr(p, "tmap:m3wrapargraw:next"); + } else { + //Printv(rawcall, Getattr(p,"lname"), NIL); + Printv(rawcall, qualarg, NIL); + p = nextSibling(p); + } + Delete(qualarg); + } + } + Printf(rawcall, ")"); + + /* Check for error codes and integrity of results */ + { + String *tm = getMappedTypeNew(n, "m3wrapretcheck", "", false); + if (tm != NIL) { + addImports(m3wrap_impl.import, "m3wrapretcheck", n); + num_exceptions += addThrows(throws_hash, "m3wrapretcheck", n); + Printv(outcheck, tm, "\n", NIL); + } + + Parm *p = l; + while (p != NIL) { + tm = Getattr(p, "tmap:m3wrapoutcheck"); + if (tm != NIL) { + String *arg = Getattr(p, "autoname"); + String *outarg = Getattr(p, "m3outarg"); + addImports(m3wrap_impl.import, "m3wrapoutcheck", p); + num_exceptions += addThrows(throws_hash, "m3wrapoutcheck", p); + //substituteClassname(Getattr(p,"type"), tm); + Replaceall(tm, "$input", arg); + Replaceall(tm, "$output", outarg); + Printv(outcheck, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapoutcheck:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Convert the results to Modula 3 data structures and + put them in the record prepared for returning */ + { + /* m3wrapretconv is processed + when it is clear if there is some output conversion and checking code */ + Parm *p = l; + while (p != NIL) { + String *tm = Getattr(p, "tmap:m3wrapoutconv"); + if (tm != NIL) { + String *arg = Getattr(p, "autoname"); + String *outarg = Getattr(p, "m3outarg"); + addImports(m3wrap_impl.import, "m3wrapoutconv", n); + num_exceptions += addThrows(throws_hash, "m3wrapoutconv", p); + //substituteClassname(Getattr(p,"type"), tm); + Replaceall(tm, "$input", arg); + Replaceall(tm, "$output", outarg); + Printf(storeout, "%s := %s;\n", outarg, tm); + p = Getattr(p, "tmap:m3wrapoutconv:next"); + } else { + p = nextSibling(p); + } + } + } + + /* Generate cleanup code */ + { + Parm *p = l; + while (p != NIL) { + String *tm = Getattr(p, "tmap:m3wrapfreearg"); + if (tm != NIL) { + String *arg = Getattr(p, "autoname"); + String *outarg = Getattr(p, "m3outarg"); + addImports(m3wrap_impl.import, "m3wrapfreearg", p); + num_exceptions += addThrows(throws_hash, "m3wrapfreearg", p); + //substituteClassname(Getattr(p,"type"), tm); + Replaceall(tm, "$input", arg); + Replaceall(tm, "$output", outarg); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:m3wrapfreearg:next"); + } else { + p = nextSibling(p); + } + } + } + + { + /* Currently I don't know how a typemap similar to the original 'out' typemap + could help returning the return value. */ + /* Receive result from call to raw library function */ + if (!has_return_raw) { + /* + rawcall(arg1); + result.val := arg1; + RETURN result; + */ + /* + rawcall(arg1); + RETURN arg1; + */ + Printf(reccall, "%s;\n", rawcall); + + if (hasContent(result_name)) { + Printf(outarg, "RETURN %s;\n", result_name); + } + } else { + /* + arg0 := rawcall(arg1); + result.ret := Convert(arg0); + result.val := arg1; + RETURN result; + */ + /* + arg0 := rawcall(); + RETURN Convert(arg0); + */ + /* + RETURN rawcall(); + */ + String *return_raw = getMappedTypeNew(n, "m3wrapretraw", "", false); + String *return_conv = getMappedTypeNew(n, "m3wrapretconv", "", false); + + /* immediate RETURN would skip result checking */ + if ((hasContent(outcheck) || hasContent(storeout) + || hasContent(cleanup)) && (!hasContent(result_name)) + && (return_raw == NIL)) { + Printv(result_name, "result", NIL); + Printf(local_variables, "%s: %s;\n", result_name, result_m3wraptype); + } + + String *result_lvalue = Copy(result_name); + if (multiretval) { + Printf(result_lvalue, ".%s", result_return); + } + if (return_raw != NIL) { + Printf(reccall, "%s := %s;\n", return_raw, rawcall); + } else if (hasContent(result_name)) { + Printf(reccall, "%s := %s;\n", result_lvalue, rawcall); + } else { + Printf(outarg, "RETURN %s;\n", rawcall); + } + if (return_conv != NIL) { + addImports(m3wrap_impl.import, "m3wrapretconv", n); + num_exceptions += addThrows(throws_hash, "m3wrapretconv", n); + if (hasContent(result_name)) { + Printf(reccall, "%s := %s;\n", result_lvalue, return_conv); + Printf(outarg, "RETURN %s;\n", result_name); + } else { + Printf(outarg, "RETURN %s;\n", return_conv); + } + } else { + if (hasContent(result_name)) { + Printf(outarg, "RETURN %s;\n", result_name); + } + } + } + } + + /* Create procedure header */ + { + String *header = NewStringf("PROCEDURE %s (%s)", + func_name, arguments); + + if ((num_returns > 0) || multiretval) { + Printf(header, ": %s", result_m3wraptype); + } + generateThrowsClause(throws_hash, header); + + Append(function_code, header); + + m3wrap_intf.enterBlock(no_block); + Printf(m3wrap_intf.f, "%s;\n\n", header); + } + + { + String *body = NewStringf("%s%s%s%s%s", + incheck, + setup, + reccall, + outcheck, + storeout); + + String *exc_handler; + if (hasContent(cleanup) && (num_exceptions > 0)) { + exc_handler = NewStringf("TRY\n%sFINALLY\n%sEND;\n", body, cleanup); + } else { + exc_handler = NewStringf("%s%s", body, cleanup); + } + + Printf(function_code, " =\n%s%s%s%sBEGIN\n%s%sEND %s;\n\n", + hasContent(local_constants) ? "CONST\n" : "", local_constants, + hasContent(local_variables) ? "VAR\n" : "", local_variables, exc_handler, outarg, func_name); + + Delete(exc_handler); + Delete(body); + } + + m3wrap_impl.enterBlock(no_block); + if (proxy_flag && global_variable_flag) { + // Properties + if (setter_flag) { + // Setter method + String *tm = getMappedTypeNew(n, "m3varin", ""); + if (tm != NIL) { + if (GetFlag(n, "feature:new")) { + Replaceall(tm, "$owner", "true"); + } else { + Replaceall(tm, "$owner", "false"); + } + substituteClassname(t, tm); + Replaceall(tm, "$rawcall", rawcall); + Replaceall(tm, "$vartype", variable_type); /* $type is already replaced by some super class */ + Replaceall(tm, "$var", variable_name); + Printf(m3wrap_impl.f, "%s", tm); + } + } else { + // Getter method + String *tm = getMappedTypeNew(n, "m3varout", ""); + if (tm != NIL) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$rawcall", rawcall); + Replaceall(tm, "$vartype", variable_type); + Replaceall(tm, "$var", variable_name); + Printf(m3wrap_impl.f, "%s", tm); + } + } + } else { + // Normal function call + Printv(m3wrap_impl.f, function_code, NIL); + } + + Delete(arguments); + Delete(return_variables); + Delete(local_variables); + Delete(local_constants); + Delete(outarg); + Delete(incheck); + Delete(outcheck); + Delete(setup); + Delete(cleanup); + Delete(storeout); + Delete(function_code); + Delete(result_name); + Delete(result_m3wraptype); + Delete(reccall); + Delete(rawcall); + Delete(throws_hash); + } + + /*---------------------------------------------------------------------- + * replaceSpecialVariables() + *--------------------------------------------------------------------*/ + + virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) { + (void)method; + SwigType *type = Getattr(parm, "type"); + substituteClassname(type, tm); + } + + /* ----------------------------------------------------------------------------- + * substituteClassname() + * + * Substitute the special variable $m3classname with the proxy class name for classes/structs/unions + * that SWIG knows about. + * Otherwise use the $descriptor name for the Modula 3 class name. Note that the $&m3classname substitution + * is the same as a $&descriptor substitution, ie one pointer added to descriptor name. + * Inputs: + * pt - parameter type + * tm - typemap contents that might contain the special variable to be replaced + * Outputs: + * tm - typemap contents complete with the special variable substitution + * Return: + * substitution_performed - flag indicating if a substitution was performed + * ----------------------------------------------------------------------------- */ + + bool substituteClassname(SwigType *pt, String *tm) { + bool substitution_performed = false; + if (Strstr(tm, "$m3classname") || Strstr(tm, "$&m3classname")) { + String *classname = getProxyName(pt); + if (classname) { + Replaceall(tm, "$&m3classname", classname); // getProxyName() works for pointers to classes too + Replaceall(tm, "$m3classname", classname); + } else { // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. + String *descriptor = NULL; + SwigType *type = Copy(SwigType_typedef_resolve_all(pt)); + + if (Strstr(tm, "$&m3classname")) { + SwigType_add_pointer(type); + descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(type)); + Replaceall(tm, "$&m3classname", descriptor); + } else { // $m3classname + descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(type)); + Replaceall(tm, "$m3classname", descriptor); + } + + // Add to hash table so that the type wrapper classes can be created later + Setattr(swig_types_hash, descriptor, type); + Delete(descriptor); + Delete(type); + } + substitution_performed = true; + } + return substitution_performed; + } + + /* ----------------------------------------------------------------------------- + * makeParameterName() + * + * Inputs: + * n - Node + * p - parameter node + * arg_num - parameter argument number + * Return: + * arg - a unique parameter name + * ----------------------------------------------------------------------------- */ + + String *makeParameterName(Node *n, Parm *p, int arg_num) { + + // Use C parameter name unless it is a duplicate or an empty parameter name + String *pn = Getattr(p, "name"); + int count = 0; + ParmList *plist = Getattr(n, "parms"); + while (plist) { + if ((Cmp(pn, Getattr(plist, "name")) == 0)) + count++; + plist = nextSibling(plist); + } + String *arg = (!pn || (count > 1)) ? NewStringf("arg%d", + arg_num) : Copy(Getattr(p, + "name")); + + return arg; + } + + /* ----------------------------------------------------------------------------- + * attachParameterNames() + * + * Inputs: + * n - Node of a function declaration + * tmid - attribute name for overriding C argument names, + * e.g. "tmap:m3wrapinname", + * don't forget to attach the mapped types before + * nameid - attribute for attaching the names, + * e.g. "modula3:inname" + * fmt - format for the argument name containing %d + * e.g. "arg%d" + * ----------------------------------------------------------------------------- */ + + void attachParameterNames(Node *n, const char *tmid, const char *nameid, const char *fmt) { + /* Use C parameter name if present and unique, + otherwise create an 'arg%d' name */ + Hash *hash = NewHash(); + Parm *p = Getattr(n, "parms"); + int count = 0; + while (p != NIL) { + String *name = Getattr(p, tmid); + if (name == NIL) { + name = Getattr(p, "name"); + } + String *newname; + if ((!hasContent(name)) || (Getattr(hash, name) != NIL)) { + newname = NewStringf(fmt, count); + } else { + newname = Copy(name); + } + if (1 == Setattr(hash, newname, "1")) { + Swig_warning(WARN_MODULA3_DOUBLE_ID, input_file, line_number, "Argument '%s' twice.\n", newname); + } + Setattr(p, nameid, newname); +// Delete(newname); + p = nextSibling(p); + count++; + } + Delete(hash); + } + + /* ----------------------------------------------------------------------------- + * createM3Signature() + * + * Create signature of M3 wrapper procedure + * Call attachParameterNames and attach mapped types before! + * m3wrapintype, m3wrapinmode, m3wrapindefault + * ----------------------------------------------------------------------------- */ + + String *createM3Signature(Node *n) { + String *arguments = NewString(""); + Parm *p = skipIgnored(Getattr(n, "parms"), "m3wrapintype"); + writeArgState state; + while (p != NIL) { + + /* Get the M3 parameter type */ + String *tm = getMappedType(p, "m3wrapintype"); + if (tm != NIL) { + if (isInParam(p)) { + addImports(m3wrap_intf.import, "m3wrapintype", p); + addImports(m3wrap_impl.import, "m3wrapintype", p); + String *mode = Getattr(p, "tmap:m3wrapinmode"); + String *deflt = Getattr(p, "tmap:m3wrapindefault"); + String *arg = Getattr(p, "autoname"); + SwigType *pt = Getattr(p, "type"); + substituteClassname(pt, tm); /* do we need this ? */ + + writeArg(arguments, state, mode, arg, tm, deflt); + } + p = skipIgnored(Getattr(p, "tmap:m3wrapintype:next"), "m3wrapintype"); + } else { + p = nextSibling(p); + } + } + writeArg(arguments, state, NIL, NIL, NIL, NIL); + return (arguments); + } + +/* not used any longer + - try SwigType_str if required again */ +#if 0 + /* ----------------------------------------------------------------------------- + * createCSignature() + * + * Create signature of C function + * ----------------------------------------------------------------------------- */ + + String *createCSignature(Node *n) { + String *arguments = NewString(""); + bool gencomma = false; + Node *p; + for (p = Getattr(n, "parms"); p != NIL; p = nextSibling(p)) { + if (gencomma) { + Append(arguments, ","); + } + gencomma = true; + String *type = Getattr(p, "type"); + String *ctype = getMappedTypeNew(type, "ctype"); + Append(arguments, ctype); + } + return arguments; + } +#endif + + /* ----------------------------------------------------------------------------- + * emitTypeWrapperClass() + * ----------------------------------------------------------------------------- */ + + void emitTypeWrapperClass(String *classname, SwigType *type) { + Node *n = NewHash(); + Setfile(n, input_file); + Setline(n, line_number); + + String *filen = NewStringf("%s%s.m3", Swig_file_dirname(outfile), classname); + File *f_swigtype = NewFile(filen, "w", SWIG_output_files()); + if (!f_swigtype) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + String *swigtype = NewString(""); + + // Emit banner name + emitBanner(f_swigtype); + + // Pure Modula 3 baseclass and interfaces + const String *pure_baseclass = typemapLookup(n, "m3base", type, WARN_NONE); + const String *pure_interfaces = typemapLookup(n, "m3interfaces", type, WARN_NONE); + + // Emit the class + Printv(swigtype, typemapLookup(n, "m3imports", type, WARN_NONE), // Import statements + "\n", typemapLookup(n, "m3classmodifiers", type, WARN_MODULA3_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " class $m3classname", // Class name and bases + *Char(pure_baseclass) ? " : " : "", pure_baseclass, *Char(pure_interfaces) ? // Interfaces + " : " : "", pure_interfaces, " {\n", " private IntPtr swigCPtr;\n", "\n", " ", typemapLookup(n, "m3ptrconstructormodifiers", type, WARN_MODULA3_TYPEMAP_PTRCONSTMOD_UNDEF), // pointer constructor modifiers + " $m3classname(IntPtr cPtr, bool bFutureUse) {\n", // Constructor used for wrapping pointers + " swigCPtr = cPtr;\n", " }\n", "\n", " protected $m3classname() {\n", // Default constructor + " swigCPtr = IntPtr.Zero;\n", " }\n", typemapLookup(n, "m3getcptr", type, WARN_MODULA3_TYPEMAP_GETCPTR_UNDEF), // getCPtr method + typemapLookup(n, "m3code", type, WARN_NONE), // extra Modula 3 code + "}\n", "\n", NIL); + + Replaceall(swigtype, "$m3classname", classname); + Printv(f_swigtype, swigtype, NIL); + + Close(f_swigtype); + Delete(filen); + Delete(swigtype); + } + + /* ----------------------------------------------------------------------------- + * typemapLookup() + * n - for input only and must contain info for Getfile(n) and Getline(n) to work + * tmap_method - typemap method name + * type - typemap type to lookup + * warning - warning number to issue if no typemaps found + * typemap_attributes - the typemap attributes are attached to this node and will + * also be used for temporary storage if non null + * return is never NULL, unlike Swig_typemap_lookup() + * ----------------------------------------------------------------------------- */ + + const String *typemapLookup(Node *n, const_String_or_char_ptr tmap_method, SwigType *type, int warning, Node *typemap_attributes = 0) { + Node *node = !typemap_attributes ? NewHash() : typemap_attributes; + Setattr(node, "type", type); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0); + if (!tm) { + tm = empty_string; + if (warning != WARN_NONE) + Swig_warning(warning, Getfile(n), Getline(n), "No %s typemap defined for %s\n", tmap_method, SwigType_str(type, 0)); + } + if (!typemap_attributes) + Delete(node); + return tm; + } + + /* ----------------------------------------------------------------------------- + * addThrows() + * + * Add all exceptions to a hash that are associated with the 'typemap'. + * Return number the number of these exceptions. + * ----------------------------------------------------------------------------- */ + + int addThrows(Hash *throws_hash, const String *typemap, Node *parameter) { + // Get the comma separated throws clause - held in "throws" attribute in the typemap passed in + int len = 0; + String *throws_attribute = NewStringf("%s:throws", typemap); + + addImports(m3wrap_intf.import, throws_attribute, parameter); + addImports(m3wrap_impl.import, throws_attribute, parameter); + + String *throws = getMappedTypeNew(parameter, Char(throws_attribute), "", false); + //printf("got exceptions %s for %s\n", Char(throws), Char(throws_attribute)); + + if (throws) { + // Put the exception classes in the throws clause into a temporary List + List *temp_classes_list = Split(throws, ',', INT_MAX); + len = Len(temp_classes_list); + + // Add the exception classes to the node throws list, but don't duplicate if already in list + if (temp_classes_list /*&& hasContent(temp_classes_list) */ ) { + for (Iterator cls = First(temp_classes_list); cls.item != NIL; cls = Next(cls)) { + String *exception_class = NewString(cls.item); + Replaceall(exception_class, " ", ""); // remove spaces + Replaceall(exception_class, "\t", ""); // remove tabs + if (hasContent(exception_class)) { + // $m3classname substitution + SwigType *pt = Getattr(parameter, "type"); + substituteClassname(pt, exception_class); + // Don't duplicate the exception class in the throws clause + //printf("add exception %s\n", Char(exception_class)); + Setattr(throws_hash, exception_class, "1"); + } + Delete(exception_class); + } + } + Delete(temp_classes_list); + } + Delete(throws_attribute); + return len; + } + + /* ----------------------------------------------------------------------------- + * generateThrowsClause() + * ----------------------------------------------------------------------------- */ + + void generateThrowsClause(Hash *throws_hash, String *code) { + // Add the throws clause into code + if (Len(throws_hash) > 0) { + Iterator cls = First(throws_hash); + Printf(code, " RAISES {%s", cls.key); + for (cls = Next(cls); cls.key != NIL; cls = Next(cls)) { + Printf(code, ", %s", cls.key); + } + Printf(code, "}"); + } + } + + /* ----------------------------------------------------------------------------- + * addImports() + * + * Add all imports that are needed for contents of 'typemap'. + * ----------------------------------------------------------------------------- */ + + void addImports(Hash *imports_hash, const String *typemap, Node *node) { + // Get the comma separated throws clause - held in "throws" attribute in the typemap passed in + String *imports_attribute = NewStringf("%s:import", typemap); + String *imports = getMappedTypeNew(node, Char(imports_attribute), "", false); + //printf("got imports %s for %s\n", Char(imports), Char(imports_attribute)); + + if (imports != NIL) { + List *import_list = Split(imports, ',', INT_MAX); + + // Add the exception classes to the node imports list, but don't duplicate if already in list + if (import_list != NIL) { + for (Iterator imp = First(import_list); imp.item != NIL; imp = Next(imp)) { + List *import_pair = Split(imp.item, ' ', 3); + if (Len(import_pair) == 1) { + Setattr(imports_hash, Getitem(import_pair, 0), ""); + } else if ((Len(import_pair) == 3) + && Strcmp(Getitem(import_pair, 1), "AS") == 0) { + Setattr(imports_hash, Getitem(import_pair, 0), Getitem(import_pair, 2)); + } else { + Swig_warning(WARN_MODULA3_BAD_IMPORT, input_file, line_number, + "Malformed import '%s' for typemap '%s' defined for type '%s'\n", imp, typemap, SwigType_str(Getattr(node, "type"), 0)); + } + Delete(import_pair); + } + } + Delete(import_list); + } + Delete(imports_attribute); + } + + /* ----------------------------------------------------------------------------- + * emitImportStatements() + * ----------------------------------------------------------------------------- */ + + void emitImportStatements(Hash *imports_hash, String *code) { + // Add the imports statements into code + Iterator imp = First(imports_hash); + while (imp.key != NIL) { + Printf(code, "IMPORT %s", imp.key); + String *imp_as = imp.item; + if (hasContent(imp_as)) { + Printf(code, " AS %s", imp_as); + } + Printf(code, ";\n"); + imp = Next(imp); + } + } + +}; /* class MODULA3 */ + +/* ----------------------------------------------------------------------------- + * swig_modula3() - Instantiate module + * ----------------------------------------------------------------------------- */ + +extern "C" Language *swig_modula3(void) { + return new MODULA3(); +} + +/* ----------------------------------------------------------------------------- + * Static member variables + * ----------------------------------------------------------------------------- */ + +const char *MODULA3::usage = (char *) "\ +Modula 3 Options (available with -modula3)\n\ + -generateconst <file> - generate code for computing numeric values of constants\n\ + -generaterename <file> - generate suggestions for %rename\n\ + -generatetypemap <file> - generate templates for some basic typemaps\n\ + -oldvarnames - old intermediary method names for variable wrappers\n\ +\n"; + +/* + -generateconst <file> - stem of the .c source file for computing the numeric values of constants\n\ + -generaterename <file> - stem of the .i source file containing %rename suggestions\n\ + -generatetypemap <file> - stem of the .i source file containing typemap patterns\n\ +*/ |