From aabec2c542019a9fe03d83a9be88b4a704eecd92 Mon Sep 17 00:00:00 2001
From: Mark Gossage
Date: Mon, 13 Feb 2006 02:36:05 +0000
Subject: [PATCH] update to extending document
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@8809 626c5289-ae23-0410-ae9c-e8d60b6d4f22
---
CHANGES.current | 3 +
Doc/Manual/Extending.html | 442 +++++++++++++++++++++++++++++++-------
2 files changed, 368 insertions(+), 77 deletions(-)
diff --git a/CHANGES.current b/CHANGES.current
index 96763fb7f..f5cec8aee 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -1,4 +1,7 @@
Version 1.3.29 (In progress)
============================
+02/13/2006: mgossage
+ [Documents] updated the extending documents to give a skeleton swigging code
+ with a few typemaps.
diff --git a/Doc/Manual/Extending.html b/Doc/Manual/Extending.html
index da1657787..15c9646ce 100644
--- a/Doc/Manual/Extending.html
+++ b/Doc/Manual/Extending.html
@@ -147,7 +147,7 @@ Code generation modules can look for these attributes to guide the wrapping proc
SWIG does not operate in this manner--any legal identifier can be used as a type name. The reason for this is primarily motivated by the use -of SWIG with partially defined data. Specifically, +of SWIG with partially defined data. Specifically, SWIG is supposed to be easy to use on interfaces with missing type information.
@@ -462,10 +462,10 @@ $ swig -c++ -python -dump_tree example.i +++ module ---------------------------------------- | name - "example" - | + | +++ insert ---------------------------------------- | code - "\n#include \"example.h\"\n" - | + | +++ include ---------------------------------------- | name - "example.h" @@ -479,63 +479,63 @@ $ swig -c++ -python -dump_tree example.i +++ access ---------------------------------------- | kind - "public" - | + | +++ constructor ---------------------------------------- | sym:name - "Shape" | name - "Shape" | decl - "f()." | code - "{\n nshapes++;\n }" | sym:symtab - 0x40194140 - | + | +++ destructor ---------------------------------------- | sym:name - "~Shape" | name - "~Shape" | storage - "virtual" | code - "{\n nshapes--;\n }" | sym:symtab - 0x40194140 - | + | +++ cdecl ---------------------------------------- | sym:name - "x" | name - "x" | decl - "" | type - "double" | sym:symtab - 0x40194140 - | + | +++ cdecl ---------------------------------------- | sym:name - "y" | name - "y" | decl - "" | type - "double" | sym:symtab - 0x40194140 - | + | +++ cdecl ---------------------------------------- | sym:name - "move" | name - "move" | decl - "f(double,double)." - | parms - double ,double + | parms - double ,double | type - "void" | sym:symtab - 0x40194140 - | + | +++ cdecl ---------------------------------------- | sym:name - "area" | name - "area" | decl - "f(void)." - | parms - void + | parms - void | storage - "virtual" | value - "0" | type - "double" | sym:symtab - 0x40194140 - | + | +++ cdecl ---------------------------------------- | sym:name - "perimeter" | name - "perimeter" | decl - "f(void)." - | parms - void + | parms - void | storage - "virtual" | value - "0" | type - "double" | sym:symtab - 0x40194140 - | + | +++ cdecl ---------------------------------------- | sym:name - "nshapes" | name - "nshapes" @@ -543,7 +543,7 @@ $ swig -c++ -python -dump_tree example.i | storage - "static" | type - "int" | sym:symtab - 0x40194140 - | + | +++ class ---------------------------------------- | sym:name - "Circle" | name - "Circle" @@ -554,41 +554,41 @@ $ swig -c++ -python -dump_tree example.i +++ access ---------------------------------------- | kind - "private" - | + | +++ cdecl ---------------------------------------- | name - "radius" | decl - "" | type - "double" - | + | +++ access ---------------------------------------- | kind - "public" - | + | +++ constructor ---------------------------------------- | sym:name - "Circle" | name - "Circle" - | parms - double + | parms - double | decl - "f(double)." | code - "{ }" | sym:symtab - 0x40194538 - | + | +++ cdecl ---------------------------------------- | sym:name - "area" | name - "area" | decl - "f(void)." - | parms - void + | parms - void | storage - "virtual" | type - "double" | sym:symtab - 0x40194538 - | + | +++ cdecl ---------------------------------------- | sym:name - "perimeter" | name - "perimeter" | decl - "f(void)." - | parms - void + | parms - void | storage - "virtual" | type - "double" | sym:symtab - 0x40194538 - | + | +++ class ---------------------------------------- | sym:name - "Square" | name - "Square" @@ -599,37 +599,37 @@ $ swig -c++ -python -dump_tree example.i +++ access ---------------------------------------- | kind - "private" - | + | +++ cdecl ---------------------------------------- | name - "width" | decl - "" | type - "double" - | + | +++ access ---------------------------------------- | kind - "public" - | + | +++ constructor ---------------------------------------- | sym:name - "Square" | name - "Square" - | parms - double + | parms - double | decl - "f(double)." | code - "{ }" | sym:symtab - 0x40194788 - | + | +++ cdecl ---------------------------------------- | sym:name - "area" | name - "area" | decl - "f(void)." - | parms - void + | parms - void | storage - "virtual" | type - "double" | sym:symtab - 0x40194788 - | + | +++ cdecl ---------------------------------------- | sym:name - "perimeter" | name - "perimeter" | decl - "f(void)." - | parms - void + | parms - void | storage - "virtual" | type - "double" | sym:symtab - 0x40194788 @@ -691,18 +691,18 @@ $ swig -dump_tree example.i | sym:name - "foo_i" | name - "foo" | decl - "f(int)." - | parms - int + | parms - int | type - "void" | sym:symtab - 0x40165078 - | + | +++ cdecl ---------------------------------------- | sym:name - "foo_d" | name - "foo" | decl - "f(double)." - | parms - double + | parms - double | type - "void" | sym:symtab - 0x40165078 - | + | +++ cdecl ---------------------------------------- | sym:name - "foo" | name - "foo" @@ -783,18 +783,18 @@ You can see this when running with the -dump_tree option. For example | sym:name - "getitem" | name - "getitem" | decl - "f(int).p." - | parms - int + | parms - int | type - "Object" | feature:except - "{\n try {\n $action\n } catc..." | sym:symtab - 0x40168ac8 - | + |Feature names are completely arbitrary and a target language module can be -programmed to respond to any feature name that it wants to recognized. The -data stored in a feature attribute is usually just a raw unparsed string. +programmed to respond to any feature name that it wants to recognized. The +data stored in a feature attribute is usually just a raw unparsed string. For example, the exception code above is simply stored without any modifications.
@@ -805,7 +805,7 @@ stored without any modifications.Language modules work by defining handler functions that know how to respond to different types of parse-tree nodes. These handlers simply look at the -attributes of each node in order to produce low-level code. +attributes of each node in order to produce low-level code.
@@ -887,7 +887,7 @@ node is then used to generate a wrapper.
Language modules work by registering handler functions for dealing with -various types of nodes at different stages of transformation. This is done by +various types of nodes at different stages of transformation. This is done by inheriting from a special Language class and defining a collection of virtual methods. For example, the Python module defines a class as follows: @@ -899,7 +899,7 @@ class PYTHON : public Language { protected: public : virtual void main(int, char *argv[]); - virtual int top(Node *); + virtual int top(Node *); virtual int functionWrapper(Node *); virtual int constantWrapper(Node *); virtual int variableWrapper(Node *); @@ -965,7 +965,7 @@ used:
-In most cases, other typenames in the source are aliases for one of these +In most cases, other typenames in the source are aliases for one of these primitive types. Specifically:
@@ -1103,7 +1103,7 @@ Chops trailing whitespace off the end of s.-Replaces the pattern pat with rep in string s. +Replaces the pattern pat with rep in string s. flags is a combination of the following flags:
@@ -1582,7 +1582,7 @@ Returns the parent of node n. Use this to move up the pass tree.
-The following macros can be used to change all of the above attributes. +The following macros can be used to change all of the above attributes. Normally, these functions are only used by the parser. Changing them without knowing what you are doing is likely to be dangerous.
@@ -1678,7 +1678,7 @@ int functionHandler(Node *n) {New attributes can be freely attached to a node as needed. However, when new attributes -are attached during code generation, they should be prepended with a namespace prefix. +are attached during code generation, they should be prepended with a namespace prefix. For example:
@@ -1715,10 +1715,10 @@ the following functions are used:Reading the SWIG encoding is often easier than figuring out the C code---just read it from left to right. For a type of "p.f(int,double).int" is -a "pointer to a function(int,double) that returns int". +a "pointer to a function(int,double) that returns int".
@@ -2016,7 +2016,7 @@ opposite of SwigType_pop().
The behavior of typedef declaration is to introduce a type alias. -For instance, typedef int Integer makes the identifier +For instance, typedef int Integer makes the identifier Integer an alias for int. The treatment of typedef in SWIG is somewhat complicated due to the pattern matching rules that get applied in typemaps and the fact that SWIG prefers to generate wrapper code @@ -2174,7 +2174,7 @@ produces two trees like this:
int p.Integer
- ^ ^ ^ ^
+ ^ ^ ^ ^
/ | \ |
/ | \ |
Integer Size Number IntegerPtr
@@ -2196,7 +2196,7 @@ returns the new type. If not, returns NULL.
Typedefs are only resolved in simple typenames that appear in a type.
-For example, the type base name and in function parameters. When
+For example, the type base name and in function parameters. When
resolving types, the process starts in the leaf nodes and moves up
the tree towards the root. Here are a few examples that show how it works:
@@ -2248,7 +2248,7 @@ will consist only of primitive typenames.
When generating wrapper code, it is necessary to emit datatypes that can
be used on the left-hand side of an assignment operator (an lvalue). However,
-not all C datatypes can be used in this way---especially arrays and
+not all C datatypes can be used in this way---especially arrays and
const-qualified types. To generate a type that can be used as an lvalue,
use the following function:
@@ -2260,7 +2260,7 @@ use the following function:
Converts type ty to a type that can be used as an lvalue in
assignment. The resulting type is stripped of qualifiers and arrays are
-converted to a pointers.
+converted to a pointers.
@@ -2488,7 +2488,7 @@ public:
printf("Generating code.\n");
return SWIG_OK;
}
-
+
};
extern "C" Language *
@@ -2578,7 +2578,7 @@ messages from your new module should appear.
-When SWIG starts, the command line options are passed to your language module. This occurs
+When SWIG starts, the command line options are passed to your language module. This occurs
before any other processing occurs (preprocessing, parsing, etc.). To capture the
command line options, simply use code similar to this:
@@ -2648,11 +2648,11 @@ void main(int argc, char *argv[]) {
... command line options ...
/* Set language-specific subdirectory in SWIG library */
- SWIG_library_directory("python");
+ SWIG_library_directory("python");
/* Set language-specific preprocessing symbol */
Preprocessor_define("SWIGPYTHON 1", 0);
-
+
/* Set language-specific configuration file */
SWIG_config_file("python.swg");
@@ -2663,7 +2663,7 @@ void main(int argc, char *argv[]) {
-The above code does several things--it registers the name of the +The above code does several things--it registers the name of the language module with the core, it supplies some preprocessor macro definitions for use in input files (so that they can determine the target language), and it registers a start-up file. In this case, the file python.swg will @@ -2673,7 +2673,7 @@ be parsed before any part of the user-supplied input file.
Before proceeding any further, create a directory for your module in the SWIG library (The Lib directory). Now, create a configuration file in the -directory. For example, python.swg. +directory. For example, python.swg.
@@ -2717,7 +2717,7 @@ An outline of top() might be as follows: int Python::top(Node *n) { /* Get the module name */ - String *module = Getattr(n,"name"); + String *module = Getattr(n,"name"); /* Get the output file name */ String *outfile = Getattr(n,"outfile"); @@ -2729,7 +2729,7 @@ int Python::top(Node *n) { ... /* Emit code for children */ - Language::top(n); + Language::top(n); ... /* Cleanup files */ @@ -2742,9 +2742,297 @@ int Python::top(Node *n) {
+Within SWIG wrappers, there are four main sections. These are (in order) + +
+Different parts of the SWIG code will fill different sections, +then upon completion of the wrappering all the sections will be saved +to the wrapper file. +
++To perform this will require several additions to the code in various places, +such as: +
+ +
+class PYTHON : public Language {
+protected:
+ /* General DOH objects used for holding the strings */
+ File *f_runtime;
+ File *f_header;
+ File *f_wrappers;
+ File *f_init;
+
+public:
+ ...
+
+};
+
+int Python::top(Node *n) {
+
+ ...
+
+ /* Initialize I/O */
+ f_runtime = NewFile(outfile, "w");
+ if (!f_runtime) {
+ FileErrorDisplay(outfile);
+ SWIG_exit(EXIT_FAILURE);
+ }
+ f_init = NewString("");
+ f_header = NewString("");
+ f_wrappers = NewString("");
+
+ /* Register file targets with the SWIG file handler */
+ Swig_register_filebyname("header", f_header);
+ Swig_register_filebyname("wrapper", f_wrappers);
+ Swig_register_filebyname("runtime", f_runtime);
+ Swig_register_filebyname("init", f_init);
+
+ /* Output module initialization code */
+ ...
+
+ /* Emit code for children */
+ Language::top(n);
+
+ ...
+ /* Write all to the file */
+ Dump(f_header, f_runtime);
+ Dump(f_wrappers, f_runtime);
+ Wrapper_pretty_print(f_init, f_runtime);
+
+ /* Cleanup files */
+ Delete(f_header);
+ Delete(f_wrappers);
+ Delete(f_init);
+ Close(f_runtime);
+ Delete(f_runtime);
+
+ return SWIG_OK;
+}
+
++Using this to process a file will generate a wrapper file, however the +wrapper will only consist of the common SWIG code as well as any inline +code which was written in the .i file. It does not contain any wrappers for +any of the functions of classes. +
+ ++The code to generate the wrappers are the various member functions, which +currently have not been touched. We will look at functionWrapper() as this +is the most commonly used function. In fact many of the other wrapper routines +will call this to do their work. +
++A simple modification to write some basic details to the wrapper looks like this: +
+ +
+int Python::functionWrapper(Node *n) {
+ /* Get some useful attributes of this function */
+ String *name = Getattr(n,"sym:name");
+ SwigType *type = Getattr(n,"type");
+ ParmList *parms = Getattr(n,"parms");
+ String *parmstr= ParmList_str_defaultargs(parms); // to string
+ String *func = SwigType_str(type, NewStringf("%s(%s)", name, parmstr));
+ String *action = Getattr(n,"wrap:action");
+
+ Printf(f_wrappers,"functionWrapper : %s\n", func);
+ Printf(f_wrappers," action : %s\n", action);
+ return SWIG_OK;
+}
+
++This will now produce some useful information within your wrapper file. +
+ ++functionWrapper : void delete_Shape(Shape *self) + action : delete arg1; + +functionWrapper : void Shape_x_set(Shape *self,double x) + action : if (arg1) (arg1)->x = arg2; + +functionWrapper : double Shape_x_get(Shape *self) + action : result = (double) ((arg1)->x); + +functionWrapper : void Shape_y_set(Shape *self,double y) + action : if (arg1) (arg1)->y = arg2; +... ++
+As ingenious as SWIG is, and despite all its capabilities and the power of +its parser, the Low-level code generation takes a lot of work to write +properly. Mainly because every language insists on its own manner of +interfacing to C/C++. To write the code generators you will need a good +understanding of how to manually write an interface to your chosen +language, so make sure you have your documentation handy. +
++At this point is also probably a good idea to take a very simple file +(just one function), and try letting SWIG generate up wrappers for many +different languages. Take a look at all of the wrappers generated, and decide +which one looks closest to the language you are trying to wrapper. +This may help you to decide which code to look at. +
++In general most language wrappers look a little like this: +
+
+/* wrapper for TYPE3 some_function(TYPE1,TYPE2); */
+RETURN_TYPE _wrap_some_function(ARGS){
+ TYPE1 arg1;
+ TYPE2 arg2;
+ TYPE3 result;
+
+ if(ARG1 is not of TYPE1) goto fail;
+ arg1=(convert ARG1);
+ if(ARG2 is not of TYPE2) goto fail;
+ arg2=(convert ARG2);
+
+ result=some_function(arg1,arg2);
+
+ convert 'result' to whatever the language wants;
+
+ do any tidy up;
+
+ return ALL_OK;
+
+ fail:
+ do any tidy up;
+ return ERROR;
+}
+
++Yes, it is rather vague and not very clear. But each language works differently +so this will have to do for now. +
++To tackle this problem will be done in two stages: +
+The first step will be done in the code, the second will be done in typemaps. +
++Our first step will be to write the code for functionWrapper(). What is +shown below is _NOT_ the solution, merely a step in the right direction. +There are a lot of issues to address. +
+
+virtual int functionWrapper(Node *n) {
+ /* get useful atributes */
+ String *name = Getattr(n,"sym:name");
+ SwigType *type = Getattr(n,"type");
+ ParmList *parms = Getattr(n,"parms");
+ ...
+
+ /* create the wrapper object */
+ Wrapper *wrapper = NewWrapper();
+
+ /* create the functions wrappered name */
+ String *wname = Swig_name_wrapper(iname);
+
+ /* deal with overloading */
+ ....
+
+ /* write the wrapper function definition */
+ Printv(wrapper->def,"RETURN_TYPE ", wname, "(ARGS) {",NIL);
+
+ /* if any additional local variable needed, add them now */
+ ...
+
+ /* write the list of locals/arguments required */
+ emit_args(type, parms, wrapper);
+
+ /* check arguments */
+ ...
+
+ /* write typemaps(in) */
+ ....
+
+ /* write constriants */
+ ....
+
+ /* Emit the function call */
+ emit_action(n,wrapper);
+
+ /* return value if necessary */
+ ....
+
+ /* write typemaps(out) */
+ ....
+
+ /* add cleanup code */
+ ....
+
+ /* Close the function(ok) */
+ Printv(wrapper->code, "return ALL_OK;\n", NIL);
+
+ /* add the failure cleanup code */
+ ...
+
+ /* Close the function(error) */
+ Printv(wrapper->code, "return ERROR;\n", "}\n", NIL);
+
+ /* final substititions if applicable */
+ ...
+
+ /* Dump the function out */
+ Wrapper_print(wrapper,f_wrappers);
+
+ /* tidy up */
+ Delete(wname);
+ DelWrapper(wrapper);
+
+ return SWIG_OK;
+}
+
++Executing this code will produce wrappers which have our basic skeleton +but without the typemaps, there are still work to do. +
+Some of the variables AC_SUBSTitutued are essential to the @@ -3203,7 +3491,7 @@ A forward C++ class declaration.
-Code insertion directive. For example, %{ ... %} or +Code insertion directive. For example, %{ ... %} or %insert(section).