mirror of https://github.com/swig/swig
3989 lines
132 KiB
C++
3989 lines
132 KiB
C++
/* -----------------------------------------------------------------------------
|
|
* This file is part of SWIG, which is licensed as a whole under version 3
|
|
* (or any later version) of the GNU General Public License. Some additional
|
|
* terms also apply to certain portions of SWIG. The full details of the SWIG
|
|
* license and copyrights can be found in the LICENSE and COPYRIGHT files
|
|
* included with the SWIG source code as distributed by the SWIG developers
|
|
* and at http://www.swig.org/legal.html.
|
|
*
|
|
* modula3.cxx
|
|
*
|
|
* Modula3 language module for SWIG.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
char cvsroot_modula3_cxx[] = "$Id$";
|
|
|
|
/*
|
|
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("wrapper", "Modula3_%f");
|
|
if (old_variable_names) {
|
|
Swig_name_register("set", "set_%n%v");
|
|
Swig_name_register("get", "get_%n%v");
|
|
}
|
|
|
|
Printf(f_wrappers, "\n#ifdef __cplusplus\n");
|
|
Printf(f_wrappers, "extern \"C\" {\n");
|
|
Printf(f_wrappers, "#endif\n\n");
|
|
|
|
constant_values = NewHash();
|
|
scanForConstPragmas(n);
|
|
enumeration_coll = NewHash();
|
|
collectEnumerations(enumeration_coll, n);
|
|
|
|
/* Emit code */
|
|
Language::top(n);
|
|
|
|
// Generate m3makefile
|
|
// This will be unnecessary if SWIG is invoked from Quake.
|
|
{
|
|
File *file = openWriteFile(NewStringf("%sm3makefile", Swig_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 {
|
|
Swig_error(input_file, line_number, "No return type for %%native method %s.\n", Getattr(n, "wrap:name"));
|
|
}
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* functionWrapper()
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
virtual int functionWrapper(Node *n) {
|
|
String *type = nodeType(n);
|
|
String *funcType = Getattr(n, "modula3:functype");
|
|
String *rawname = Getattr(n, "name");
|
|
String *symname = Getattr(n, "sym:name");
|
|
String *capname = capitalizeFirst(symname);
|
|
//String *wname = Swig_name_wrapper(symname);
|
|
|
|
//printf("function: %s\n", Char(symname));
|
|
//printf(" purpose: %s\n", Char(funcType));
|
|
|
|
if (Strcmp(type, "cdecl") == 0) {
|
|
if (funcType == NIL) {
|
|
// no wrapper needed for plain functions
|
|
emitM3RawPrototype(n, rawname, symname);
|
|
emitM3Wrapper(n, symname);
|
|
} else if (Strcmp(funcType, "method") == 0) {
|
|
Setattr(n, "modula3:funcname", capname);
|
|
emitCWrapper(n, capname);
|
|
emitM3RawPrototype(n, capname, capname);
|
|
emitM3Wrapper(n, capname);
|
|
} else if (Strcmp(funcType, "accessor") == 0) {
|
|
/*
|
|
* Generate the proxy class properties for public member variables.
|
|
* Not for enums and constants.
|
|
*/
|
|
if (proxy_flag && wrapping_member_flag && !enum_constant_flag) {
|
|
// Capitalize the first letter in the function name
|
|
Setattr(n, "proxyfuncname", capname);
|
|
Setattr(n, "imfuncname", symname);
|
|
if (hasPrefix(capname, "Set")) {
|
|
Setattr(n, "modula3:setname", capname);
|
|
} else {
|
|
Setattr(n, "modula3:getname", capname);
|
|
}
|
|
|
|
emitCWrapper(n, capname);
|
|
emitM3RawPrototype(n, capname, capname);
|
|
emitM3Wrapper(n, capname);
|
|
//proxyClassFunctionHandler(n);
|
|
}
|
|
#ifdef DEBUG
|
|
} else {
|
|
Swig_warning(WARN_MODULA3_BAD_ENUMERATION, input_file, line_number, "Function type <%s> unknown.\n", Char(funcType));
|
|
#endif
|
|
}
|
|
} else if ((Strcmp(type, "constructor") == 0) || (Strcmp(type, "destructor") == 0)) {
|
|
emitCWrapper(n, capname);
|
|
emitM3RawPrototype(n, capname, capname);
|
|
emitM3Wrapper(n, capname);
|
|
}
|
|
// a Java relict
|
|
#if 0
|
|
if (!(proxy_flag && is_wrapping_class()) && !enum_constant_flag) {
|
|
emitM3Wrapper(n, capname);
|
|
}
|
|
#endif
|
|
|
|
Delete(capname);
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* emitCWrapper()
|
|
*
|
|
* Generate the wrapper in C which calls C++ methods.
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
virtual int emitCWrapper(Node *n, const String *wname) {
|
|
String *rawname = Getattr(n, "name");
|
|
String *c_return_type = NewString("");
|
|
String *cleanup = NewString("");
|
|
String *outarg = NewString("");
|
|
String *body = NewString("");
|
|
Hash *throws_hash = NewHash();
|
|
ParmList *l = Getattr(n, "parms");
|
|
SwigType *t = Getattr(n, "type");
|
|
String *symname = Getattr(n, "sym:name");
|
|
|
|
if (!Getattr(n, "sym:overloaded")) {
|
|
if (!addSymbol(wname, n)) {
|
|
return SWIG_ERROR;
|
|
}
|
|
}
|
|
// A new wrapper function object
|
|
Wrapper *f = NewWrapper();
|
|
|
|
/* Attach the non-standard typemaps to the parameter list. */
|
|
Swig_typemap_attach_parms("ctype", l, f);
|
|
|
|
/* Get return types */
|
|
{
|
|
String *tm = getMappedTypeNew(n, "ctype", "");
|
|
if (tm != NIL) {
|
|
Printf(c_return_type, "%s", tm);
|
|
}
|
|
}
|
|
|
|
bool is_void_return = (Cmp(c_return_type, "void") == 0);
|
|
if (!is_void_return) {
|
|
Wrapper_add_localv(f, "cresult", c_return_type, "cresult = 0", NIL);
|
|
}
|
|
|
|
Printv(f->def, " SWIGEXPORT ", c_return_type, " ", wname, "(", NIL);
|
|
|
|
// Emit all of the local variables for holding arguments.
|
|
emit_parameter_variables(l, f);
|
|
|
|
/* Attach the standard typemaps */
|
|
emit_attach_parmmaps(l, f);
|
|
Setattr(n, "wrap:parms", l);
|
|
|
|
// Generate signature and argument conversion for C wrapper
|
|
{
|
|
Parm *p;
|
|
attachParameterNames(n, "tmap:name", "c:wrapname", "m3arg%d");
|
|
bool gencomma = false;
|
|
for (p = skipIgnored(l, "in"); p; p = skipIgnored(p, "in")) {
|
|
|
|
String *arg = Getattr(p, "c:wrapname");
|
|
{
|
|
/* Get the ctype types of the parameter */
|
|
String *c_param_type = getMappedType(p, "ctype");
|
|
// Add parameter to C function
|
|
Printv(f->def, gencomma ? ", " : "", c_param_type, " ", arg, NIL);
|
|
Delete(c_param_type);
|
|
gencomma = true;
|
|
}
|
|
|
|
// Get typemap for this argument
|
|
String *tm = getMappedType(p, "in");
|
|
if (tm != NIL) {
|
|
addThrows(throws_hash, "in", p);
|
|
Replaceall(tm, "$input", arg);
|
|
Setattr(p, "emit:input", arg); /*??? */
|
|
Printf(f->code, "%s\n", tm);
|
|
p = Getattr(p, "tmap:in:next");
|
|
} else {
|
|
p = nextSibling(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Insert constraint checking code */
|
|
{
|
|
Parm *p;
|
|
for (p = l; p;) {
|
|
String *tm = Getattr(p, "tmap:check");
|
|
if (tm != NIL) {
|
|
addThrows(throws_hash, "check", p);
|
|
Replaceall(tm, "$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; 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) {
|
|
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 *name = Getattr(n, "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, Getfile(n), Getline(n),
|
|
"Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Modula 3.\n",
|
|
name, 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", name, WARN_NONE);
|
|
if (hasContent(pure_baseclass) && hasContent(baseclass)) {
|
|
Swig_warning(WARN_MODULA3_MULTIPLE_INHERITANCE, Getfile(n), Getline(n),
|
|
"Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in Modula 3.\n", name, pure_baseclass);
|
|
}
|
|
// Pure Modula 3 interfaces
|
|
const String *pure_interfaces = typemapLookup(n, derived ? "m3interfaces_derived" : "m3interfaces",
|
|
name, WARN_NONE);
|
|
|
|
// Start writing the proxy class
|
|
Printv(proxy_class_def, typemapLookup(n, "m3imports", name, WARN_NONE), // Import statements
|
|
"\n", typemapLookup(n, "m3classmodifiers", name, WARN_MODULA3_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers
|
|
" class $m3classname", // Class name and bases
|
|
(derived || *Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", baseclass, pure_baseclass, ((derived || *Char(pure_baseclass)) && *Char(pure_interfaces)) ? // Interfaces
|
|
", " : "", pure_interfaces, " {\n", " private IntPtr swigCPtr;\n", // Member variables for memory handling
|
|
derived ? "" : " protected bool swigCMemOwn;\n", "\n", " ", typemapLookup(n, "m3ptrconstructormodifiers", name, WARN_MODULA3_TYPEMAP_PTRCONSTMOD_UNDEF), // pointer constructor modifiers
|
|
" $m3classname(IntPtr cPtr, bool cMemoryOwn) ", // Constructor used for wrapping pointers
|
|
derived ?
|
|
": base($imclassname.$m3classnameTo$baseclass(cPtr), cMemoryOwn) {\n"
|
|
: "{\n swigCMemOwn = cMemoryOwn;\n", " swigCPtr = cPtr;\n", " }\n", NIL);
|
|
|
|
if (!have_default_constructor_flag) { // All proxy classes need a constructor
|
|
Printv(proxy_class_def, "\n", " protected $m3classname() : this(IntPtr.Zero, false) {\n", " }\n", NIL);
|
|
}
|
|
// C++ destructor is wrapped by the Dispose method
|
|
// Note that the method name is specified in a typemap attribute called methodname
|
|
String *destruct = NewString("");
|
|
const String *tm = NULL;
|
|
Node *attributes = NewHash();
|
|
String *destruct_methodname = NULL;
|
|
if (derived) {
|
|
tm = typemapLookup(n, "m3destruct_derived", name, WARN_NONE, attributes);
|
|
destruct_methodname = Getattr(attributes, "tmap:m3destruct_derived:methodname");
|
|
} else {
|
|
tm = typemapLookup(n, "m3destruct", name, WARN_NONE, attributes);
|
|
destruct_methodname = Getattr(attributes, "tmap:m3destruct:methodname");
|
|
}
|
|
if (!destruct_methodname) {
|
|
Swig_error(Getfile(n), Getline(n), "No methodname attribute defined in m3destruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name);
|
|
}
|
|
// Emit the Finalize and Dispose methods
|
|
if (tm) {
|
|
// Finalize method
|
|
if (*Char(destructor_call)) {
|
|
Printv(proxy_class_def, typemapLookup(n, "m3finalize", name, WARN_NONE), NIL);
|
|
}
|
|
// Dispose method
|
|
Printv(destruct, tm, NIL);
|
|
if (*Char(destructor_call))
|
|
Replaceall(destruct, "$imcall", destructor_call);
|
|
else
|
|
Replaceall(destruct, "$imcall", "throw new MethodAccessException(\"C++ destructor does not have public access\")");
|
|
if (*Char(destruct))
|
|
Printv(proxy_class_def, "\n public ", derived ? "override" : "virtual", " void ", destruct_methodname, "() ", destruct, "\n", NIL);
|
|
}
|
|
Delete(attributes);
|
|
Delete(destruct);
|
|
|
|
// Emit various other methods
|
|
Printv(proxy_class_def, typemapLookup(n, "m3getcptr", name, WARN_MODULA3_TYPEMAP_GETCPTR_UNDEF), // getCPtr method
|
|
typemapLookup(n, "m3code", name, WARN_NONE), // extra Modula 3 code
|
|
"\n", NIL);
|
|
|
|
// Substitute various strings into the above template
|
|
Replaceall(proxy_class_def, "$m3classname", proxy_class_name);
|
|
Replaceall(proxy_class_code, "$m3classname", proxy_class_name);
|
|
|
|
Replaceall(proxy_class_def, "$baseclass", baseclass);
|
|
Replaceall(proxy_class_code, "$baseclass", baseclass);
|
|
|
|
Replaceall(proxy_class_def, "$imclassname", m3raw_name);
|
|
Replaceall(proxy_class_code, "$imclassname", m3raw_name);
|
|
|
|
// Add code to do C++ casting to base class (only for classes in an inheritance hierarchy)
|
|
if (derived) {
|
|
Printv(m3raw_cppcasts_code, "\n [DllImport(\"", m3wrap_name, "\", EntryPoint=\"Modula3_", proxy_class_name, "To", baseclass, "\")]\n", NIL);
|
|
Printv(m3raw_cppcasts_code, " public static extern IntPtr ", "$m3classnameTo$baseclass(IntPtr objectRef);\n", NIL);
|
|
|
|
Replaceall(m3raw_cppcasts_code, "$m3classname", proxy_class_name);
|
|
Replaceall(m3raw_cppcasts_code, "$baseclass", baseclass);
|
|
|
|
Printv(upcasts_code,
|
|
"SWIGEXPORT long Modula3_$imclazznameTo$imbaseclass",
|
|
"(long objectRef) {\n",
|
|
" long baseptr = 0;\n" " *($cbaseclass **)&baseptr = *($cclass **)&objectRef;\n" " return baseptr;\n" "}\n", "\n", NIL);
|
|
|
|
Replaceall(upcasts_code, "$imbaseclass", baseclass);
|
|
Replaceall(upcasts_code, "$cbaseclass", c_baseclass);
|
|
Replaceall(upcasts_code, "$imclazzname", proxy_class_name);
|
|
Replaceall(upcasts_code, "$cclass", c_classname);
|
|
}
|
|
Delete(baseclass);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* getAttrString()
|
|
*
|
|
* If necessary create and return the string
|
|
* associated with a certain attribute of 'n'.
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
String *getAttrString(Node *n, const char *attr) {
|
|
String *str = Getattr(n, attr);
|
|
if (str == NIL) {
|
|
str = NewString("");
|
|
Setattr(n, attr, str);
|
|
}
|
|
return str;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* getMethodDeclarations()
|
|
*
|
|
* If necessary create and return the handle
|
|
* where the methods of the current access can be written to.
|
|
* 'n' must be a member of a struct or a class.
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
String *getMethodDeclarations(Node *n) {
|
|
String *acc_str = Getattr(n, "access");
|
|
String *methodattr;
|
|
if (acc_str == NIL) {
|
|
methodattr = NewString("modula3:method:public");
|
|
} else {
|
|
methodattr = NewStringf("modula3:method:%s", acc_str);
|
|
}
|
|
String *methods = getAttrString(parentNode(n), Char(methodattr));
|
|
Delete(methodattr);
|
|
return methods;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* classHandler()
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
virtual int classHandler(Node *n) {
|
|
|
|
File *f_proxy = NULL;
|
|
proxy_class_name = Copy(Getattr(n, "sym:name"));
|
|
//String *rawname = Getattr(n,"name");
|
|
|
|
if (proxy_flag) {
|
|
if (!addSymbol(proxy_class_name, n))
|
|
return SWIG_ERROR;
|
|
|
|
if (Cmp(proxy_class_name, m3raw_name) == 0) {
|
|
Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name);
|
|
SWIG_exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (Cmp(proxy_class_name, m3wrap_name) == 0) {
|
|
Printf(stderr, "Class name cannot be equal to module class name: %s\n", proxy_class_name);
|
|
SWIG_exit(EXIT_FAILURE);
|
|
}
|
|
|
|
String *filen = NewStringf("%s%s.m3", Swig_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, Getfile(n), Getline(n),
|
|
"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(NSPACE_TODO, 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(NSPACE_TODO, 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(NSPACE_TODO, Swig_name_member(NSPACE_TODO, 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(NSPACE_TODO, 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(NSPACE_TODO, 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\
|
|
*/
|