diff --git a/Doc/Manual/R.html b/Doc/Manual/R.html new file mode 100644 index 000000000..4d66cc67a --- /dev/null +++ b/Doc/Manual/R.html @@ -0,0 +1,91 @@ + + + +SWIG and R + + + + +

SWIG and R

+ +

+R is a GPL'ed open source statistical and plotting environment. +Information about R can be found at www.r-project.org. + +The R binding are under active development and are extremely +experimental. Not all features have been implemented and the API is +not stable. +

+ +

Bugs

+

+Currently the following features are not implemented or broken: +

+ +

Using R and SWIG

+ +

+To use R and SWIG in C mode, execute the following commands where +example_func.c is the name of the file with the functions in them +

+
+swig -r -o example,c example.i
+PKG_LIBS="example_func.c" R CMD SHLIB example.c
+
+
+ +The corresponding comments for C++ mode are +
+
+swig -c++ -r -o example.cpp example.i
+PKG_LIBS="example_func.cxx" R CMD SHLIB example.cpp
+
+
+ +Note that R is sensitive to the name of the file and to the file +extension in C and C++ mode. The name of the wrapper file must be the +name of the library. Also in C++ mode, the file extension must be cpp +rather than cxx for the R compile command to recognize it. +

+ +

+The commands produce two files. A dynamic shared object file called +example.so and an R wrapper file called example_wrap.S. To load these +files, start up R and type in the following commands +

+
+dyn.load('example.so')
+source('example_wrap.S')
+
+These two files can be loaded in any order +

+ +

General policy

+The general policy of the module is to treat the C/C++ as a basic +wrapping over the underlying functions and rely on the R type system +to provide R syntax. + +

Language conventions

+getitem and setitem use C++ conventions (i.e. zero based indices). [<- +and [ are overloaded to allow for R syntax (one based indices and +slices) + +

C++ classes

+C++ objects are implemented as external pointer objects with the class +being the mangled name of the class. The C++ classes are encapsulated +as an SEXP with an external pointer type. The class is the mangled +name of the class. The nice thing about R is that is allows you to +keep track of the pointer object which removes the necessity for a lot +of the proxy class baggage you see in other languages. + +

Enumerations

+enumerations are characters which are then converted back and forth to +ints before calling the C routines. All of the enumeration code is +done in R. + + diff --git a/Doc/Manual/chapters b/Doc/Manual/chapters index 64cb026c1..2c84281e7 100644 --- a/Doc/Manual/chapters +++ b/Doc/Manual/chapters @@ -29,4 +29,5 @@ Pike.html Python.html Ruby.html Tcl.html +R.html Extending.html diff --git a/Examples/Makefile.in b/Examples/Makefile.in index ae5985760..268fcc5d6 100644 --- a/Examples/Makefile.in +++ b/Examples/Makefile.in @@ -1017,3 +1017,26 @@ uffi_clean: rm -f core @EXTRA_CLEAN@ rm -f *.@OBJEXT@ *@SO@ +################################################################## +##### R ###### +################################################################## + +R = R +RSRCS = $(INTERFACE:.i=_wrap.c) #special code for R build system +RCXXSRCS = $(INTERFACE:.i=_wrap.cpp) #special code for R build system + +r: $(SRCS) + $(SWIG) -r $(SWIGOPT) -o $(RSRCS) $(INTERFACE) + PKG_LIBS="$(SRCS)" PKG_CPPFLAGS="$(INCLUDES)" \ + $(R) CMD SHLIB $(RSRCS) + +r_cpp: $(CXXSRCS) + $(SWIG) -c++ -r $(SWIGOPT) -o $(RCXXSRCS) $(INTERFACE) + PKG_LIBS="$(CXXSRCS)" PKG_CPPFLAGS="$(INCLUDES)" \ + $(R) CMD SHLIB $(RCXXSRCS) + +r_clean: + rm -f *_wrap* *~ .~* $(RSRCS) $(RCXXSRCS) + rm -f core @EXTRA_CLEAN@ + rm -f *.@OBJEXT@ *@SO@ + diff --git a/Examples/r/class/Makefile b/Examples/r/class/Makefile new file mode 100644 index 000000000..6bed3ce53 --- /dev/null +++ b/Examples/r/class/Makefile @@ -0,0 +1,18 @@ +TOP = ../.. +SWIG = $(TOP)/../preinst-swig +CXXSRCS = example.cxx +TARGET = example +INTERFACE = example.i +LIBS = -lm +ARGS = SRCS='$(SRCS)' SWIG='$(SWIG)' \ + TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' + +all:: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' r_cpp + +clean:: + $(MAKE) -f $(TOP)/Makefile $(ARGS) r_clean + +check: all + R CMD BATCH runme.R diff --git a/Examples/r/class/example.cxx b/Examples/r/class/example.cxx new file mode 100644 index 000000000..1e8e203dd --- /dev/null +++ b/Examples/r/class/example.cxx @@ -0,0 +1,28 @@ +/* File : example.c */ + +#include "example.h" +#define M_PI 3.14159265358979323846 + +/* Move the shape to a new location */ +void Shape::move(double dx, double dy) { + x += dx; + y += dy; +} + +int Shape::nshapes = 0; + +double Circle::area(void) { + return M_PI*radius*radius; +} + +double Circle::perimeter(void) { + return 2*M_PI*radius; +} + +double Square::area(void) { + return width*width; +} + +double Square::perimeter(void) { + return 4*width; +} diff --git a/Examples/r/class/example.h b/Examples/r/class/example.h new file mode 100644 index 000000000..46d901361 --- /dev/null +++ b/Examples/r/class/example.h @@ -0,0 +1,39 @@ +/* File : example.h */ + +class Shape { +public: + Shape() { + nshapes++; + } + virtual ~Shape() { + nshapes--; + }; + double x, y; + void move(double dx, double dy); + virtual double area(void) = 0; + virtual double perimeter(void) = 0; + static int nshapes; +}; + +class Circle : public Shape { +private: + double radius; +public: + Circle(double r) : radius(r) { }; + virtual double area(void); + virtual double perimeter(void); +}; + +class Square : public Shape { +private: + double width; +public: + Square(double w) : width(w) { }; + virtual double area(void); + virtual double perimeter(void); +}; + + + + + diff --git a/Examples/r/class/example.i b/Examples/r/class/example.i new file mode 100644 index 000000000..4654d269f --- /dev/null +++ b/Examples/r/class/example.i @@ -0,0 +1,9 @@ +/* File : example.i */ +%module example + +%inline %{ +#include "example.h" +%} +%include "example.h" + + diff --git a/Examples/r/class/runme.R b/Examples/r/class/runme.R new file mode 100644 index 000000000..1bbe4c20e --- /dev/null +++ b/Examples/r/class/runme.R @@ -0,0 +1,49 @@ +# This file illustrates the shadow-class C++ interface generated +# by SWIG. + +dyn.load('example_wrap.so') +source('example_wrap.R') +cacheMetaData(1) + +# ----- Object creation ----- + +print("Creating some objects:") +circle <- Circle(10) +print (" Created circle") +square <- Square(10) +print (" Created square") + +# ----- Access a static member ----- + +sprintf("A total of %d shapes were created", Shape_nshapes()) + +# ----- Member data access ----- + +# Set the location of the object + +circle$x <- 20 +circle$y <- 30 + +square$x <- -10 +square$y <- 5 + +print("Here is their current position:") +sprintf(" Circle = (%f, %f)", circle$x,circle$y) +sprintf(" Square = (%f, %f)", square$x,square$y) + +# ----- Call some methods ----- + +print ("Here are some properties of the shapes:") + +sapply(c(circle, square), + function(o) { +sprintf(" area = %f perimeter = %f", o$area(), o$perimeter()) +}) + +print("Guess I'll clean up now") +delete(circle) +delete(square) + +sprintf("%d shapes remain", Shape_nshapes()) +print ("Goodbye"); + diff --git a/Examples/r/simple/Makefile b/Examples/r/simple/Makefile new file mode 100644 index 000000000..e01d35925 --- /dev/null +++ b/Examples/r/simple/Makefile @@ -0,0 +1,16 @@ +TOP = ../.. +SWIG = $(TOP)/../preinst-swig +SRCS = example.c +TARGET = example +INTERFACE = example.i +ARGS = SRCS='$(SRCS)' SWIG='$(SWIG)' \ + TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' + +all:: + $(MAKE) -f $(TOP)/Makefile $(ARGS) r + +clean:: + $(MAKE) -f $(TOP)/Makefile $(ARGS) r_clean + +check: all + R CMD BATCH runme.R diff --git a/Examples/r/simple/example.c b/Examples/r/simple/example.c new file mode 100644 index 000000000..1c2af789c --- /dev/null +++ b/Examples/r/simple/example.c @@ -0,0 +1,18 @@ +/* File : example.c */ + +/* A global variable */ +double Foo = 3.0; + +/* Compute the greatest common divisor of positive integers */ +int gcd(int x, int y) { + int g; + g = y; + while (x > 0) { + g = x; + x = y % x; + y = g; + } + return g; +} + + diff --git a/Examples/r/simple/example.i b/Examples/r/simple/example.i new file mode 100644 index 000000000..24093b9bf --- /dev/null +++ b/Examples/r/simple/example.i @@ -0,0 +1,7 @@ +/* File : example.i */ +%module example + +%inline %{ +extern int gcd(int x, int y); +extern double Foo; +%} diff --git a/Examples/r/simple/runme.R b/Examples/r/simple/runme.R new file mode 100644 index 000000000..775b520b3 --- /dev/null +++ b/Examples/r/simple/runme.R @@ -0,0 +1,24 @@ +# file: runme.R + +dyn.load('example_wrap.so') +source('example_wrap.R') +cacheMetaData(1) + +# Call our gcd() function + +x <- 42 +y <- 105 +g <- gcd(x,y) +sprintf("The gcd of %d and %d is %d", x, y, g) + +# Manipulate the Foo global variable + +# Output its current value +Foo() + +# Change its value +Foo(3.1415926) + +# See if the change took effect +Foo() + diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index 26035fbfd..044c20bb2 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -35,7 +35,7 @@ CXXSRCS = CSRCS = TARGETPREFIX = TARGETSUFFIX = -SWIGOPT = -I$(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE)/$(LANGUAGE) -I$(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE) +SWIGOPT = -I$(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE)/$(LANGUAGE) -I$(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE) -DSWIG_NOEXTRA_QUALIFICATION INCLUDES = -I$(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE)/$(LANGUAGE) -I$(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE) LIBS = -L. LIBPREFIX = lib diff --git a/Examples/test-suite/constructor_copy.i b/Examples/test-suite/constructor_copy.i index 929a49cb6..f2b44dbd0 100644 --- a/Examples/test-suite/constructor_copy.i +++ b/Examples/test-suite/constructor_copy.i @@ -77,7 +77,7 @@ public: SWIG_STD_VECTOR_SPECIALIZE_MINIMUM(Flow, Space::Flow) #endif -#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGPYTHON) +#if defined(SWIGJAVA) || defined(SWIGCSHARP) || defined(SWIGPYTHON)||defined(SWIGR) #define SWIG_GOOD_VECTOR %ignore std::vector::vector(size_type); %ignore std::vector::resize(size_type); diff --git a/Examples/test-suite/global_vars.i b/Examples/test-suite/global_vars.i index ca387a4b5..01968c744 100644 --- a/Examples/test-suite/global_vars.i +++ b/Examples/test-suite/global_vars.i @@ -19,7 +19,11 @@ int x; int *xp; +#ifdef SWIGR + int& c_member = x; +#else int& c = x; +#endif void *vp; diff --git a/Examples/test-suite/name_warnings.i b/Examples/test-suite/name_warnings.i index f691ba628..a9cb35686 100644 --- a/Examples/test-suite/name_warnings.i +++ b/Examples/test-suite/name_warnings.i @@ -61,7 +61,10 @@ namespace std %inline { /* silently rename the parameter names in csharp/java */ - +#ifdef SWIGR + double foo(double inparam, double out) { return 1.0; } +#else double foo(double in, double out) { return 1.0; } +#endif double bar(double native, bool boolean) { return 1.0; } } diff --git a/Examples/test-suite/r/Makefile.in b/Examples/test-suite/r/Makefile.in new file mode 100644 index 000000000..142bc25a2 --- /dev/null +++ b/Examples/test-suite/r/Makefile.in @@ -0,0 +1,54 @@ +####################################################################### +# $Header$ +# Makefile for mzscheme test-suite +####################################################################### + +LANGUAGE = r +SCRIPTSUFFIX = _runme.R +WRAPSUFFIX = _wrap.R +RUNR = R CMD BATCH --no-save --no-restore +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = @top_builddir@ + +C_TEST_CASES = copyStruct simpleArray legacy +CPP_TEST_CASES = funcptr double_delete + +include $(srcdir)/../common.mk + +# Overridden variables here + +# Rules for the different types of tests +%.cpptest: + $(setup) \ + ($(swig_and_compile_cpp); ) && \ + $(run_testcase) + +%.ctest: + $(setup) \ + ($(swig_and_compile_c); ) && \ + $(run_testcase) + +%.multicpptest: + $(setup) \ + ($(swig_and_compile_multi_cpp); ) && \ + $(run_testcase) + +# Runs the testcase. +# +# Run the runme if it exists. If not just load the R wrapper to +# check for syntactic correctness +run_testcase = \ + if [ -f $(srcdir)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ]; then ( \ + env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH \ + $(RUNR) $(srcdir)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ;) \ + else \ + ($(RUNR) $(srcdir)/$(SCRIPTPREFIX)$*$(WRAPSUFFIX);) \ + fi; + +# Clean +clean: + $(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile r_clean + +%.clean: + @rm -f $*_wrap.R $*_wrap.so $*_wrap.cpp $*_wrap.c $*_runme.Rout diff --git a/Examples/test-suite/r/copyStruct_runme.R b/Examples/test-suite/r/copyStruct_runme.R new file mode 100644 index 000000000..8c9b2c52f --- /dev/null +++ b/Examples/test-suite/r/copyStruct_runme.R @@ -0,0 +1,55 @@ +source('unittest.R') +dyn.load('copyStruct_wrap.so') +source('copyStruct_wrap.R') +cacheMetaData(1) + +a <- getA() + +r = getARef() + +unittest(A_d_get(r), 42) +unittest(r$d, 42) +unittest(r$i, 20) + +# An error in trying to access a field that doesn't exist. +try(r$foo) + +r$d <- pi +unittesttol(r$d, 3.141593, 0.0001) +r$i <- -100 + +r$ui +r$ui <- 10 + + # An error since i is unsigned and so must be positive. +try(r$ui <- -10) + + +a = A() +unittest(a$i,0) +unittest(a$d,0) +unittest(a$ui,0) +a$ui <- 100 +unittest(a$ui,100) +a$d = 1 +unittest(a$d,1) + +d <- bar() +unittest(class(d), "_p_D") +unittest(d$x, 1) +unittest(d$u, 0) + + +la <- new("A"); +la@ui <- 5 + +other = A() +foo <- copyToC(la, other) + +aa = A() +aa$i = 201 +aa$d = pi +aa$str = 'foo' +copyToR(aa) + + diff --git a/Examples/test-suite/r/double_delete.i b/Examples/test-suite/r/double_delete.i new file mode 100644 index 000000000..4f2d1e0a2 --- /dev/null +++ b/Examples/test-suite/r/double_delete.i @@ -0,0 +1,15 @@ +/* File : example.i */ +%module double_delete + +%inline %{ + +class Foo { +private: + double r; +public: + Foo(double rin) : r(rin) {}; +}; +%} + + + diff --git a/Examples/test-suite/r/double_delete_runme.R b/Examples/test-suite/r/double_delete_runme.R new file mode 100644 index 000000000..789692dfe --- /dev/null +++ b/Examples/test-suite/r/double_delete_runme.R @@ -0,0 +1,12 @@ +# This file illustrates the shadow-class C++ interface generated +# by SWIG. + +dyn.load('double_delete_wrap.so') +source('double_delete_wrap.R') +cacheMetaData(1) + +# ----- Object creation ----- + +f <- Foo(2.0) +delete(f); +delete(f); \ No newline at end of file diff --git a/Examples/test-suite/r/funcptr_runme.R b/Examples/test-suite/r/funcptr_runme.R new file mode 100644 index 000000000..4989ed669 --- /dev/null +++ b/Examples/test-suite/r/funcptr_runme.R @@ -0,0 +1,7 @@ +source('unittest.R') +dyn.load('funcptr_wrap.so') +source('funcptr_wrap.R') +cacheMetaData(1) +unittest(do_op(1, 3, add), 4) +unittest(do_op(2, 3, mul), 6) +unittest(do_op(2, 3, funcvar()), 5) \ No newline at end of file diff --git a/Examples/test-suite/r/ignore_parameter_runme.R b/Examples/test-suite/r/ignore_parameter_runme.R new file mode 100644 index 000000000..ff406b49c --- /dev/null +++ b/Examples/test-suite/r/ignore_parameter_runme.R @@ -0,0 +1,10 @@ +source('unittest.R') +dyn.load('ignore_parameter_wrap.so') +source('ignore_parameter_wrap.R') +cacheMetaData(1) + +unittest(jaguar(1, 1.0), "hello") +q(save='no') + + + diff --git a/Examples/test-suite/r/legacy_runme.R b/Examples/test-suite/r/legacy_runme.R new file mode 100644 index 000000000..6cd88922f --- /dev/null +++ b/Examples/test-suite/r/legacy_runme.R @@ -0,0 +1,30 @@ +source('unittest.R') +dyn.load('legacy_wrap.so') +source('legacy_wrap.R') +cacheMetaData(1) + +obj <- getObject(1,3) +unittest(class(obj), "_p_Obj") +unittest(obj$i, 1) +unittesttol(obj$d, 3, 0.001) +unittest(obj$str, "a test string") +obj$i <- 2 +unittest(obj$i, 2) +obj$d <- 4 +unittesttol(obj$d, 4, 0.001) +obj$str <- "a new string" +unittest(obj$str, "a new string") + +unittest(getInt(), 42) +unittesttol(getDouble(),3.14159, 0.001) +unittesttol(getFloat(),3.14159/2.0, 0.001) +unittest(getLong(), -321313) +unittest(getUnsignedLong(), 23123) +unittest(getChar(), "A") + +q(save='no') + + + + + diff --git a/Examples/test-suite/r/simpleArray_runme.R b/Examples/test-suite/r/simpleArray_runme.R new file mode 100644 index 000000000..025f8f04d --- /dev/null +++ b/Examples/test-suite/r/simpleArray_runme.R @@ -0,0 +1,9 @@ +source('unittest.R') +dyn.load('simpleArray_wrap.so') +source('simpleArray_wrap.R') +cacheMetaData(1) +initArray() + +q(save='no') + + diff --git a/Examples/test-suite/r/unions_runme.R b/Examples/test-suite/r/unions_runme.R new file mode 100644 index 000000000..c4238cdd6 --- /dev/null +++ b/Examples/test-suite/r/unions_runme.R @@ -0,0 +1,12 @@ +source('unittest.R') +dyn.load('unions_wrap.so') +source('unions_wrap.R') +cacheMetaData(1) + +ss <- SmallStruct() + +bstruct <- BigStruct() + +q(save='no') + + diff --git a/Examples/test-suite/r/unittest.R b/Examples/test-suite/r/unittest.R new file mode 100644 index 000000000..81c590a3f --- /dev/null +++ b/Examples/test-suite/r/unittest.R @@ -0,0 +1,9 @@ +unittest <- function (x,y) { +if (x==y) print("PASS") +else print("FAIL") +} + +unittesttol <- function(x,y,z) { +if (abs(x-y) < z) print("PASS") +else print("FAIL") +} \ No newline at end of file diff --git a/Lib/r/cdata.i b/Lib/r/cdata.i new file mode 100644 index 000000000..367965990 --- /dev/null +++ b/Lib/r/cdata.i @@ -0,0 +1 @@ +%include diff --git a/Lib/r/exception.i b/Lib/r/exception.i new file mode 100644 index 000000000..39cb09594 --- /dev/null +++ b/Lib/r/exception.i @@ -0,0 +1,8 @@ +%include + + +%insert("runtime") { + %define_as(SWIG_exception(code, msg), +%block(switch (code) {case SWIG_IndexError: return Rf_ScalarLogical(NA_LOGICAL); default: %error(code, msg); SWIG_fail;} )) +} + diff --git a/Lib/r/r.swg b/Lib/r/r.swg new file mode 100644 index 000000000..0c6dadd7d --- /dev/null +++ b/Lib/r/r.swg @@ -0,0 +1,189 @@ +/* */ + + +%insert("header") "swiglabels.swg" + +%insert("header") "swigerrors.swg" +%insert("init") "swiginit.swg" +%insert("runtime") "swigrun.swg" +%insert("runtime") "rrun.swg" + +%init %{ +SWIGEXPORT void SWIG_init(void) { +%} + +#define %Rruntime %insert("s") + +#define SWIG_Object SEXP +#define VOID_Object R_NilValue + +#define %append_output(obj) SET_VECTOR_ELT($result, $n, obj) + +%define %set_constant(name, obj) %begin_block + SEXP _obj = obj; + assign(name, _obj); +%end_block %enddef + +%define %raise(obj,type,desc) +return R_NilValue; +%enddef + +%insert("sinit") "srun.swg" + +%insert("sinitroutine") %{ +SWIG_init(); +SWIG_InitializeModule(0); +%} + +%include +%typemap(in) (double *x, int len) %{ + $1 = REAL(x); + $2 = Rf_length(x); +%} + +/* XXX + Need to worry about inheritance, e.g. if B extends A + and we are looking for an A[], then B elements are okay. +*/ +%typemap(scheck) SWIGTYPE[ANY] + %{ +# assert(length($input) > $1_dim0) + assert(all(sapply($input, class) == "$R_class")) + %} + +%typemap(out) void ""; + +%typemap(in) int *, int[ANY] %{ + $1 = INTEGER($input); +%} + +%typemap(in) double *, double[ANY] %{ + $1 = REAL($input); +%} + +/* Shoul dwe recycle to make the length correct. + And warn if length() > the dimension. +*/ +%typemap(scheck) SWIGTYPE [ANY] %{ +# assert(length($input) >= $1_dim0) +%} + +/* Handling vector case to avoid warnings, + although we just use the first one. */ +%typemap(scheck) unsigned int %{ + assert(length($input) == 1 && $input >= 0, "All values must be non-negative") +%} + + +%typemap(scheck) int %{ + if(length($input) > 1) { + warning("using only the first element of $input") + } +%} + + +%include +%include +%include +%include +%include +%include + +%apply int[ANY] { enum SWIGTYPE[ANY] }; + +%typemap(in,noblock=1) enum SWIGTYPE[ANY] { + $1 = %reinterpret_cast(INTEGER($input), $1_ltype); +} + +%typemap(in,noblock=1) char* { + $1 = %reinterpret_cast(CHAR(STRING_ELT($input, 0)), $1_ltype); +} + +%typemap(in,noblock=1) char *[ANY] { + $1 = %reinterpret_cast(CHAR(STRING_ELT($input, 0)), $1_ltype); +} + +%typemap(in,noblock=1) char[ANY] + "$1 = CHAR(STRING_ELT($input, 0));"; + +%typemap(in,noblock=1) char[] + "$1 = CHAR(STRING_ELT($input, 0));"; + +%typemap(memberin) char[] %{ +if ($input) strcpy($1, $input); +else +strcpy($1, ""); +%} + +%typemap(globalin) char[] %{ +if ($input) strcpy($1, $input); +else +strcpy($1, ""); +%} + +%typemap(out,noblock=1) char* + { $result = $1 ? mkString(%reinterpret_cast($1,char *)) : R_NilValue; } + +%typemap(in,noblock=1) char { +$1 = %static_cast(CHAR(STRING_ELT($input, 0))[0],$1_ltype); +} + +%typemap(out,noblock=1) char + { + char tmp[2] = "x"; + tmp[0] = $1; + $result = mkString(tmp); + } + + +%typemap(in,noblock=1) int { + $1 = %static_cast(INTEGER($input)[0], $1_ltype); +} + +%typemap(out,noblock=1) int + "$result = ScalarInteger($1);"; + + +%typemap(in,noblock=1) bool + "$1 = LOGICAL($input)[0];"; + + +%typemap(out,noblock=1) bool + "$result = ScalarLogical($1);"; + +%typemap(in,noblock=1) unsigned int, + unsigned long, + float, + double, + long +{ + $1 = %static_cast(REAL($input)[0], $1_ltype); +} + + +%typemap(out,noblock=1) unsigned int * + "$result = ScalarReal(*($1));"; + +%Rruntime %{ +setMethod('[', "ExternalReference", +function(x,i,j, ..., drop=TRUE) +if (!is.null(x$"__getitem__")) +sapply(i, function(n) x$"__getitem__"(i=as.integer(n-1)))) + +setMethod('[<-' , "ExternalReference", +function(x,i,j, ..., value) +if (!is.null(x$"__setitem__")) { +sapply(1:length(i), function(n) +x$"__setitem__"(i=as.integer(i[n]-1), x=value[n])) +x +}) + +setAs('ExternalReference', 'character', +function(from) {if (!is.null(from$"__str__")) from$"__str__"()}) + +setMethod('print', 'ExternalReference', +function(x) {print(as(x, "character"))}) +%} + + + diff --git a/Lib/r/rcontainer.swg b/Lib/r/rcontainer.swg new file mode 100644 index 000000000..d6d54d715 --- /dev/null +++ b/Lib/r/rcontainer.swg @@ -0,0 +1,198 @@ + +// +// Common fragments +// + + +/**** The python container methods ****/ + + + +%fragment("RSequence_Base","header") +{ +%#include +namespace swig { + inline size_t + check_index(ptrdiff_t i, size_t size, bool insert = false) { + if ( i < 0 ) { + if ((size_t) (-i) <= size) + return (size_t) (i + size); + } else if ( (size_t) i < size ) { + return (size_t) i; + } else if (insert && ((size_t) i == size)) { + return size; + } + + throw std::out_of_range("index out of range"); + } + + inline size_t + slice_index(ptrdiff_t i, size_t size) { + if ( i < 0 ) { + if ((size_t) (-i) <= size) { + return (size_t) (i + size); + } else { + throw std::out_of_range("index out of range"); + } + } else { + return ( (size_t) i < size ) ? ((size_t) i) : size; + } + } + + template + inline typename Sequence::iterator + getpos(Sequence* self, Difference i) { + typename Sequence::iterator pos = self->begin(); + std::advance(pos, check_index(i,self->size())); + return pos; + } + + template + inline typename Sequence::const_iterator + cgetpos(const Sequence* self, Difference i) { + typename Sequence::const_iterator pos = self->begin(); + std::advance(pos, check_index(i,self->size())); + return pos; + } + + template + inline Sequence* + getslice(const Sequence* self, Difference i, Difference j) { + typename Sequence::size_type size = self->size(); + typename Sequence::size_type ii = swig::check_index(i, size); + typename Sequence::size_type jj = swig::slice_index(j, size); + + if (jj > ii) { + typename Sequence::const_iterator vb = self->begin(); + typename Sequence::const_iterator ve = self->begin(); + std::advance(vb,ii); + std::advance(ve,jj); + return new Sequence(vb, ve); + } else { + return new Sequence(); + } + } + + template + inline void + setslice(Sequence* self, Difference i, Difference j, const InputSeq& v) { + typename Sequence::size_type size = self->size(); + typename Sequence::size_type ii = swig::check_index(i, size, true); + typename Sequence::size_type jj = swig::slice_index(j, size); + if (jj < ii) jj = ii; + size_t ssize = jj - ii; + if (ssize <= v.size()) { + typename Sequence::iterator sb = self->begin(); + typename InputSeq::const_iterator vmid = v.begin(); + std::advance(sb,ii); + std::advance(vmid, jj - ii); + self->insert(std::copy(v.begin(), vmid, sb), vmid, v.end()); + } else { + typename Sequence::iterator sb = self->begin(); + typename Sequence::iterator se = self->begin(); + std::advance(sb,ii); + std::advance(se,jj); + self->erase(sb,se); + self->insert(sb, v.begin(), v.end()); + } + } + + template + inline void + delslice(Sequence* self, Difference i, Difference j) { + typename Sequence::size_type size = self->size(); + typename Sequence::size_type ii = swig::check_index(i, size, true); + typename Sequence::size_type jj = swig::slice_index(j, size); + if (jj > ii) { + typename Sequence::iterator sb = self->begin(); + typename Sequence::iterator se = self->begin(); + std::advance(sb,ii); + std::advance(se,jj); + self->erase(sb,se); + } + } +} +} + +%define %swig_container_methods(Container...) + + %newobject __getslice__; + + %extend { + bool __nonzero__() const { + return !(self->empty()); + } + + size_type __len__() const { + return self->size(); + } + } +%enddef + +%define %swig_sequence_methods_common(Sequence...) +// %swig_sequence_iterator(%arg(Sequence)) + %swig_container_methods(%arg(Sequence)) + + %fragment("RSequence_Base"); + + %extend { + value_type pop() throw (std::out_of_range) { + if (self->size() == 0) + throw std::out_of_range("pop from empty container"); + Sequence::value_type x = self->back(); + self->pop_back(); + return x; + } + + Sequence* __getslice__(difference_type i, difference_type j) throw (std::out_of_range) { + return swig::getslice(self, i, j); + } + + void __setslice__(difference_type i, difference_type j, const Sequence& v) + throw (std::out_of_range, std::invalid_argument) { + swig::setslice(self, i, j, v); + } + + void __delslice__(difference_type i, difference_type j) throw (std::out_of_range) { + swig::delslice(self, i, j); + } + + void __delitem__(difference_type i) throw (std::out_of_range) { + self->erase(swig::getpos(self,i)); + } + } +%enddef + +%define %swig_sequence_methods(Sequence...) + %swig_sequence_methods_common(%arg(Sequence)) + %extend { + const value_type& __getitem__(difference_type i) const throw (std::out_of_range) { + return *(swig::cgetpos(self, i)); + } + + void __setitem__(difference_type i, const value_type& x) throw (std::out_of_range) { + *(swig::getpos(self,i)) = x; + } + + void append(const value_type& x) { + self->push_back(x); + } + } +%enddef + +%define %swig_sequence_methods_val(Sequence...) + %swig_sequence_methods_common(%arg(Sequence)) + %extend { + value_type __getitem__(difference_type i) throw (std::out_of_range) { + return *(swig::cgetpos(self, i)); + } + + void __setitem__(difference_type i, value_type x) throw (std::out_of_range) { + *(swig::getpos(self,i)) = x; + } + + void append(value_type x) { + self->push_back(x); + } + } +%enddef diff --git a/Lib/r/rfragments.swg b/Lib/r/rfragments.swg new file mode 100644 index 000000000..1dd31802f --- /dev/null +++ b/Lib/r/rfragments.swg @@ -0,0 +1,167 @@ +#define SWIG_Error(code, msg) warning(msg); return Rf_ScalarLogical(NA_LOGICAL) + +#define SWIG_fail return Rf_ScalarLogical(NA_LOGICAL) + +/* for raw pointers */ +#define SWIG_ConvertPtr(oc, ptr, ty, flags) SWIG_R_ConvertPtr(oc, ptr, ty, flags) +#define SWIG_ConvertFunctionPtr(oc, ptr, ty) SWIG_R_ConvertPtr(oc, ptr, ty, 0) +#define SWIG_NewPointerObj(ptr, ty, flags) SWIG_R_NewPointerObj(ptr, ty, flags) +#define SWIG_NewFunctionPtrObj(ptr, ty) SWIG_R_NewPointerObj(ptr, ty, 0) + +/* for raw packed data */ +#define SWIG_ConvertPacked(obj, ptr, sz, ty) SWIG_R_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewPackedObj(ptr, sz, ty) SWIG_R_NewPackedObj(ptr, sz, ty) + +/* for class or struct pointers */ +#define SWIG_ConvertInstance(obj, pptr, ty, flags) SWIG_ConvertPtr(obj, pptr, ty, flags) +#define SWIG_NewInstanceObj(ptr, ty, flags) SWIG_NewPointerObj(ptr, ty, flags) + +/* for C++ member pointers, ie, member methods */ +#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_R_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewMemberObj(ptr, sz, ty) SWIG_R_NewPackedObj(ptr, sz, ty) + + +/* Runtime API */ + +#define SWIG_GetModule(clientdata) SWIG_R_GetModule() +#define SWIG_SetModule(clientdata, pointer) SWIG_R_SetModule(pointer) + +%fragment(SWIG_From_frag(long),"header") { +SWIGINTERNINLINE SEXP +SWIG_From_dec(long)(long value) +{ + return Rf_ScalarInteger((int)value); +} +} + +%fragment(SWIG_AsVal_frag(long),"header") { +SWIGINTERNINLINE int +SWIG_AsVal_dec(long)(SEXP obj, long *val) +{ + if (val) *val = Rf_asInteger(obj); + return SWIG_OK; +} +} + + +%fragment(SWIG_From_frag(long long),"header") { +SWIGINTERNINLINE SEXP +SWIG_From_dec(long long)(long long value) +{ + return Rf_ScalarInteger((int)value); +} +} + +%fragment(SWIG_AsVal_frag(long long),"header") { +SWIGINTERNINLINE int +SWIG_AsVal_dec(long long)(SEXP obj, long long *val) +{ + if (val) *val = Rf_asInteger(obj); + return SWIG_OK; +} +} + +%fragment(SWIG_From_frag(unsigned long),"header") { +SWIGINTERNINLINE SEXP +SWIG_From_dec(unsigned long)(unsigned long value) +{ + return Rf_ScalarInteger((int)value); +} +} + + +%fragment(SWIG_AsVal_frag(unsigned long),"header") { +SWIGINTERNINLINE int +SWIG_AsVal_dec(unsigned long)(SEXP obj, unsigned long *val) +{ + if (val) *val = Rf_asInteger(obj); + return SWIG_OK; +} +} + + +%fragment(SWIG_From_frag(unsigned long long),"header") { +SWIGINTERNINLINE SEXP +SWIG_From_dec(unsigned long long)(unsigned long long value) +{ + return Rf_ScalarInteger((int)value); +} +} + + +%fragment(SWIG_AsVal_frag(unsigned long long),"header") { +SWIGINTERNINLINE int +SWIG_AsVal_dec(unsigned long long)(SEXP obj, unsigned long long *val) +{ + if (val) *val = Rf_asInteger(obj); + return SWIG_OK; +} +} + +%fragment(SWIG_From_frag(double),"header") { +SWIGINTERNINLINE SEXP +SWIG_From_dec(double)(double value) +{ + return Rf_ScalarReal(value); +} +} + + +%fragment(SWIG_AsVal_frag(double),"header") { +SWIGINTERNINLINE int +SWIG_AsVal_dec(double)(SEXP obj, double *val) +{ + if (val) *val = Rf_asReal(obj); + return SWIG_OK; +} +} + +%fragment("SWIG_AsCharPtrAndSize", "header") +{ +SWIGINTERN int +SWIG_AsCharPtrAndSize(SEXP obj, char** cptr, size_t* psize, int *alloc) +{ + if (!cptr) return SWIG_TypeError; + if (!Rf_isString(obj)) return SWIG_TypeError; + char *cstr; int len; + cstr = CHAR(STRING_ELT(obj, 0)); + len = strlen(cstr); + + if (cptr) { + if (alloc) { + if (*alloc == SWIG_NEWOBJ) + { + *cptr = %new_copy_array(cstr, len + 1, char); + *alloc = SWIG_NEWOBJ; + } + else { + *cptr = cstr; + *alloc = SWIG_OLDOBJ; + } + } else { + *cptr = strdup(cstr); + } + } + if (psize) *psize = len + 1; + return SWIG_OK; +} +} + +# This is modified from the R header files + +%fragment("SWIG_FromCharPtrAndSize","header") +{ +SWIGINTERN SEXP +SWIG_FromCharPtrAndSize(const char* carray, size_t size) +{ + SEXP t, c; + if (!carray) return R_NilValue; + PROTECT(t = allocVector(STRSXP, 1)); + c = allocString(size); + strncpy(CHAR(c), carray, size); + SET_STRING_ELT(t, 0, c); + UNPROTECT(1); + return t; +} +} + diff --git a/Lib/r/ropers.swg b/Lib/r/ropers.swg new file mode 100644 index 000000000..a71f5ba72 --- /dev/null +++ b/Lib/r/ropers.swg @@ -0,0 +1,44 @@ +#ifdef __cplusplus + +// These are auto-supported by the Perl-module +%rename(__plusplus__) *::operator++; +%rename(__minmin__) *::operator--; +%rename(__add__) *::operator+; +%rename(__sub__) *::operator-; +%rename(__neg__) *::operator-(); +%rename(__neg__) *::operator-() const; +%rename(__mul__) *::operator*; +%rename(__div__) *::operator/; +%rename(__eq__) *::operator==; +%rename(__ne__) *::operator!=; +%rename(__mod__) *::operator%; +%rename(__gt__) *::operator>; +%rename(__lt__) *::operator<; +%rename(__not__) *::operator!; + +// These are renamed, but no 'use overload...' is added +%rename(__lshift__) *::operator<<; +%rename(__rshift__) *::operator>>; +%rename(__and__) *::operator&; +%rename(__or__) *::operator|; +%rename(__xor__) *::operator^; +%rename(__invert__) *::operator~; +%rename(__le__) *::operator<=; +%rename(__ge__) *::operator>=; +%rename(__call__) *::operator(); +%rename(__getitem__) *::operator[]; + +%rename(__seteq__) *::operator=; + + +/* Ignored operators */ +%ignoreoperator(LNOT) operator!; +%ignoreoperator(LAND) operator&&; +%ignoreoperator(LOR) operator||; +%ignoreoperator(EQ) *::operator=; +%ignoreoperator(PLUSPLUS) *::operator++; +%ignoreoperator(MINUSMINUS) *::operator--; +%ignoreoperator(ARROWSTAR) *::operator->*; +%ignoreoperator(INDEX) *::operator[]; + +#endif diff --git a/Lib/r/rrun.swg b/Lib/r/rrun.swg new file mode 100644 index 000000000..cf81c82ad --- /dev/null +++ b/Lib/r/rrun.swg @@ -0,0 +1,355 @@ + +/* Not really used yet. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#undef length +#define SWIGR 1 + +/* + This is mainly a way to avoid having lots of local variables that may + conflict with those in the routine. + + Change name to R_SWIG_Callb.... +*/ +typedef struct RCallbackFunctionData { + + SEXP fun; + SEXP userData; + + + SEXP expr; + SEXP retValue; + int errorOccurred; + + SEXP el; /* Temporary pointer used in the construction of the expression to call the R function. */ + + struct RCallbackFunctionData *previous; /* Stack */ + +} RCallbackFunctionData; + +static RCallbackFunctionData *callbackFunctionDataStack; + + +SWIGRUNTIME SEXP +R_SWIG_debug_getCallbackFunctionData() +{ + int n, i; + SEXP ans; + RCallbackFunctionData *p = callbackFunctionDataStack; + + n = 0; + while(p) { + n++; + p = p->previous; + } + + PROTECT(ans = Rf_allocVector(VECSXP, n)); + for(p = callbackFunctionDataStack, i = 0; i < n; p = p->previous, i++) + SET_VECTOR_ELT(ans, i, p->fun); + + UNPROTECT(1); + + return(ans); +} + + + +SWIGRUNTIME RCallbackFunctionData * +R_SWIG_pushCallbackFunctionData(SEXP fun, SEXP userData) +{ + RCallbackFunctionData *el; + el = (RCallbackFunctionData *) calloc(1, sizeof(RCallbackFunctionData)); + el->fun = fun; + el->userData = userData; + el->previous = callbackFunctionDataStack; + + callbackFunctionDataStack = el; + + return(el); +} + + +SWIGRUNTIME SEXP +R_SWIG_R_pushCallbackFunctionData(SEXP fun, SEXP userData) +{ + R_SWIG_pushCallbackFunctionData(fun, userData); + return R_NilValue; +} + +SWIGRUNTIME RCallbackFunctionData * +R_SWIG_getCallbackFunctionData() +{ + if(!callbackFunctionDataStack) { + PROBLEM "Supposedly impossible error occurred in the SWIG callback mechanism." + " No callback function data set." /* split across two strings to make more readable. */ + ERROR; + } + + return callbackFunctionDataStack; +} + +SWIGRUNTIME void +R_SWIG_popCallbackFunctionData(int doFree) +{ + RCallbackFunctionData *el = NULL; + if(!callbackFunctionDataStack) + return ; /* Error !!! */ + + el = callbackFunctionDataStack ; + callbackFunctionDataStack = callbackFunctionDataStack->previous; + + if(doFree) + free(el); +} + + +/* + Interface to S function + is(obj, type) + which is to be used to determine if an + external pointer inherits from the right class. + + Ideally, we would like to be able to do this without an explicit call to the is() function. + When the S4 class system uses its own SEXP types, then we will hopefully be able to do this + in the C code. + + Should we make the expression static and preserve it to avoid the overhead of + allocating each time. +*/ +SWIGRUNTIME int +R_SWIG_checkInherits(SEXP obj, SEXP tag, const char *type) +{ + SEXP e, val; + int check_err = 0; + + PROTECT(e = Rf_allocVector(LANGSXP, 3)); + SETCAR(e, Rf_install("extends")); + + SETCAR(CDR(e), mkString(CHAR(PRINTNAME(tag)))); + SETCAR(CDR(CDR(e)), mkString(type)); + + val = R_tryEval(e, R_GlobalEnv, &check_err); + UNPROTECT(1); + if(check_err) + return(0); + + + return(LOGICAL(val)[0]); +} + + +SWIGRUNTIME void * +R_SWIG_resolveExternalRef(SEXP arg, const char * const type, const char * const argName, Rboolean nullOk) +{ + void *ptr; + SEXP orig = arg; + + if(TYPEOF(arg) != EXTPTRSXP) + arg = GET_SLOT(arg, mkString("ref")); + + + if(TYPEOF(arg) != EXTPTRSXP) { + PROBLEM "argument %s must be an external pointer (from an ExternalReference)", argName + ERROR; + } + + + ptr = R_ExternalPtrAddr(arg); + + if(ptr == NULL && nullOk == (Rboolean) FALSE) { + PROBLEM "the external pointer (of type %s) for argument %s has value NULL", + argName, type + ERROR; + } + + if(type[0] && R_ExternalPtrTag(arg) != Rf_install(type) && strcmp(type, "voidRef") + && !R_SWIG_checkInherits(orig, R_ExternalPtrTag(arg), type)) { + PROBLEM "the external pointer for argument %s has tag %s, not the expected value %s", + argName, CHAR(PRINTNAME(R_ExternalPtrTag(arg))), type + ERROR; + } + + + return(ptr); +} + +SWIGRUNTIME void +R_SWIG_ReferenceFinalizer(SEXP el) +{ + void *ptr = R_SWIG_resolveExternalRef(el, "", "", (Rboolean) 1); +fprintf(stderr, "In R_SWIG_ReferenceFinalizer for %p\n", ptr); +Rf_PrintValue(el); + + if(ptr) { + if(TYPEOF(el) != EXTPTRSXP) + el = GET_SLOT(el, mkString("ref")); + + if(TYPEOF(el) == EXTPTRSXP) + R_ClearExternalPtr(el); + + free(ptr); + } + + return; +} + +typedef enum {R_SWIG_EXTERNAL, R_SWIG_OWNER } R_SWIG_Owner; + +SWIGRUNTIME SEXP +SWIG_MakePtr(void *ptr, const char *typeName, R_SWIG_Owner owner) +{ + SEXP external, r_obj; + const char *p = typeName; + + if(typeName[0] == '_') + p = typeName + 1; + + PROTECT(external = R_MakeExternalPtr(ptr, Rf_install(typeName), R_NilValue)); + PROTECT(r_obj = NEW_OBJECT(MAKE_CLASS((char *) typeName))); + + if(owner) + R_RegisterCFinalizer(external, R_SWIG_ReferenceFinalizer); + + r_obj = SET_SLOT(r_obj, mkString((char *) "ref"), external); + + UNPROTECT(2); + + return(r_obj); +} + + +SWIGRUNTIME SEXP +R_SWIG_create_SWIG_R_Array(const char *typeName, SEXP ref, int len) +{ + SEXP arr; + +/*XXX remove the char * cast when we can. MAKE_CLASS should be declared appropriately. */ + PROTECT(arr = NEW_OBJECT(MAKE_CLASS((char *) typeName))); + PROTECT(arr = R_do_slot_assign(arr, mkString("ref"), ref)); + PROTECT(arr = R_do_slot_assign(arr, mkString("dims"), ScalarInteger(len))); + + UNPROTECT(3); + + return arr; +} + +#define ADD_OUTPUT_ARG(result, pos, value, name) r_ans = AddOutputArgToReturn(pos, value, name, OutputValues); + +SWIGRUNTIME SEXP +AddOutputArgToReturn(int pos, SEXP value, const char *name, SEXP output) +{ + SET_VECTOR_ELT(output, pos, value); + + return(output); +} + +/* Create a new pointer object */ +SWIGRUNTIMEINLINE SEXP +SWIG_R_NewPointerObj(void *ptr, swig_type_info *type, int flags) { + SEXP rptr = R_MakeExternalPtr(ptr, + R_MakeExternalPtr(type, R_NilValue, R_NilValue), R_NilValue); +// rptr = Rf_setAttrib(rptr, R_ClassSymbol, mkChar(SWIG_TypeName(type))); + return rptr; +} + +/* Convert a pointer value */ +SWIGRUNTIMEINLINE int +SWIG_R_ConvertPtr(SEXP obj, void **ptr, swig_type_info *ty, int flags) { + if (!obj) return SWIG_ERROR; + if (obj == R_NilValue) { + if (ptr) *ptr = NULL; + return SWIG_OK; + } + + void *vptr = R_ExternalPtrAddr(obj); + if (ty) { + swig_type_info *to = (swig_type_info*) + R_ExternalPtrAddr(R_ExternalPtrTag(obj)); + if (to == ty) { + if (ptr) *ptr = vptr; + } else { + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (ptr) *ptr = SWIG_TypeCast(tc,vptr); + } + } else { + if (ptr) *ptr = vptr; + } + return SWIG_OK; +} + +SWIGRUNTIME swig_module_info * +SWIG_GetModule(void *v) { + static void *type_pointer = (void *)0; + return (swig_module_info *) type_pointer; +} + +SWIGRUNTIME void +SWIG_SetModule(void *v, swig_module_info *swig_module) { +} + +typedef struct { + void *pack; + swig_type_info *ty; + size_t size; +} RSwigPacked; + +/* Create a new packed object */ + +SWIGRUNTIMEINLINE SEXP RSwigPacked_New(void *ptr, size_t sz, + swig_type_info *ty) { + SEXP rptr; + RSwigPacked *sobj = + (RSwigPacked*) malloc(sizeof(RSwigPacked)); + if (sobj) { + void *pack = malloc(sz); + if (pack) { + memcpy(pack, ptr, sz); + sobj->pack = pack; + sobj->ty = ty; + sobj->size = sz; + } else { + sobj = 0; + } + } + rptr = R_MakeExternalPtr(sobj, R_NilValue, R_NilValue); + return rptr; +} + +SWIGRUNTIME swig_type_info * +RSwigPacked_UnpackData(SEXP obj, void *ptr, size_t size) +{ + RSwigPacked *sobj = + (RSwigPacked *)R_ExternalPtrAddr(obj); + if (sobj->size != size) return 0; + memcpy(ptr, sobj->pack, size); + return sobj->ty; +} + +SWIGRUNTIMEINLINE SEXP +SWIG_R_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) { + return ptr ? RSwigPacked_New((void *) ptr, sz, type) : R_NilValue; +} + +/* Convert a packed value value */ + +SWIGRUNTIME int +SWIG_R_ConvertPacked(SEXP obj, void *ptr, size_t sz, swig_type_info *ty) { + swig_type_info *to = RSwigPacked_UnpackData(obj, ptr, sz); + if (!to) return SWIG_ERROR; + if (ty) { + if (to != ty) { + /* check type cast? */ + swig_cast_info *tc = SWIG_TypeCheck(to->name,ty); + if (!tc) return SWIG_ERROR; + } + } + return SWIG_OK; +} + +#ifdef __cplusplus +} +#endif diff --git a/Lib/r/rstdcommon.swg b/Lib/r/rstdcommon.swg new file mode 100644 index 000000000..223203773 --- /dev/null +++ b/Lib/r/rstdcommon.swg @@ -0,0 +1,216 @@ +%fragment("StdTraits","header",fragment="StdTraitsCommon") +{ +namespace swig { + /* + Traits that provides the from method + */ + + template struct traits_from_ptr { + static SWIG_Object from(Type *val, int owner = 0) { + return SWIG_NewPointerObj(val, type_info(), owner); + } + }; + + template struct traits_from { + static SWIG_Object from(const Type& val) { + return traits_from_ptr::from(new Type(val), 1); + } + }; + + template struct traits_from { + static SWIG_Object from(Type* val) { + return traits_from_ptr::from(val, 0); + } + }; + + template + inline SWIG_Object from(const Type& val) { + return traits_from::from(val); + } + + template + inline SWIG_Object from_ptr(Type* val, int owner) { + return traits_from_ptr::from(val, owner); + } + + /* + Traits that provides the asval/as/check method + */ + template + struct traits_asptr { + static int asptr(SWIG_Object obj, Type **val) { + Type *p; + int res = (SWIG_ConvertPtr(obj, (void**)&p, type_info(), 0) == SWIG_OK) ? SWIG_OLDOBJ : 0; + if (SWIG_IsOK(res)) { + if (val) *val = p; + } + return res; + } + }; + + template + inline int asptr(SWIG_Object obj, Type **vptr) { + return traits_asptr::asptr(obj, vptr); + } + + template + struct traits_asval { + static int asval(SWIG_Object obj, Type *val) { + if (val) { + Type *p = 0; + int res = traits_asptr::asptr(obj, &p); + if (!SWIG_IsOK(res)) return res; + if (p) { + typedef typename noconst_traits::noconst_type noconst_type; + *(const_cast(val)) = *p; + if (SWIG_IsNewObj(res)){ + %delete(p); + res = SWIG_DelNewMask(res); + } + return res; + } else { + return SWIG_ERROR; + } + } else { + return traits_asptr::asptr(obj, (Type **)(0)); + } + } + }; + + template struct traits_asval { + static int asval(SWIG_Object obj, Type **val) { + if (val) { + typedef typename noconst_traits::noconst_type noconst_type; + noconst_type *p = 0; + int res = traits_asptr::asptr(obj, &p); + if (SWIG_IsOK(res)) { + *(const_cast(val)) = p; + } + return res; + } else { + return traits_asptr::asptr(obj, (Type **)(0)); + } + } + }; + + template + inline int asval(SWIG_Object obj, Type *val) { + return traits_asval::asval(obj, val); + } + + template + struct traits_as { + static Type as(SWIG_Object obj, bool throw_error) { + Type v; + int res = asval(obj, &v); + if (!obj || !SWIG_IsOK(res)) { +// if (!PyErr_Occurred()) { +// %type_error(swig::type_name()); +// } + if (throw_error) throw std::invalid_argument("bad type"); + } + return v; + } + }; + + template + struct traits_as { + static Type as(SWIG_Object obj, bool throw_error) { + Type *v = 0; + int res = (obj ? traits_asptr::asptr(obj, &v) : SWIG_ERROR); + if (SWIG_IsOK(res) && v) { + if (SWIG_IsNewObj(res)) { + Type r(*v); + %delete(v); + return r; + } else { + return *v; + } + } else { + // Uninitialized return value, no Type() constructor required. + static Type *v_def = (Type*) malloc(sizeof(Type)); +// if (!PyErr_Occurred()) { +// %type_error(swig::type_name()); +// } + if (throw_error) throw std::invalid_argument("bad type"); + memset(v_def,0,sizeof(Type)); + return *v_def; + } + } + }; + + template + struct traits_as { + static Type* as(SWIG_Object obj, bool throw_error) { + Type *v = 0; + int res = (obj ? traits_asptr::asptr(obj, &v) : SWIG_ERROR); + if (SWIG_IsOK(res)) { + return v; + } else { +// if (!PyErr_Occurred()) { +// %type_error(swig::type_name()); +// } + if (throw_error) throw std::invalid_argument("bad type"); + return 0; + } + } + }; + + template + inline Type as(SWIG_Object obj, bool te = false) { + return traits_as::category>::as(obj, te); + } + + template + struct traits_check { + static bool check(SWIG_Object obj) { + int res = obj ? asval(obj, (Type *)(0)) : SWIG_ERROR; + return SWIG_IsOK(res) ? true : false; + } + }; + + template + struct traits_check { + static bool check(SWIG_Object obj) { + int res = obj ? asptr(obj, (Type **)(0)) : SWIG_ERROR; + return SWIG_IsOK(res) ? true : false; + } + }; + + template + inline bool check(SWIG_Object obj) { + return traits_check::category>::check(obj); + } +} +} + +%define %specialize_std_container(Type,Check,As,From) +%{ +namespace swig { + template <> struct traits_asval { + typedef Type value_type; + static int asval(SWIG_Object obj, value_type *val) { + if (Check(obj)) { + if (val) *val = As(obj); + return SWIG_OK; + } + return SWIG_ERROR; + } + }; + template <> struct traits_from { + typedef Type value_type; + static SWIG_Object from(const value_type& val) { + return From(val); + } + }; + + template <> + struct traits_check { + static int check(SWIG_Object obj) { + int res = Check(obj); + return obj && res ? res : 0; + } + }; +} +%} +%enddef diff --git a/Lib/r/rtype.swg b/Lib/r/rtype.swg new file mode 100644 index 000000000..6479a0d64 --- /dev/null +++ b/Lib/r/rtype.swg @@ -0,0 +1,200 @@ + +/* These map the primitive C types to the appropriate R type + for use in class representations. + */ + +%typemap("rtype") int, int *, int & "numeric"; +%apply int {size_t} +%apply int {std::size_t} +%apply int {ptrdiff_t} +%apply int {std::ptrdiff_t} + +%typemap("rtype") long, long * "numeric"; +%typemap("rtype") unsigned long, + unsigned long * "numeric"; +%typemap("rtype") unsigned int, + unsigned int * "numeric"; +%typemap("rtype") double, double*, double & "numeric"; +%typemap("rtype") float, float *, float & "numeric"; +%typemap("rtype") char *, char ** "character"; +%typemap("rtype") char "character"; +%typemap("rtype") string, string *, string & "character"; +%typemap("rtype") std::string, std::string *, std::string & "character"; +%typemap("rtype") bool, bool * "logical"; +%typemap("rtype") enum SWIGTYPE "character"; +%typemap("rtype") enum SWIGTYPE * "character"; +%typemap("rtype") enum SWIGTYPE & "character"; +%typemap("rtype") SWIGTYPE * "$R_class"; +%typemap("rtype") SWIGTYPE & "$R_class"; +%typemap("rtype") SWIGTYPE "$&R_class"; + + + +/* Have to be careful that as(x, "numeric") is different from as.numeric(x). + The latter makes a REALSXP, whereas the former leaves an INTSXP as an + INTSXP. +*/ + + +%typemap(scoercein) int, int *, int & + %{ $input = as($input, "integer"); %} +%typemap(scoercein) ptrdiff_t, ptrdiff_t *, ptrdiff_t & + %{ $input = as($input, "integer"); %} +%typemap(scoercein) unsigned long, unsigned long *, unsigned long & + %{ $input = as($input, "integer"); %} +%typemap(scoercein) unsigned int, unsigned int *, unsigned int & + %{ $input = as($input, "integer"); %} +%typemap(scoercein) double, double *, double & + %{ $input = as($input, "numeric"); %} +%typemap(scoercein) float, float *, float & + %{ $input = as($input, "numeric"); %} +%typemap(scoercein) char, char *, char & + %{ $input = as($input, "character"); %} +%typemap(scoercein) string, string *, string & + %{ $input = as($input, "character"); %} +%typemap(scoercein) std::string, std::string *, std::string & + %{ $input = as($input, "character"); %} +%typemap(scoercein) enum SWIGTYPE + %{ $input = enumToInteger($input, "$R_class") %} +%typemap(scoercein) enum SWIGTYPE & + %{ $input = enumToInteger($input, "$R_class") %} +%typemap(scoercein) enum SWIGTYPE * + %{ $input = enumToInteger($input, "$R_class") %} + +%typemap(scoercein) SWIGTYPE * + %{ $input = coerceIfNotSubclass($input, "$R_class") %} + +%typemap(scoercein) SWIGTYPE & + %{ $input = coerceIfNotSubclass($input, "$R_class") %} + +%typemap(scoercein) SWIGTYPE + %{ $input = coerceIfNotSubclass($input, "$&R_class") %} + + +%typemap(scoercein) SWIGTYPE[ANY] + %{ + if(is.list($input)) + assert(all(sapply($input, class) == "$R_class")) + %} + + +/* **************************************************************** */ + +%typemap(scoercein) bool, bool *, bool & + "$input = as.logical($input) "; + +%typemap(scoercein) int, + int *, + int &, + int[ANY], + size_t, + std::size_t, + size_t &, + std::size_t & + "$input = as.integer($input) "; + + +%typemap(scoercein) unsigned int, + unsigned long, + double, + float, + long, + long long, + unsigned int[], + unsigned long[], + double[], + float[], + long[], + long long[], + unsigned int[ANY], + unsigned long[ANY], + double[ANY], + float[ANY], + long[ANY], + long long[ANY], + unsigned int *, + unsigned long *, + double*, + float*, + long*, + long long * +%{ $input = as.numeric($input) %} + + +%typemap(scoercein) char *, string, std::string, +string &, std::string & +%{ $input = as($input, "character") %} + +%typemap(scoerceout) enum SWIGTYPE + %{ $result = enumFromInteger($result, "$R_class") %} + +%typemap(scoerceout) enum SWIGTYPE & + %{ $result = enumFromInteger($result, "$R_class") %} + +%typemap(scoerceout) enum SWIGTYPE * + %{ $result = enumToInteger($result, "$R_class") %} + + +%typemap(scoerceout) SWIGTYPE + %{ class($result) <- "$&R_class" %} + +%typemap(scoerceout) SWIGTYPE & + %{ class($result) <- "$R_class" %} + +%typemap(scoerceout) SWIGTYPE * + %{ class($result) <- "$R_class" %} + +/* Override the SWIGTYPE * above. */ +%typemap(scoerceout) char, + char *, + char &, + unsigned int, + unsigned int &, + unsigned long, + unsigned long &, + double, + double &, + float, + float &, + long, + long &, + long long, + long long &, + int, + int &, + bool, + bool &, + string, + std::string, + string &, + std::string &, + size_t, + std::size_t, + size_t &, + std::size_t &, + void + %{ %} + + +#if 0 + Just examining the values for a SWIGTYPE. + +%typemap(scoerceout) SWIGTYPE %{ + + name = $1_name + type = $1_type + ltype = $1_ltype + + mangle = $1_mangle + descriptor = $1_descriptor + + pointer type = $*1_type + pointer ltype = $*1_ltype + + pointer descriptor = $*1_descriptor + basetype = $*_basetype + +%} +#endif + + diff --git a/Lib/r/srun.swg b/Lib/r/srun.swg new file mode 100644 index 000000000..71a508d49 --- /dev/null +++ b/Lib/r/srun.swg @@ -0,0 +1,150 @@ +# srun.swg # +# +# This is the basic code that is needed at run time within R to +# provide and define the relevant classes. It is included +# automatically in the generated code by copying the contents of +# srun.swg into the newly created binding code. + + +# This could be provided as a separate run-time library but this +# approach allows the code to to be included directly into the +# generated bindings and so removes the need to have and install an +# additional library. We may however end up with multiple copies of +# this and some confusion at run-time as to which class to use. This +# is an issue when we use NAMESPACES as we may need to export certain +# classes. + +###################################################################### + +if(length(getClassDef("RSWIGStruct")) == 0) + setClass("RSWIGStruct", representation("VIRTUAL")) + + + +if(length(getClassDef("ExternalReference")) == 0) +# Should be virtual but this means it loses its slots currently +#representation("VIRTUAL") + setClass("ExternalReference", representation( ref = "externalptr")) + + + +if(length(getClassDef("NativeRoutinePointer")) == 0) + setClass("NativeRoutinePointer", + representation(parameterTypes = "character", + returnType = "character", + "VIRTUAL"), + contains = "ExternalReference") + +if(length(getClassDef("CRoutinePointer")) == 0) + setClass("CRoutinePointer", contains = "NativeRoutinePointer") + + +if(length(getClassDef("EnumerationValue")) == 0) + setClass("EnumerationValue", contains = "integer") + + +if(!isGeneric("copyToR")) + setGeneric("copyToR", + function(value, obj = new(gsub("Ref$", "", class(value)))) + standardGeneric("copyToR" + )) + +setGeneric("delete", function(obj) standardGeneric("delete")) + + +SWIG_createNewRef = +function(className, ..., append = TRUE) +{ + f = get(paste("new", className, sep = "_"), mode = "function") + + f(...) +} + +if(!isGeneric("copyToC")) + setGeneric("copyToC", + function(value, obj = RSWIG_createNewRef(class(value))) + standardGeneric("copyToC" + )) + + +# +defineEnumeration = +function(name, .values, where = topenv(parent.frame()), suffix = "Value") +{ + # Mirror the class definitions via the E analogous to .__C__ + defName = paste(".__E__", name, sep = "") + assign(defName, .values, envir = where) + + if(nchar(suffix)) + name = paste(name, suffix, sep = "") + + setClass(name, contains = "EnumerationValue", where = where) +} + +enumToInteger <- function(name,type) +{ + if (is.character(name)) { + ans <- as.integer(get(paste(".__E__", type, sep = ""))[name]) + if (is.na(ans)) {warning("enum not found ", name, " ", type)} + ans + } +} + +enumFromInteger = +function(i,type) +{ + itemlist <- get(paste(".__E__", type, sep="")) + names(itemlist)[match(i, itemlist)] +} + +coerceIfNotSubclass = +function(obj, type) +{ + if(!is(obj, type)) {as(obj, type)} else obj +} + + +setClass("SWIGArray", representation(dims = "integer"), contains = "ExternalReference") + +setMethod("length", "SWIGArray", function(x) x@dims[1]) + + +defineEnumeration("SCopyReferences", + .values = c( "FALSE" = 0, "TRUE" = 1, "DEEP" = 2)) + +assert = +function(condition, message = "") +{ + if(!condition) + stop(message) + + TRUE +} + + +if(FALSE) { +print.SWIGFunction = +function(x, ...) + { + } +} + + +####################################################################### + +R_SWIG_getCallbackFunctionStack = +function() +{ + # No PACKAGE argument as we don't know what the DLL is. + .Call("R_SWIG_debug_getCallbackFunctionData") +} + +R_SWIG_addCallbackFunctionStack = +function(fun, userData = NULL) +{ + # No PACKAGE argument as we don't know what the DLL is. + .Call("R_SWIG_R_pushCallbackFunctionData", fun, userData) +} + + +####################################################################### \ No newline at end of file diff --git a/Lib/r/std_alloc.i b/Lib/r/std_alloc.i new file mode 100644 index 000000000..87fa8d4a8 --- /dev/null +++ b/Lib/r/std_alloc.i @@ -0,0 +1 @@ +%include \ No newline at end of file diff --git a/Lib/r/std_common.i b/Lib/r/std_common.i new file mode 100644 index 000000000..fec0efe51 --- /dev/null +++ b/Lib/r/std_common.i @@ -0,0 +1,2 @@ +%include +%include diff --git a/Lib/r/std_container.i b/Lib/r/std_container.i new file mode 100644 index 000000000..076c1c6a4 --- /dev/null +++ b/Lib/r/std_container.i @@ -0,0 +1,2 @@ +%include +%include diff --git a/Lib/r/std_deque.i b/Lib/r/std_deque.i new file mode 100644 index 000000000..0c757ab04 --- /dev/null +++ b/Lib/r/std_deque.i @@ -0,0 +1 @@ +%include \ No newline at end of file diff --git a/Lib/r/std_except.i b/Lib/r/std_except.i new file mode 100644 index 000000000..af98428f6 --- /dev/null +++ b/Lib/r/std_except.i @@ -0,0 +1 @@ +%include diff --git a/Lib/r/std_pair.i b/Lib/r/std_pair.i new file mode 100644 index 000000000..3ac795704 --- /dev/null +++ b/Lib/r/std_pair.i @@ -0,0 +1 @@ +%include \ No newline at end of file diff --git a/Lib/r/std_string.i b/Lib/r/std_string.i new file mode 100644 index 000000000..dc1378ae6 --- /dev/null +++ b/Lib/r/std_string.i @@ -0,0 +1 @@ +%include diff --git a/Lib/r/std_vector.i b/Lib/r/std_vector.i new file mode 100644 index 000000000..03364822d --- /dev/null +++ b/Lib/r/std_vector.i @@ -0,0 +1,10 @@ +%fragment("StdVectorTraits","header") +%{ +%} + +#define %swig_vector_methods(Type...) %swig_sequence_methods(Type) +#define %swig_vector_methods_val(Type...) %swig_sequence_methods_val(Type); + + + +%include \ No newline at end of file diff --git a/Lib/r/stl.i b/Lib/r/stl.i new file mode 100644 index 000000000..9656ee6d4 --- /dev/null +++ b/Lib/r/stl.i @@ -0,0 +1,8 @@ +/* initial STL definition. extended as needed in each language */ +%include std_common.i +%include std_vector.i +%include std_string.i + + + + diff --git a/Lib/r/typemaps.i b/Lib/r/typemaps.i new file mode 100644 index 000000000..1f9b9c432 --- /dev/null +++ b/Lib/r/typemaps.i @@ -0,0 +1 @@ +%include diff --git a/Makefile.in b/Makefile.in index 27037266c..db9da7467 100644 --- a/Makefile.in +++ b/Makefile.in @@ -51,6 +51,7 @@ skip-allegrocl = test -n "@SKIP_ALLEGROCL@" skip-clisp = test -n "@SKIP_CLISP@" skip-cffi = test -n "@SKIP_CFFI@" skip-uffi = test -n "@SKIP_UFFI@" +skip-r = test -n "@SKIP_R@" # Additional dependencies for some tests skip-gcj = test -n "@SKIP_GCJ@" @@ -85,6 +86,7 @@ check-aliveness: @$(skip-csharp) || ./$(TARGET) -csharp -help @$(skip-modula3) || ./$(TARGET) -modula3 -help @$(skip-lua) || ./$(TARGET) -lua -help + @$(skip-r) || ./$(TARGET) -lua -help # Checks examples for compilation (does not run them) check-examples: \ @@ -105,7 +107,8 @@ check-examples: \ check-allegrocl-examples \ check-clisp-examples \ check-uffi-examples \ - check-cffi-examples + check-cffi-examples \ + check-r-examples check-%-examples: @passed=true; \ @@ -186,7 +189,8 @@ check-test-suite: \ check-clisp-test-suite \ check-uffi-test-suite \ check-cffi-test-suite \ - check-chicken-test-suite + check-chicken-test-suite \ + check-r-test-suite check-%-test-suite: @passed=true; \ @@ -224,7 +228,8 @@ all-test-suite: \ all-clisp-test-suite \ all-uffi-test-suite \ all-cffi-test-suite \ - all-chicken-test-suite + all-chicken-test-suite \ + all-r-test-suite all-%-test-suite: @$(MAKE) -k -s check-$*-test-suite ACTION=all @@ -249,7 +254,8 @@ broken-test-suite: \ broken-clisp-test-suite \ broken-uffi-test-suite \ broken-cffi-test-suite \ - broken-chicken-test-suite + broken-chicken-test-suite \ + broken-r-test-suite broken-%-test-suite: @$(MAKE) -k -s check-$*-test-suite ACTION=broken @@ -329,7 +335,8 @@ noskip-test-suite: \ noskip-clisp-test-suite \ noskip-uffi-test-suite \ noskip-cffi-test-suite \ - noskip-chicken-test-suite + noskip-chicken-test-suite \ + noskip-r-test-suite noskip-%-test-suite: dir="Examples/test-suite/$*"; \ @@ -375,7 +382,7 @@ install-main: @$(INSTALL_PROGRAM) $(TARGET) $(DESTDIR)$(BIN_DIR)/`echo $(TARGET_NOEXE) | sed '$(transform)'`@EXEEXT@ lib-languages = gcj typemaps tcl perl5 python guile java mzscheme ruby php4 ocaml \ - pike chicken csharp modula3 allegrocl clisp lua cffi uffi + pike chicken csharp modula3 allegrocl clisp lua cffi uffi r lib-modules = std diff --git a/Source/Makefile.am b/Source/Makefile.am index af7999e6b..efbad1ffd 100644 --- a/Source/Makefile.am +++ b/Source/Makefile.am @@ -59,6 +59,7 @@ eswig_SOURCES = CParse/cscanner.c \ Modules/php4.cxx \ Modules/pike.cxx \ Modules/python.cxx \ + Modules/r.cxx \ Modules/ruby.cxx \ Modules/s-exp.cxx \ Modules/swigmain.cxx \ diff --git a/Source/Modules/r.cxx b/Source/Modules/r.cxx new file mode 100644 index 000000000..69f76f62b --- /dev/null +++ b/Source/Modules/r.cxx @@ -0,0 +1,3035 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * r.cxx + * + * R language module for SWIG. + * ----------------------------------------------------------------------------- */ + +// Derived from an implementation of SWIG for R by Duncan Temple Lang + +#include "swigmod.h" + +#define UNUSED(a) (void)a + +static const double DEFAULT_NUMBER = .0000123456712312312323; +static const int MAX_OVERLOAD_ARGS = 5; + + +static String * getRTypeName(SwigType *t, int *outCount = NULL) { + String *b = SwigType_base(t); + List *els = SwigType_split(t); + int count = 0, i; + + if(Strncmp(b, "struct ", 7) == 0) + Replace(b, "struct ", "", DOH_REPLACE_FIRST); + + /* Printf(stderr, " %s,base = %s\n", t, b); + for(i = 0; i < Len(els); i++) + Printf(stderr, "%d) %s, ", i, Getitem(els,i)); + Printf(stderr, "\n"); */ + + for(i = 0; i < Len(els); i++) { + String *el = Getitem(els, i); + if(Strcmp(el, "p.") == 0 || Strncmp(el, "a(", 2) == 0) { + count++; + Append(b, "Ref"); + } + } + if(outCount) + *outCount = count; + + String *tmp = NewString(""); + char *retName = Char(SwigType_manglestr(t)); + Insert(tmp, 0, retName); + return tmp; + + if(count) + return(b); + + Delete(b); + return(NewString("")); +} + +#if 0 +static String * getRType(Node *n) { + SwigType *elType = Getattr(n, "type"); + SwigType *elDecl = Getattr(n, "decl"); + //XXX How can we tell if this is already done. + SwigType_push(elType, elDecl); + String *ans; + + String *rtype = Swig_typemap_lookup_new("rtype", n, "", 0); + String *i = getRTypeName(elType); + + if(Len(i) == 0) { + SwigType *td = SwigType_typedef_resolve(elType); + if(td) { + // Printf(stderr, "Resolving typedef %s -> %s\n", elType, td); + i = getRTypeName(td); + } + } + // Printf(stderr, " i = %s, rtype = %s (for %s)\n", + // i, rtype, elType); + if(rtype) { + ans = NewString(""); + Printf(ans, "%s", rtype); + Replaceall(ans, "$R_class", Char(i)); + // Printf(stderr, "Found r type in typemap for %s (for %s) => %s (%s) => %s\n", + // SwigType_str(elType, 0), Getattr(n, "name"), rtype, i, ans); + } else { + ans = i; + } + + return(ans); +} +#endif + +/********************* + Tries to get the name of the R class corresponding to the given type + e.g. struct A * is ARef, struct A** is ARefRef. + Now handles arrays, i.e. struct A[2] +****************/ + +static String *getRClassName(String *retType, int addRef = 1, int upRef=0) { + String *tmp = NewString(""); + SwigType *resolved = SwigType_typedef_resolve_all(retType); + char *retName = Char(SwigType_manglestr(resolved)); + if (upRef) { + Printf(tmp, "_p%s", retName); + } else{ + Insert(tmp, 0, retName); + } + + return tmp; +#if 1 + List *l = SwigType_split(retType); + int n = Len(l); + if(!l || n == 0) { +#ifdef R_SWIG_VERBOSE + if (debugMode) + Printf(stderr, "SwigType_split return an empty list for %s\n", + retType); +#endif + return(tmp); + } + + + String *el = Getitem(l, n-1); + char *ptr = Char(el); + if(strncmp(ptr, "struct ", 7) == 0) + ptr += 7; + + Printf(tmp, "%s", ptr); + + if(addRef) { + for(int i = 0; i < n; i++) { + if(Strcmp(Getitem(l, i), "p.") == 0 || + Strncmp(Getitem(l, i), "a(", 2) == 0) + Printf(tmp, "Ref"); + } + } + +#else + char *retName = Char(SwigType_manglestr(retType)); + if(!retName) + return(tmp); + + if(addRef) { + while(retName && strlen(retName) > 1 && strncmp(retName, "_p", 2) == 0) { + retName += 2; + Printf(tmp, "Ref"); + } + } + if(retName[0] == '_') + retName ++; + Insert(tmp, 0, retName); +#endif + + return tmp; +} + +/********************* + Tries to get the name of the R class corresponding to the given type + e.g. struct A * is ARef, struct A** is ARefRef. + Now handles arrays, i.e. struct A[2] +****************/ + +static String * getRClassNameCopyStruct(String *retType, int addRef) { + String *tmp = NewString(""); + +#if 1 + List *l = SwigType_split(retType); + int n = Len(l); + if(!l || n == 0) { +#ifdef R_SWIG_VERBOSE + Printf(stderr, "SwigType_split return an empty list for %s\n", retType); +#endif + return(tmp); + } + + + String *el = Getitem(l, n-1); + char *ptr = Char(el); + if(strncmp(ptr, "struct ", 7) == 0) + ptr += 7; + + Printf(tmp, "%s", ptr); + + if(addRef) { + for(int i = 0; i < n; i++) { + if(Strcmp(Getitem(l, i), "p.") == 0 || + Strncmp(Getitem(l, i), "a(", 2) == 0) + Printf(tmp, "Ref"); + } + } + +#else + char *retName = Char(SwigType_manglestr(retType)); + if(!retName) + return(tmp); + + if(addRef) { + while(retName && strlen(retName) > 1 && + strncmp(retName, "_p", 2) == 0) { + retName += 2; + Printf(tmp, "Ref"); + } + } + + if(retName[0] == '_') + retName ++; + Insert(tmp, 0, retName); +#endif + + return tmp; +} + + +/********************************* + Write the elements of a list to the File*, one element per line. + If quote is true, surround the element with "element". + This takes care of inserting a tab in front of each line and also + a comma after each element, except the last one. +**********************************/ + +static void writeListByLine(List *l, File *out, bool quote = 0) { + int i, n = Len(l); + for(i = 0; i < n; i++) + Printf(out, "%s%s%s%s%s\n", tab8, + quote ? "\"" :"", + Getitem(l, i), + quote ? "\"" :"", i < n-1 ? "," : ""); +} + + +static const char *usage = (char *)"\ +R Options (available with -r)\n\ + -dll - the name of the DLL (withouth the .dll or .so) included in the PACKAGE argument of the R .Call() invocations\n\ + -package - (not currently used). Typically, same as dll.\n\ + -no-init-code - turn off the generation of the R_init__wrap code. (Registration information still generated.)\n\ + -namespace - output NAMESPACE file.\n\ + -copystruct - emit R code to copy C structs (on by default)\n\ + -cppcast - Enable C++ casting operators (default) \n\ + -debug - output debug\n\ + -memoryprof - add memory profile\n\ + -gc - aggressive garbage collection\n\ +"; + + + +/************ + Display the help for this module on the screen/console. +*************/ +static void showUsage() { + fputs(usage, stdout); +} + +static bool expandTypedef(SwigType *t) { + if (SwigType_isenum(t)) return false; + String *prefix = SwigType_prefix(t); + if (Strncmp(prefix, "f", 1)) return false; + if (Strncmp(prefix, "p.f", 3)) return false; + return true; +} + + +/***** + Determine whether we should add a .copy argument to the S function + that wraps/interfaces to the routine that returns the given type. +*****/ +static int addCopyParameter(SwigType *type) { + int ok = 0; + ok = Strncmp(type, "struct ", 7) == 0 || Strncmp(type, "p.struct ", 9) == 0; + if(!ok) { + ok = Strncmp(type, "p.", 2); + } + + return(ok); +} + +static void replaceRClass(String *tm, SwigType *type) { + String *tmp = getRClassName(type); + String *tmp_base = getRClassName(type, 0); + String *tmp_ref = getRClassName(type, 1, 1); + Replaceall(tm, "$R_class", tmp); + Replaceall(tm, "$*R_class", tmp_base); + Replaceall(tm, "$&R_class", tmp_ref); + Delete(tmp); Delete(tmp_base); Delete(tmp_ref); +} + +static double getNumber(String *value, String *type) { + UNUSED(type); + + double d = DEFAULT_NUMBER; + if(Char(value)) { + // Printf(stderr, "getNumber %s %s\n", Char(value), type); + if(sscanf(Char(value), "%lf", &d) != 1) + return(DEFAULT_NUMBER); + } + return(d); +} + +class R : public Language { +public: + void registerClass(Node *n); + void main(int argc, char *argv[]); + int top(Node *n); + + void dispatchFunction(Node *n); + int functionWrapper(Node *n); + int variableWrapper(Node *n); + + int classDeclaration(Node *n); + int enumDeclaration(Node *n); + + int membervariableHandler(Node *n); + + int typedefHandler(Node *n); + + int memberfunctionHandler(Node *n) { + if (debugMode) + Printf(stderr, " %s %s\n", + Getattr(n, "name"), + Getattr(n, "type")); + member_name = Getattr(n, "name"); + processing_class_member_function = 1; + int status = Language::memberfunctionHandler(n); + processing_class_member_function = 0; + return status; + } + + + // Grab the name of the current class being processed so that we can + // deal with members of that class. + int classHandler(Node *n){ + if(!ClassMemberTable) + ClassMemberTable = NewHash(); + + class_name = Getattr(n, "name"); + int status = Language::classHandler(n); + + class_name = NULL; + return status; + }; + // Not used: + String *runtimeCode(); + +protected: + bool debugMode; + bool copyStruct; + bool memoryProfile; + bool aggressiveGc; + int addRegistrationRoutine(String *rname, int nargs); + int outputRegistrationRoutines(File *out); + + int outputCommandLineArguments(File *out); + int generateCopyRoutinesObsolete(Node *n); + int generateCopyRoutines(Node *n); + int DumpCode(Node *n, String *module); + + int OutputMemberReferenceMethod(String *className, int isSet, List *el, File *out); + int OutputArrayMethod(String *className, List *el, File *out); + int OutputClassMemberTable(Hash *tb, File *out); + int OutputClassMethodsTable(File *out); + int OutputClassAccessInfo(Hash *tb, File *out); + + int defineArrayAccessors(SwigType *type); + + void addNamespaceFunction(String *name) { + if(!namespaceFunctions) + namespaceFunctions = NewList(); + Append(namespaceFunctions, name); + } + void addNamespaceMethod(String *name) { + if(!namespaceMethods) + namespaceMethods = NewList(); + Append(namespaceMethods, name); + } + + String* processType(SwigType *t, Node *n, int *nargs = NULL); + String *createFunctionPointerHandler(SwigType *t, Node *n, int *nargs); + int addFunctionPointerProxy(String *name, Node *n, SwigType *t, String *s_paramTypes) { + /*XXX Do we need to put the t in there to get the return type later. */ + if(!functionPointerProxyTable) + functionPointerProxyTable = NewHash(); + + Setattr(functionPointerProxyTable, name, n); + + Setattr(SClassDefs, name, name); + Printv(s_classes, "setClass('", + name, + "',\n", tab8, + "prototype = list(parameterTypes = c(", s_paramTypes, "),\n", + tab8, tab8, tab8, + "returnType = '", SwigType_manglestr(t), "'),\n", tab8, + "contains = 'CRoutinePointer')\n\n##\n", NIL); + + return SWIG_OK; + }; + + + void addSMethodInfo(String *name, + String *argType, int nargs); + // Simple initialization such as constant strings that can be reused. + void init(); + + + void addAccessor(String *memberName, Wrapper *f, + String *name, int isSet = -1); + +protected: + // Strings into which we cumulate the generated code that is to be written + //vto the files. + String *sfile, + *f_init, + *s_classes, + *f_runtime, + *f_wrapper, + *s_header, + *f_wrappers, + *s_init, + *s_init_routine, + *s_namespace; + + // State variables that carry information across calls to functionWrapper() + // from member accessors and class declarations. + String *opaqueClassDeclaration; + int processing_variable; + int processing_member_access_function; + String *member_name; + String *class_name; + + + int processing_class_member_function; + List *class_member_functions, *class_member_set_functions; + + /* */ + Hash *ClassMemberTable; + Hash *ClassMethodsTable; + Hash *SClassDefs; + Hash *SMethodInfo; + + // Information about routines that are generated and to be registered with + // R for dynamic lookup. + Hash *registrationTable; + Hash *functionPointerProxyTable; + + List *namespaceFunctions; + List *namespaceMethods; + List *namespaceClasses; // Probably can do this from ClassMemberTable. + + + // Store a copy of the command line. + // Need only keep a string that has it formatted. + char **argv; + int argc; + bool inCPlusMode; + + // State variables that we remember from the command line settings + // potentially that govern the code we generate. + String *DllName; + String *Rpackage; + bool noInitializationCode; + bool outputNamespaceInfo; + + String *UnProtectWrapupCode; +}; + + +static int getFunctionPointerNumArgs(Node *n, SwigType *tt) { + (void) tt; + n = Getattr(n, "type"); + Printf(stderr, "type: %s\n", n); +#if 0 + SwigType *tmp = SwigType_typedef_resolve(tt); + + n = SwigType_typedef_resolve(tt); +#endif + + ParmList *parms(Getattr(n, "parms")); + Printf(stderr, "parms = %p\n", parms); + return ParmList_len(parms); +} + + +void +R::addSMethodInfo(String *name, String *argType, int nargs) { + (void) argType; + + if(!SMethodInfo) + SMethodInfo = NewHash(); + if (debugMode) + Printf(stderr, "[addMethodInfo] %s\n", name); + + Hash *tb = Getattr(SMethodInfo, name); + + if(!tb) { + tb = NewHash(); + Setattr(SMethodInfo, name, tb); + } + + String *str = Getattr(tb, "max"); + int max = -1; + if(str) + max = atoi(Char(str)); + if(max < nargs) { + if(str) Delete(str); + str = NewStringf("%d", max); + Setattr(tb, "max", str); + } +} + +/* + +Returns the name of the new routine. +*/ +String * R::createFunctionPointerHandler(SwigType *t, Node *n, int *numArgs) { + String *funName = SwigType_manglestr(t); + + /* See if we have already processed this one. */ + if(functionPointerProxyTable && Getattr(functionPointerProxyTable, funName)) + return funName; + + SwigType *base = SwigType_base(t); + if (debugMode) + Printf(stderr, " Defining %s\n", t); + + int isVoidType = 0; + + // ParmList *parms = Getattr(n, "parms"); + // memory leak + ParmList *parms = + SwigType_function_parms(SwigType_del_pointer(Copy(t))); + if (debugMode) { + Printf(stderr, "Type: %s\n", t); + Printf(stderr, "Return type: %s\n", SwigType_base(t)); + } + + isVoidType = Strcmp(base, "void") == 0; + if (debugMode) + Printf(stderr, "%s is void ? %s (%s)\n", funName, isVoidType ? "yes" : "no", base); + + Wrapper *f = NewWrapper(); + + + Parm *ppp = parms; + int i = 0; + while(ppp) { + String *name = Getattr(ppp, "name"); + if(Len(name) == 0) { + name = NewStringf("s_arg%d", i+1); + Setattr(ppp, "name", Copy(name)); + } + if (debugMode) { + Printf(stderr, "Parm : %s\n", name); + } + Setattr(ppp, "lname", Copy(Getattr(ppp, "name"))); + ppp = nextSibling(ppp); + i++; + } + + Swig_typemap_attach_parms("in", parms, f); + Swig_typemap_attach_parms("out", parms, f); + Swig_typemap_attach_parms("scoercein", parms, f); + Swig_typemap_attach_parms("scoerceout", parms, f); + Swig_typemap_attach_parms("scheck", parms, f); + + emit_args(base, parms, f);// should this be t or base. base puts the correct return type variable. + emit_attach_parmmaps(parms,f); + + /* Using weird name and struct to avoid potential conflicts. */ + Wrapper_add_local(f, "__r_swig_cb_data", + "RCallbackFunctionData *__r_swig_cb_data = R_SWIG_getCallbackFunctionData()"); + String *lvar = NewString("__r_swig_cb_data"); + + Wrapper_add_local(f, "__tmp", "SEXP __tmp"); // for use in converting arguments to R objects for call. + Wrapper_add_local(f, "__r_nprotect", "int __r_nprotect = 0"); // for use in converting arguments to R objects for call. + Wrapper_add_local(f, "r_vmax", "char * r_vmax= 0"); // for use in converting arguments to R objects for call. + + // Add local for error code in return value. This is not in emit_args because that assumes an out typemap + // whereas the type makes are reverse + Wrapper_add_local(f, "ecode", "int ecode = 0"); + + Printf(f->def, "%s\n%s(", SwigType_base(t), funName); + + Parm *p = parms; + int nargs = ParmList_len(parms); + if(numArgs) { + *numArgs = nargs; + if (debugMode) + Printf(stderr, "Setting number of parameters to %d\n", *numArgs); + } + String *setExprElements = NewString(""); + + String *s_paramTypes = NewString(""); + for(int i = 0; p; i++) { + SwigType *tt = Getattr(p, "type"); + SwigType *name = Getattr(p, "name"); + // String *lname = Getattr(p,"lname"); + Printf(f->def, "%s %s", SwigType_str(tt, 0), name); + String *tm = Getattr(p, "tmap:out"); + if(tm) { + Replaceall(tm, "$1", name); + Replaceall(tm, "$result", "__tmp"); + replaceRClass(tm, Getattr(p,"type")); + Replaceall(tm,"$owner", "R_SWIG_EXTERNAL"); + } + + Printf(setExprElements, "%s\n", tm); + Printf(setExprElements, "SETCAR(__r_swig_cb_data->el, %s);\n", "__tmp"); + Printf(setExprElements, "__r_swig_cb_data->el = CDR(__r_swig_cb_data->el);\n\n"); + + Printf(s_paramTypes, "'%s'", SwigType_manglestr(tt)); + + + p = nextSibling(p); + if(p) { + Printf(f->def, ", ", i, tt, name); + Printf(s_paramTypes, ", "); + } + } + + Printf(f->def, ")\n{\n"); + + Printf(f->code, "PROTECT(%s->expr = allocVector(LANGSXP, %d));\n", lvar, nargs + 1); + Printf(f->code, "__r_nprotect++;\n"); + Printf(f->code, "__r_swig_cb_data->el = __r_swig_cb_data->expr;\n\n"); + + Printf(f->code, "SETCAR(__r_swig_cb_data->el, __r_swig_cb_data->fun);\n"); + Printf(f->code, "__r_swig_cb_data->el = CDR(__r_swig_cb_data->el);\n\n"); + + Printf(f->code, "%s\n\n", setExprElements); + + Printv(f->code, "__r_swig_cb_data->retValue = R_tryEval(", + "__r_swig_cb_data->expr,", + " R_GlobalEnv,", + " &__r_swig_cb_data->errorOccurred", + ");\n", + NIL); + + Printv(f->code, "\n", + "if(__r_swig_cb_data->errorOccurred) {\n", + "R_SWIG_popCallbackFunctionData(1);\n", + "PROBLEM \"error in calling R function as a function pointer (", + funName, + "\"\n", + "ERROR;\n", + "}\n", + NIL); + + + + if(!isVoidType) { + /* Need to deal with the return type of the function pointer, not the function pointer itself. + So build a new node that has the relevant pieces. + XXX Have to be a little more clever so that we can deal with struct A * - the * is getting lost. + Is this still true? If so, will a SwigType_push() solve things? + */ + Node *bbase = NewHash(); + + Setattr(bbase, "type", base); + Setattr(bbase, "name", NewString("result")); + String *returnTM = Swig_typemap_lookup_new("in", bbase, "result", 0); + if(returnTM) { + String *tm = returnTM; + SwigType *retType = base; // Getattr(n, "type"); + + Replaceall(tm,"$input", "__r_swig_cb_data->retValue"); + Replaceall(tm,"$target", "result"); + replaceRClass(tm, retType); + Replaceall(tm,"$owner", "R_SWIG_EXTERNAL"); + Printf(f->code, "%s\n", tm); + } + Delete(bbase); + } + + Printv(f->code, "R_SWIG_popCallbackFunctionData(1);\n", NIL); + Printv(f->code, "\n", UnProtectWrapupCode, NIL); + + if(!isVoidType) + Printv(f->code, "return result;\n", NIL); + + Printv(f->code, "\n}\n", NIL); + + /* To coerce correctly in S, we really want to have an extra/intermediate + function that handles the scoerceout. + We need to check if any of the argument types have an entry in + that map. If none do, the ignore and call the function straight. + Otherwise, generate the a marshalling function. + Need to be able to find it in S. Or use an entirely generic one + that evaluates the expressions. + Handle errors in the evaluation of the function by restoring + the stack, if there is one in use for this function (i.e. no + userData). + */ + + Wrapper_print(f, f_wrapper); + + + addFunctionPointerProxy(funName, n, t, s_paramTypes); + Delete(s_paramTypes); + + return funName; +} + +void R::init() { + UnProtectWrapupCode = + NewStringf("%s", "vmaxset(r_vmax);\nif(__r_nprotect) UNPROTECT(__r_nprotect);\n\n"); + + SClassDefs = NewHash(); + + sfile = NewString(""); + f_init = NewString(""); + s_header = NewString(""); + f_runtime = NewString(""); + f_wrapper = NewString(""); + s_classes = NewString(""); + s_init = NewString(""); + s_init_routine = NewString(""); +} + + + +#if 0 +int R::cDeclaration(Node *n) { + SwigType *t = Getattr(n, "type"); + SwigType *name = Getattr(n, "name"); + if (debugMode) + Printf(stderr, "cDeclaration (%s): %s\n", name, SwigType_lstr(t, 0)); + return Language::cDeclaration(n); +} +#endif + + +/** + Method from Language that is called to start the entire + processing off, i.e. the generation of the code. + It is called after the input has been read and parsed. + Here we open the output streams and generate the code. +***/ +int R::top(Node *n) { + String *module = Getattr(n, "name"); + if(!Rpackage) + Rpackage = Copy(module); + if(!DllName) + DllName = Copy(module); + Append(DllName, "_wrap"); + + + if(outputNamespaceInfo) { + s_namespace = NewString(""); + Swig_register_filebyname("snamespace", s_namespace); + Printf(s_namespace, "useDynLib(%s)\n", DllName); + } else { + String *dev = NewString("/dev/null"); + File *devnull = NewFile(dev, "w+"); + Delete(dev); + if(!devnull) { + FileErrorDisplay(dev); + SWIG_exit(EXIT_FAILURE); + } + Swig_register_filebyname("snamespace", devnull); + } + + + /* Associate the different streams with names so that they can be used in %insert directives by the + typemap code. */ + Swig_register_filebyname("sinit", s_init); + Swig_register_filebyname("sinitroutine", s_init_routine); + + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("header", s_header); + Swig_register_filebyname("wrapper", f_wrapper); + Swig_register_filebyname("s", sfile); + + Swig_register_filebyname("sclasses", s_classes); + + + Printf(s_init, "# This is an automatically generate file by the R module for SWIG.\n\n"); + outputCommandLineArguments(s_init); + + Language::top(n); + + String *type_table = NewString(""); + SwigType_emit_type_table(f_runtime,f_wrapper); + Delete(type_table); + + if(ClassMemberTable) { + //XXX OutputClassAccessInfo(ClassMemberTable, sfile); + Delete(ClassMemberTable); + ClassMemberTable = NULL; + } + + Printf(f_init,"}\n"); + if(registrationTable) + outputRegistrationRoutines(f_init); + + + /* Now arrange to write the 2 files - .S and .c. */ + + DumpCode(n, module); + + Delete(sfile); + Delete(s_classes); + Delete(s_init); + Delete(f_wrapper); + Delete(f_init); + + Delete(s_header); + Delete(f_runtime); + + return SWIG_OK; +} + + +/***************************************************** + Write the generated code to the .S and the .c files. +****************************************************/ +int R::DumpCode(Node *n, String *module) { + String *output_filename = NewString(""); + + + /* The name of the file in which we will generate the S code. */ + Printf(output_filename, "%s%s_wrap.R", SWIG_output_directory(), module); + +#ifdef R_SWIG_VERBOSE + Printf(stderr, "Writing S code to %s\n", output_filename); +#endif + + File *scode = NewFile(output_filename, "w"); + if (!scode) { + FileErrorDisplay(output_filename); + SWIG_exit(EXIT_FAILURE); + } + Delete(output_filename); + + + Printf(scode, "%s\n\n", s_init); + Printf(scode, "%s\n\n", s_classes); + Printf(scode, "%s\n", sfile); + + Close(scode); + // Delete(scode); + String *outfile = Getattr(n,"outfile"); + File *runtime = NewFile(outfile,"w"); + if (!runtime) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + Swig_banner(runtime); + + + Printf(runtime, "/* Runtime */\n"); + Printf(runtime, "%s\n", f_runtime); + + Printf(runtime, "/* Header */\n"); + Printf(runtime, "%s\n", s_header); + + Printf(runtime, "/* Wrapper */\n"); + Printf(runtime, "%s\n", f_wrapper); + + Printf(runtime, "/* Init code */\n"); + Printf(runtime, "%s\n", f_init); + + Close(runtime); + Delete(runtime); + + if(outputNamespaceInfo) { + output_filename = NewString(""); + Printf(output_filename, "%sNAMESPACE", SWIG_output_directory()); + File *ns = NewFile(output_filename, "w"); + if (!ns) { + FileErrorDisplay(output_filename); + SWIG_exit(EXIT_FAILURE); + } + Delete(output_filename); + + Printf(ns, "%s\n", s_namespace); + + Printf(ns, "\nexport(\n"); + writeListByLine(namespaceFunctions, ns); + Printf(ns, ")\n"); + Printf(ns, "\nexportMethods(\n"); + writeListByLine(namespaceFunctions, ns, 1); + Printf(ns, ")\n"); + Close(ns); + Delete(ns); + Delete(s_namespace); + } + + return SWIG_OK; +} + + + +/* + We may need to do more.... so this is left as a + stub for the moment. +*/ +int R::OutputClassAccessInfo(Hash *tb, File *out) { + int n = OutputClassMemberTable(tb, out); + OutputClassMethodsTable(out); + return n; +} + +/************************************************************************ + Currently this just writes the information collected about the + different methods of the C++ classes that have been processed + to the console. + This will be used later to define S4 generics and methods. +**************************************************************************/ +int R::OutputClassMethodsTable(File *) { + Hash *tb = ClassMethodsTable; + + if(!tb) + return SWIG_OK; + + List *keys = Keys(tb); + String *key; + int i, n = Len(keys); + if (debugMode) { + for(i = 0; i < n ; i++ ) { + key = Getitem(keys, i); + Printf(stderr, "%d) %s\n", i, key); + List *els = Getattr(tb, key); + int nels = Len(els); + Printf(stderr, "\t"); + for(int j = 0; j < nels; j+=2) { + Printf(stderr, "%s%s", Getitem(els, j), j < nels - 1 ? ", " : ""); + Printf(stderr, "%s\n", Getitem(els, j+1)); + } + Printf(stderr, "\n"); + } + } + + return SWIG_OK; +} + + +/* + Iterate over the _set and <>_get + elements and generate the $ and $<- functions + that provide constrained access to the member + fields in these elements. + + tb - a hash table that is built up in functionWrapper + as we process each membervalueHandler. + The entries are indexed by _set and + _get. Each entry is a List *. + + out - the stram where the code is to be written. This is the S + code stream as we generate only S code here.. +*/ +int R::OutputClassMemberTable(Hash *tb, File *out) { + List *keys = Keys(tb), *el; + + String *key; + int i, n = Len(keys); + /* Loop over all the _set and _get entries in the table. */ + + if(n && outputNamespaceInfo) { + Printf(s_namespace, "exportClasses("); + } + for(i = 0; i < n; i++) { + key = Getitem(keys, i); + el = Getattr(tb, key); + + String *className = Getitem(el, 0); + char *ptr = Char(key); + ptr = &ptr[Len(key) - 3]; + int isSet = strcmp(ptr, "set") == 0; + + // OutputArrayMethod(className, el, out); + OutputMemberReferenceMethod(className, isSet, el, out); + + if(outputNamespaceInfo) + Printf(s_namespace, "\"%s\"%s", className, i < n-1 ? "," : ""); + } + if(n && outputNamespaceInfo) { + Printf(s_namespace, ")\n"); + } + + return n; +} + +/******************************************************************* + Write the methods for $ or $<- for accessing a member field in an + struct or union (or class). + className - the name of the struct or union (e.g. Bar for struct Bar) + isSet - a logical value indicating whether the method is for + modifying ($<-) or accessing ($) the member field. + el - a list of length 2 * # accessible member elements + 1. + The first element is the name of the class. + The other pairs are member name and the name of the R function to access it. + out - the stream where we write the code. +********************************************************************/ +int R::OutputMemberReferenceMethod(String *className, int isSet, + List *el, File *out) { + int numMems = Len(el), j; + int has_getitem = 0, has_setitem = 0, has_str = 0; + int varaccessor = 0; + if (numMems == 0) + return SWIG_OK; + + Wrapper *f = NewWrapper(), *attr = NewWrapper(); + + Printf(f->def, "function(x, name%s)", isSet ? ", value" : ""); + Printf(attr->def, "function(x, i, j, ...%s)", isSet ? ", value" : ""); + + Printf(f->code, "{\n"); + Printf(f->code, "%saccessorFuns = list(", tab8); + + for(j = 0; j < numMems; j+=3) { + String *item = Getitem(el, j); + if (!Strcmp(item, "__getitem__")) has_getitem = 1; + if (!Strcmp(item, "__setitem__")) has_setitem = 1; + if (!Strcmp(item, "__str__")) has_str = 1; + + String *dup = Getitem(el, j + 1); + char *ptr = Char(dup); + ptr = &ptr[Len(dup) - 3]; + + if (!strcmp(ptr, "get")) + varaccessor++; + Printf(f->code, "'%s' = %s%s", item, dup, j < numMems - 3 ? ", " : ""); + } + Printf(f->code, ")\n"); + + if (!isSet && varaccessor > 0) { + Printf(f->code, "%svaccessors = c(", tab8); + int vcount = 0; + for(j = 0; j < numMems; j+=3) { + String *item = Getitem(el, j); + String *dup = Getitem(el, j + 1); + char *ptr = Char(dup); + ptr = &ptr[Len(dup) - 3]; + + if (!strcmp(ptr, "get")) { + vcount++; + Printf(f->code, "'%s'%s", item, vcount < varaccessor ? ", " : ""); + } + } + Printf(f->code, ")\n"); + } + + + /* Printv(f->code, tab8, + "idx = pmatch(name, names(accessorFuns))\n", + tab8, + "if(is.na(idx)) {\n", + tab8, tab4, + "stop(\"No ", (isSet ? "modifiable" : "accessible"), " field named \", name, \" in ", className, + ": fields are \", paste(names(accessorFuns), sep = \", \")", + ")", "\n}\n", NIL); */ + Printv(f->code, tab8, + "idx = pmatch(name, names(accessorFuns))\n", + tab8, + "if(is.na(idx)) \n", + tab8, tab4, NIL); + Printf(f->code, "return(callNextMethod(x, name%s))\n", + isSet ? ", value" : ""); + Printv(f->code, tab8, "f = accessorFuns[[idx]]\n", NIL); + if(isSet) { + Printv(f->code, tab8, "f(x, value)\n", NIL); + Printv(f->code, tab8, "x\n", NIL); // make certain to return the S value. + } else { + Printv(f->code, tab8, "formals(f)[[1]] = x\n", NIL); + if (varaccessor) { + Printv(f->code, tab8, + "if (is.na(match(name, vaccessors))) f else f(x)\n", NIL); + } else { + Printv(f->code, tab8, "f\n", NIL); + } + } + Printf(f->code, "}\n"); + + + Printf(out, "# Start of accessor method for %s\n", className); + Printf(out, "setMethod('$%s', '_p%s', ", + isSet ? "<-" : "", + getRClassName(className)); + Wrapper_print(f, out); + Printf(out, ")\n"); + + if(isSet) { + Printf(out, "setMethod('[[<-', c('_p%s', 'character'),", + getRClassName(className)); + Insert(f->code, 2, "name = i\n"); + Printf(attr->code, "%s", f->code); + Wrapper_print(attr, out); + Printf(out, ")\n"); + } + + DelWrapper(attr); + DelWrapper(f); + + Printf(out, "# end of accessor method for %s\n", className); + + return SWIG_OK; +} + +/******************************************************************* + Write the methods for [ or [<- for accessing a member field in an + struct or union (or class). + className - the name of the struct or union (e.g. Bar for struct Bar) + el - a list of length 2 * # accessible member elements + 1. + The first element is the name of the class. + The other pairs are member name and the name of the R function to access it. + out - the stream where we write the code. +********************************************************************/ +int R::OutputArrayMethod(String *className, List *el, File *out) { + int numMems = Len(el), j; + + if(!el || numMems == 0) + return(0); + + Printf(out, "# start of array methods for %s\n", className); + for(j = 0; j < numMems; j+=3) { + String *item = Getitem(el, j); + String *dup = Getitem(el, j + 1); + if (!Strcmp(item, "__getitem__")) { + Printf(out, + "setMethod('[', '_p%s', function(x, i, j, ..., drop =TRUE) ", + getRClassName(className)); + Printf(out, " sapply(i, function (n) %s(x, as.integer(n-1))))\n\n", dup); + } + if (!Strcmp(item, "__setitem__")) { + Printf(out, "setMethod('[<-', '_p%s', function(x, i, j, ..., value)", + getRClassName(className)); + Printf(out, " sapply(1:length(i), function(n) %s(x, as.integer(i[n]-1), value[n])))\n\n", dup); + } + + } + + Printf(out, "# end of array methods for %s\n", className); + + return SWIG_OK; +} + + +/************************************************************ + Called when a enumeration is to be processed. + We want to call the R function defineEnumeration(). + tdname is the typedef of the enumeration, i.e. giving its name. +*************************************************************/ +int R::enumDeclaration(Node *n) { + String *name = Getattr(n, "name"); + String *tdname = Getattr(n, "tdname"); + + /* Using name if tdname is empty. */ + + if(Len(tdname) == 0) + tdname = name; + + + if(!tdname || Strcmp(tdname, "") == 0) { + Language::enumDeclaration(n); + return SWIG_OK; + } + + String *mangled_tdname = SwigType_manglestr(tdname); + String *scode = NewString(""); + + Printv(scode, "defineEnumeration('", mangled_tdname, "'", + ",\n", tab8, tab8, tab4, ".values = c(\n", NIL); + + Node *c; + int value = -1; // First number is zero + for (c = firstChild(n); c; c = nextSibling(c)) { + // const char *tag = Char(nodeType(c)); + // if (Strcmp(tag,"cdecl") == 0) { + name = Getattr(c, "name"); + String *type = Getattr(c, "type"); + String *val = Getattr(c, "enumvalue"); + if(val && Char(val)) { + int inval = (int) getNumber(val, type); + if(inval == DEFAULT_NUMBER) + value++; + else + value = inval; + } else + value++; + + Printf(scode, "%s%s%s'%s' = %d%s\n", tab8, tab8, tab8, name, value, + nextSibling(c) ? ", " : ""); + // } + } + + Printv(scode, "))", NIL); + Printf(sfile, "%s\n", scode); + + Delete(scode); + Delete(mangled_tdname); + + return SWIG_OK; +} + + +/************************************************************* +**************************************************************/ +int R::variableWrapper(Node *n) { + String *name = Getattr(n, "sym:name"); + + processing_variable = 1; + Language::variableWrapper(n); // Force the emission of the _set and _get function wrappers. + processing_variable = 0; + + + SwigType *ty = Getattr(n, "type"); + int addCopyParam = addCopyParameter(ty); + + //XXX + processType(ty, n); + + if(!SwigType_isconst(ty)) { + Wrapper *f = NewWrapper(); + Printf(f->def, "%s = \nfunction(value%s)\n{\n", + name, addCopyParam ? ", .copy = FALSE" : ""); + Printv(f->code, "if(missing(value)) {\n", + name, "_get(", addCopyParam ? ".copy" : "", ")\n}", NIL); + Printv(f->code, " else {\n", + name, "_set(value)\n}\n}", NIL); + + Wrapper_print(f, sfile); + DelWrapper(f); + } else { + Printf(sfile, "%s = %s_get\n", name, name); + } + + return SWIG_OK; +} + + +void R::addAccessor(String *memberName, Wrapper *wrapper, String *name, + int isSet) { + if(isSet < 0) { + int n = Len(name); + char *ptr = Char(name); + isSet = Strcmp(NewString(&ptr[n-3]), "set") == 0; + } + + List *l = isSet ? class_member_set_functions : class_member_functions; + + if(!l) { + l = NewList(); + if(isSet) + class_member_set_functions = l; + else + class_member_functions = l; + } + + Append(l, memberName); + Append(l, name); + + String *tmp = NewString(""); + Wrapper_print(wrapper, tmp); + Append(l, tmp); + // if we could put the wrapper in directly: Append(l, Copy(sfun)); + if (debugMode) + Printf(stderr, "Adding accessor: %s (%s) => %s\n", memberName, name, tmp); +} + +#define MAX_OVERLOAD 256 + +struct Overloaded { + Node *n; /* Node */ + int argc; /* Argument count */ + ParmList *parms; /* Parameters used for overload check */ + int error; /* Ambiguity error */ +}; + + +static List * Swig_overload_rank(Node *n, + bool script_lang_wrapping) { + Overloaded nodes[MAX_OVERLOAD]; + int nnodes = 0; + Node *o = Getattr(n,"sym:overloaded"); + + + if (!o) return 0; + + Node *c = o; + while (c) { + if (Getattr(c,"error")) { + c = Getattr(c,"sym:nextSibling"); + continue; + } + /* if (SmartPointer && Getattr(c,"cplus:staticbase")) { + c = Getattr(c,"sym:nextSibling"); + continue; + } */ + + /* Make a list of all the declarations (methods) that are overloaded with + * this one particular method name */ + + if (Getattr(c,"wrap:name")) { + nodes[nnodes].n = c; + nodes[nnodes].parms = Getattr(c,"wrap:parms"); + nodes[nnodes].argc = emit_num_required(nodes[nnodes].parms); + nodes[nnodes].error = 0; + nnodes++; + } + c = Getattr(c,"sym:nextSibling"); + } + + /* Sort the declarations by required argument count */ + { + int i,j; + for (i = 0; i < nnodes; i++) { + for (j = i+1; j < nnodes; j++) { + if (nodes[i].argc > nodes[j].argc) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + } + } + } + + /* Sort the declarations by argument types */ + { + int i,j; + for (i = 0; i < nnodes-1; i++) { + if (nodes[i].argc == nodes[i+1].argc) { + for (j = i+1; (j < nnodes) && (nodes[j].argc == nodes[i].argc); j++) { + Parm *p1 = nodes[i].parms; + Parm *p2 = nodes[j].parms; + int differ = 0; + int num_checked = 0; + while (p1 && p2 && (num_checked < nodes[i].argc)) { + // Printf(stdout,"p1 = '%s', p2 = '%s'\n", Getattr(p1,"type"), Getattr(p2,"type")); + if (checkAttribute(p1,"tmap:in:numinputs","0")) { + p1 = Getattr(p1,"tmap:in:next"); + continue; + } + if (checkAttribute(p2,"tmap:in:numinputs","0")) { + p2 = Getattr(p2,"tmap:in:next"); + continue; + } + String *t1 = Getattr(p1,"tmap:typecheck:precedence"); + String *t2 = Getattr(p2,"tmap:typecheck:precedence"); + if ((!t1) && (!nodes[i].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[i].n), Getline(nodes[i].n), + "Overloaded %s(%s) not supported (no type checking rule for '%s').\n", + Getattr(nodes[i].n,"name"),ParmList_str_defaultargs(Getattr(nodes[i].n,"parms")), + SwigType_str(Getattr(p1,"type"),0)); + nodes[i].error = 1; + } else if ((!t2) && (!nodes[j].error)) { + Swig_warning(WARN_TYPEMAP_TYPECHECK, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded %s(%s) not supported (no type checking rule for '%s').\n", + Getattr(nodes[j].n,"name"),ParmList_str_defaultargs(Getattr(nodes[j].n,"parms")), + SwigType_str(Getattr(p2,"type"),0)); + nodes[j].error = 1; + } + if (t1 && t2) { + int t1v, t2v; + t1v = atoi(Char(t1)); + t2v = atoi(Char(t2)); + differ = t1v-t2v; + } + else if (!t1 && t2) differ = 1; + else if (t2 && !t1) differ = -1; + else if (!t1 && !t2) differ = -1; + num_checked++; + if (differ > 0) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + break; + } else if ((differ == 0) && (Strcmp(t1,"0") == 0)) { + t1 = Getattr(p1,"ltype"); + if (!t1) { + t1 = SwigType_ltype(Getattr(p1,"type")); + if (Getattr(p1,"tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t1); + } + Setattr(p1,"ltype",t1); + } + t2 = Getattr(p2,"ltype"); + if (!t2) { + t2 = SwigType_ltype(Getattr(p2,"type")); + if (Getattr(p2,"tmap:typecheck:SWIGTYPE")) { + SwigType_add_pointer(t2); + } + Setattr(p2,"ltype",t2); + } + + /* Need subtype check here. If t2 is a subtype of t1, then we need to change the + order */ + + if (SwigType_issubtype(t2,t1)) { + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + + if (Strcmp(t1,t2) != 0) { + differ = 1; + break; + } + } else if (differ) { + break; + } + if (Getattr(p1,"tmap:in:next")) { + p1 = Getattr(p1,"tmap:in:next"); + } else { + p1 = nextSibling(p1); + } + if (Getattr(p2,"tmap:in:next")) { + p2 = Getattr(p2,"tmap:in:next"); + } else { + p2 = nextSibling(p2); + } + } + if (!differ) { + /* See if declarations differ by const only */ + String *d1 = Getattr(nodes[i].n,"decl"); + String *d2 = Getattr(nodes[j].n,"decl"); + if (d1 && d2) { + String *dq1 = Copy(d1); + String *dq2 = Copy(d2); + if (SwigType_isconst(d1)) { + Delete(SwigType_pop(dq1)); + } + if (SwigType_isconst(d2)) { + Delete(SwigType_pop(dq2)); + } + if (Strcmp(dq1,dq2) == 0) { + + if (SwigType_isconst(d1) && !SwigType_isconst(d2)) { + if (script_lang_wrapping) { + // Swap nodes so that the const method gets ignored (shadowed by the non-const method) + Overloaded t = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = t; + } + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded %s(%s) const ignored. Non-const method at %s:%d used.\n", + Getattr(nodes[j].n,"name"), ParmList_protostr(nodes[j].parms), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s(%s) ignored. Method %s(%s) const at %s:%d used.\n", + Getattr(nodes[j].n,"name"), ParmList_protostr(nodes[j].parms), + Getattr(nodes[i].n,"name"), ParmList_protostr(nodes[i].parms), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } + } + nodes[j].error = 1; + } else if (!SwigType_isconst(d1) && SwigType_isconst(d2)) { + differ = 1; + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_CONST, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded %s(%s) const ignored. Non-const method at %s:%d used.\n", + Getattr(nodes[j].n,"name"), ParmList_protostr(nodes[j].parms), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s(%s) const ignored. Method %s(%s) at %s:%d used.\n", + Getattr(nodes[j].n,"name"), ParmList_protostr(nodes[j].parms), + Getattr(nodes[i].n,"name"), ParmList_protostr(nodes[i].parms), + Getfile(nodes[i].n), Getline(nodes[i].n)); + } + } + nodes[j].error = 1; + } + } + Delete(dq1); + Delete(dq2); + } + } + if (!differ) { + if (!nodes[j].error) { + if (script_lang_wrapping) { + Swig_warning(WARN_LANG_OVERLOAD_SHADOW, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded %s(%s)%s is shadowed by %s(%s)%s at %s:%d.\n", + Getattr(nodes[j].n,"name"), ParmList_protostr(nodes[j].parms), + SwigType_isconst(Getattr(nodes[j].n,"decl")) ? " const" : "", + Getattr(nodes[i].n,"name"), ParmList_protostr(nodes[i].parms), + SwigType_isconst(Getattr(nodes[i].n,"decl")) ? " const" : "", + Getfile(nodes[i].n),Getline(nodes[i].n)); + } else { + if (!Getattr(nodes[j].n, "overload:ignore")) + Swig_warning(WARN_LANG_OVERLOAD_IGNORED, Getfile(nodes[j].n), Getline(nodes[j].n), + "Overloaded method %s(%s)%s ignored. Method %s(%s)%s at %s:%d used.\n", + Getattr(nodes[j].n,"name"), ParmList_protostr(nodes[j].parms), + SwigType_isconst(Getattr(nodes[j].n,"decl")) ? " const" : "", + Getattr(nodes[i].n,"name"), ParmList_protostr(nodes[i].parms), + SwigType_isconst(Getattr(nodes[i].n,"decl")) ? " const" : "", + Getfile(nodes[i].n),Getline(nodes[i].n)); + } + nodes[j].error = 1; + } + } + } + } + } + } + List *result = NewList(); + { + int i; + for (i = 0; i < nnodes; i++) { + if (nodes[i].error) + Setattr(nodes[i].n, "overload:ignore", "1"); + Append(result,nodes[i].n); + // Printf(stdout,"[ %d ] %s\n", i, ParmList_protostr(nodes[i].parms)); + // Swig_print_node(nodes[i].n); + } + } + return result; +} + +void R::dispatchFunction(Node *n) { + Wrapper *f = NewWrapper(); + String *symname = Getattr(n, "sym:name"); + String *nodeType = Getattr(n, "nodeType"); + bool constructor = (!Cmp(nodeType, "constructor")); + + String *sfname = NewString(symname); + + if (constructor) + Replace(sfname, "new_", "", DOH_REPLACE_FIRST); + + Printf(f->def, + "`%s` <- function(...) {", sfname); + List *dispatch = Swig_overload_rank(n, true); + int nfunc = Len(dispatch); + Printv(f->code, + "argtypes <- mapply(class, list(...))\n", + "argc <- length(argtypes)\n", NIL ); + + Printf(f->code, "# dispatch functions %d\n", nfunc); + int cur_args = -1; + bool first_compare = true; + for (int i=0; i < nfunc; i++) { + Node *ni = Getitem(dispatch,i); + Parm *pi = Getattr(ni,"wrap:parms"); + int num_arguments = emit_num_arguments(pi); + + String *overname = Getattr(ni,"sym:overname"); + if (cur_args != num_arguments) { + if (cur_args != -1) { + Printv(f->code, "} else ", NIL); + } + Printf(f->code, "if (argc == %d) {", num_arguments); + cur_args = num_arguments; + first_compare = true; + } + Parm *p; + int j; + if (num_arguments > 0) { + if (!first_compare) { + Printv(f->code, " else ", NIL); + } else { + first_compare = false; + } + Printv(f->code, "if (", NIL); + for (p =pi, j = 0 ; j < num_arguments ; j++) { + String *tm = Swig_typemap_lookup_new("rtype", p, "", 0); + if(tm) { + replaceRClass(tm, Getattr(p, "type")); + } + Printf(f->code, "%sextends(argtypes[%d], '%s')", + j == 0 ? "" : " && ", + j+1, + tm); + p = Getattr(p, "tmap:in:next"); + } + Printf(f->code, ") { f <- %s%s }\n", sfname, overname); + } else { + Printf(f->code, "f <- %s%s", sfname, overname); + } + } + if (cur_args != -1) { + Printv(f->code, "}", NIL); + } + Printv(f->code, "\nf(...)", NIL); + Printv(f->code, "\n}", NIL); + Wrapper_print(f, sfile); + Printv(sfile, "# Dispatch function\n", NIL); +} + +/****************************************************************** + +*******************************************************************/ +int R::functionWrapper(Node *n) { + String *fname = Getattr(n, "name"); + String *iname = Getattr(n, "sym:name"); + String *type = Getattr(n, "type"); + + if (debugMode) { + Printf(stderr, + " %s %s %s\n", fname, iname, type); + } + String *overname = 0; + String *nodeType = Getattr(n, "nodeType"); + bool constructor = (!Cmp(nodeType, "constructor")); + bool destructor = (!Cmp(nodeType, "destructor")); + + String *sfname = NewString(iname); + + if (constructor) + Replace(sfname, "new_", "", DOH_REPLACE_FIRST); + + if (Getattr(n,"sym:overloaded")) { + overname = Getattr(n,"sym:overname"); + Append(sfname, overname); + } + + if (debugMode) + Printf(stderr, + " processing parameters\n"); + + + ParmList *l = Getattr(n, "parms"); + Parm *p; + String *returnTM = NULL; + String *tm; + + p = l; + while(p) { + SwigType *resultType = Getattr(p, "type"); + if (expandTypedef(resultType) && + SwigType_istypedef(resultType)) { + SwigType *resolved = + SwigType_typedef_resolve_all(resultType); + if (expandTypedef(resolved)) { + Setattr(p, "type", Copy(resolved)); + } + } + p = nextSibling(p); + } + + String *unresolved_return_type = + Copy(type); + if (expandTypedef(type) && + SwigType_istypedef(type)) { + SwigType *resolved = + SwigType_typedef_resolve_all(type); + if (expandTypedef(resolved)) { + type = Copy(resolved); + Setattr(n, "type", type); + } + } + if (debugMode) + Printf(stderr, " unresolved_return_type %s\n", + unresolved_return_type); + if(processing_member_access_function) { + if (debugMode) + Printf(stderr, " '%s' '%s' '%s' '%s'\n", + fname, iname, member_name, class_name); + + if(opaqueClassDeclaration) + return SWIG_OK; + + + /* Add the name of this member to a list for this class_name. + We will dump all these at the end. */ + + int n = Len(iname); + char *ptr = Char(iname); + bool isSet(Strcmp(NewString(&ptr[n-3]), "set") == 0); + + + String *tmp = NewString(""); + Printf(tmp, "%s_%s", class_name, isSet ? "set" : "get"); + + List *memList = Getattr(ClassMemberTable, tmp); + if(!memList) { + memList = NewList(); + Append(memList, class_name); + Setattr(ClassMemberTable, tmp, memList); + } + Delete(tmp); + Append(memList, member_name); + Append(memList, iname); + } + + int i; + int nargs, num_required, varargs; + UNUSED(varargs); + + String *wname = Swig_name_wrapper(iname); + Replace(wname, "_wrap", "R_swig", DOH_REPLACE_FIRST); + if(overname) + Append(wname, overname); + Setattr(n,"wrap:name", wname); + + Wrapper *f = NewWrapper(); + Wrapper *sfun = NewWrapper(); + + + int isVoidReturnType = 0; + returnTM = Swig_typemap_lookup_new("out", n, "result",0); + if(returnTM) + isVoidReturnType = (Strcmp(type, "void") == 0); + + SwigType *rtype = Getattr(n, "type"); + int addCopyParam = 0; + + if(!isVoidReturnType) + addCopyParam = addCopyParameter(rtype); + + + // Can we get the nodeType() of the type node! and see if it is a struct. + // int addCopyParam = SwigType_isclass(rtype); + + // if(addCopyParam) + if (debugMode) + Printf(stderr, "Adding a .copy argument to %s for %s = %s\n", + iname, type, addCopyParam ? "yes" : "no"); + if (inCPlusMode) + Printv(f->def, "extern \"C\" ", NIL); + + Printv(f->def, "SWIGINTERN SEXP\n", wname, " ( ", NIL); + + Printf(sfun->def, "# Start of %s\n", iname); + Printv(sfun->def, "\n`", sfname, "` = function(", NIL); + + if(outputNamespaceInfo) //XXX Need to be a little more discriminating + addNamespaceFunction(iname); + + Swig_typemap_attach_parms("scoercein", l, f); + Swig_typemap_attach_parms("scoerceout", l, f); + Swig_typemap_attach_parms("scheck", l, f); + + // Need to use the unresolved return type since + // typedef resolution removes the const which causes a + // mismatch with the function action + emit_args(unresolved_return_type, l, f); + emit_attach_parmmaps(l,f); + Setattr(n,"wrap:parms",l); + + nargs = emit_num_arguments(l); + num_required = emit_num_required(l); + varargs = emit_isvarargs(l); + + Wrapper_add_local(f, "__r_nprotect", "unsigned int __r_nprotect = 0"); + Wrapper_add_localv(f, "r_ans", "SEXP", "r_ans = R_NilValue", NIL); + Wrapper_add_localv(f, "r_vmax", "char *", "r_vmax = vmaxget()", NIL); + + String *sargs = NewString(""); + + + String *s_inputTypes = NewString(""); + String *s_inputMap = NewString(""); + bool inFirstArg = true; + Parm *curP; + for (p =l, i = 0 ; i < nargs ; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *tt = Getattr(p, "type"); + int nargs = -1; + String *funcptr_name = processType(tt, p, &nargs); + + // SwigType *tp = Getattr(p, "type"); + String *name = Getattr(p,"name"); + String *lname = Getattr(p,"lname"); + + + /* If we have a :: in the parameter name because we are accessing a static member of a class, say, then + we need to remove that prefix. */ + while (Strstr(name, "::")) { + //XXX need to free. + name = NewStringf("%s", Strchr(name, ':') + 2); + if (debugMode) + Printf(stderr, "+++ parameter name with :: in it %s\n", name); + } + if (Len(name) == 0) + name = NewStringf("s_arg%d", i+1); + + if (!Strncmp(name, "_", 1)) { + name = Copy(name); + Insert(name, 0, "s"); + } + + if (!Strncmp(name, "arg", 3)) { + name = Copy(name); + Insert(name, 0, "s_"); + } + + if(processing_variable) { + name = Copy(name); + Insert(name, 0, "s_"); + } + + if(!Strcmp(name, fname)) { + name = Copy(name); + Insert(name, 0, "s_"); + } + + Printf(sargs, "%s, ", name); + + String *tm; + if((tm = Getattr(p, "tmap:scoercein"))) { + Replaceall(tm, "$input", name); + replaceRClass(tm, Getattr(p, "type")); + + if(funcptr_name) { + //XXX need to get this to return non-zero + if(nargs == -1) + nargs = getFunctionPointerNumArgs(p, tt); + + String *snargs = NewStringf("%d", nargs); + Printv(sfun->code, "if(is.function(", name, ")) {", "\n", + "assert('...' %in% names(formals(", name, + ")) || length(formals(", name, ")) >= ", snargs, ")\n} ", NIL); + Delete(snargs); + + Printv(sfun->code, "else {\n", + "if(is.character(", name, ")) {\n", + name, " = getNativeSymbolInfo(", name, ")", + "\n}\n", + "if(is(", name, ", \"NativeSymbolInfo\")) {\n", + name, " = ", name, "$address", "\n}\n", + "}\n", + NIL); + } else { + Printf(sfun->code, "%s\n", tm); + } + } + + Printv(sfun->def, inFirstArg ? "" : ", ", name, NIL); + + if ((tm = Getattr(p,"tmap:scheck"))) { + + Replaceall(tm,"$target", lname); + Replaceall(tm,"$source", name); + Replaceall(tm,"$input", name); + replaceRClass(tm, Getattr(p, "type")); + Printf(sfun->code,"%s\n",tm); + } + + + + curP = p; + if ((tm = Getattr(p,"tmap:in"))) { + + Replaceall(tm,"$target", lname); + Replaceall(tm,"$source", name); + Replaceall(tm,"$input", name); + + if (Getattr(p,"wrap:disown") || (Getattr(p,"tmap:in:disown"))) { + Replaceall(tm,"$disown","SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm,"$disown","0"); + } + + if(funcptr_name) { + /* have us a function pointer */ + Printf(f->code, "if(TYPEOF(%s) != CLOSXP) {\n", name); + Replaceall(tm,"$R_class", ""); + } else { + replaceRClass(tm, Getattr(p, "type")); + } + + + Printf(f->code,"%s\n",tm); + if(funcptr_name) + Printf(f->code, "} else {\n%s = %s;\nR_SWIG_pushCallbackFunctionData(%s, NULL);\n}\n", + lname, funcptr_name, name); + Printv(f->def, inFirstArg ? "" : ", ", "SEXP ", name, NIL); + if (Len(name) != 0) + inFirstArg = false; + p = Getattr(p,"tmap:in:next"); + + } else { + p = nextSibling(p); + } + + + tm = Swig_typemap_lookup_new("rtype", curP, "", 0); + if(tm) { + replaceRClass(tm, Getattr(curP, "type")); + } + Printf(s_inputTypes, "'%s'%s", tm, p ? ", " : ""); + Printf(s_inputMap, "%s='%s'%s", name, tm, p ? ", " : ""); + + if(funcptr_name) + Delete(funcptr_name); + } /* end of looping over parameters. */ + + if(addCopyParam) { + Printf(sfun->def, "%s.copy = FALSE", nargs > 0 ? ", " : ""); + Printf(f->def, "%sSEXP s_swig_copy", nargs > 0 ? ", " : ""); + + Printf(sargs, "as.logical(.copy), "); + } + + Printv(f->def, ")\n{\n", NIL); + Printv(sfun->def, ")\n{\n", NIL); + + emit_action(n, f); + + + + + String *outargs = NewString(""); + int numOutArgs = isVoidReturnType ? -1 : 0; + for(p = l, i = 0; p; i++) { + String *tm; + if((tm = Getattr(p, "tmap:argout"))) { + // String *lname = Getattr(p, "lname"); + numOutArgs++; + String *pos = NewStringf("%d", numOutArgs); + Replaceall(tm,"$source", Getattr(p, "lname")); + Replaceall(tm,"$result", "r_ans"); + Replaceall(tm,"$n", pos); // The position into which to store the answer. + Replaceall(tm,"$arg", Getattr(p, "emit:input")); + Replaceall(tm,"$input", Getattr(p, "emit:input")); + Replaceall(tm,"$owner", "R_SWIG_EXTERNAL"); + + + Printf(outargs, "%s\n", tm); + p = Getattr(p,"tmap:argout:next"); + } else + p = nextSibling(p); + } + + /* Deal with the explicit return value. */ + if (returnTM) { + String *tm = returnTM; + SwigType *retType = Getattr(n, "type"); + //Printf(stderr, "Return Value for %s, array? %s\n", retType, SwigType_isarray(retType) ? "yes" : "no"); + /* if(SwigType_isarray(retType)) { + defineArrayAccessors(retType); + } */ + + + Replaceall(tm,"$1", "result"); + Replaceall(tm,"$result", "r_ans"); + replaceRClass(tm, retType); + + if (GetFlag(n,"feature:new")) { + Replaceall(tm, "$owner", "R_SWIG_OWNER"); + } else { + Replaceall(tm,"$owner", "R_SWIG_EXTERNAL"); + } + + if(0 && addCopyParam) { + Printf(f->code, "if(LOGICAL(s_swig_copy)[0]) {\n"); + Printf(f->code, "/* Deal with returning a reference. */\nr_ans = R_NilValue;\n"); + Printf(f->code, "}\n else {\n"); + } + Printf(f->code, "%s\n", tm); + if(0 && addCopyParam) + Printf(f->code, "}\n"); /* end of if(s_swig_copy) ... else { ... } */ + + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, + "Unable to use return type %s in function %s.\n", SwigType_str(type, 0), fname); + } + + + if(Len(outargs)) { + Wrapper_add_local(f, "R_OutputValues", "SEXP R_OutputValues"); + + String *tmp = NewString(""); + if(!isVoidReturnType) + Printf(tmp, "PROTECT(r_ans);\n"); + + Printf(tmp, "PROTECT(R_OutputValues = NEW_LIST(%d));\n__r_nprotect += %d;\n", + numOutArgs + !isVoidReturnType, + isVoidReturnType ? 1 : 2); + + if(!isVoidReturnType) + Printf(tmp, "SET_VECTOR_ELT(R_OutputValues, 0, r_ans);\n"); + Printf(tmp, "r_ans = R_OutputValues;\n"); + + Insert(outargs, 0, tmp); + Delete(tmp); + + Printf(f->code, "%s", outargs); + Delete(outargs); + } + + + + Printv(f->code, UnProtectWrapupCode, NIL); + + /*If the user gave us something to convert the result in */ + if ((tm = Swig_typemap_lookup_new("scoerceout", n, + "result", sfun))) { + Replaceall(tm,"$source","ans"); + Replaceall(tm,"$result","ans"); + replaceRClass(tm, Getattr(n, "type")); + Chop(tm); + } + + + Printv(sfun->code, (Len(tm) ? "ans = " : ""), ".Call('", wname, + "', ", sargs, "PACKAGE='", DllName, "')\n", NIL); + if(Len(tm)) + Printf(sfun->code, "%s\n\nans\n", tm); + if (destructor) + Printv(f->code, "R_ClearExternalPtr(self);\n", NIL); + + Printv(f->code, "return r_ans;\n}\n", NIL); + Printv(sfun->code, "\n}", NIL); + + Wrapper_print(f, f_wrapper); + Wrapper_print(sfun, sfile); + + Printf(sfun->code, "\n# End of %s\n", iname); + tm = Swig_typemap_lookup_new("rtype", n, "", 0); + if(tm) { + SwigType *retType = Getattr(n, "type"); + replaceRClass(tm, retType); + } + + Printv(sfile, "attr(`", sfname, "`, 'returnType') = '", + isVoidReturnType ? "void" : (tm ? tm : ""), + "'\n", NIL); + + if(nargs > 0) + Printv(sfile, "attr(`", sfname, "`, \"inputTypes\") = c(", + s_inputTypes, ")\n", NIL); + Printv(sfile, "class(`", sfname, "`) = c(\"SWIGFunction\", class('", + sfname, "'))\n\n", NIL); + + if (memoryProfile) { + Printv(sfile, "memory.profile()\n", NIL); + } + if (aggressiveGc) { + Printv(sfile, "gc()\n", NIL); + } + + // Printv(sfile, "setMethod('", name, "', '", name, "', ", iname, ")\n\n\n"); + + + + /* If we are dealing with a method in an C++ class, then + add the name of the R function and its definition. + XXX need to figure out how to store the Wrapper if possible in the hash/list. + Would like to be able to do this so that we can potentialy insert + */ + if(processing_member_access_function || processing_class_member_function) { + String *tmp; + if(member_name) + tmp = member_name; + else + tmp = Getattr(n, "memberfunctionHandler:name"); + addAccessor(member_name, sfun, iname); + } + + if (Getattr(n, "sym:overloaded") && + !Getattr(n, "sym:nextSibling")) { + dispatchFunction(n); + } + + addRegistrationRoutine(wname, addCopyParam ? nargs +1 : nargs); + + DelWrapper(f); + DelWrapper(sfun); + + Delete(sargs); + Delete(sfname); + return SWIG_OK; +} + + +int R::defineArrayAccessors(SwigType *type) { + + SwigType *base = SwigType_base(type); + String *rclass = NewStringf("%sArray", base); + char *prclassName = Char(rclass); + if(strncmp(prclassName, "struct ", 7) == 0) + prclassName += 7; + + Node *n = NewHash(); + Setattr(n, "type", base); + String *tm; + String *rclassName = getRClassName(base); + String *rclassBase = getRClassName(base, 0); + + String *cGetName = NewStringf("R_SWIG_%s_get_item_", prclassName); + String *cSetName = NewStringf("R_SWIG_%s_set_item_", prclassName); + + Wrapper *cGetItem = NewWrapper(); + + String *getItem = NewString(""), + *setItem = NewString(""); + + Printf(getItem, "function(x, i, j, ..., drop = TRUE) {\n"); + + Printf(getItem, "%sif(i < 1 || i > x@dims[1])\n%sstop('index must be between 1 and ', x@dims[1])\n", tab4, tab8); + Printf(getItem, "%s.Call('%s', x@ref, as.integer(i-1), PACKAGE = '%s')\n", tab4, cGetName, DllName); + Printf(getItem, "}\n"); + + + + Printf(setItem, "function(x, i, j, ..., value) {\n"); + + Printf(setItem, "%sif(i < 1 || i > x@dims[1])\n%sstop('index must be between 1 and ', x@dims[1])\n", tab4, tab8); + + /* Do the SCOERCEIN and the SCHECK here */ + tm = Swig_typemap_lookup_new("scoercein", n, "value", 0); + if(tm) { + Replaceall(tm, "$input", "s_value"); + Replaceall(tm, "$R_class", rclassName); + Replaceall(tm, "$*R_class", rclassBase); + + Printf(setItem, "%s%s\n", tab4, tm); + } + + tm = Swig_typemap_lookup_new("scheck", n, "value", 0); + if(tm) { + Replaceall(tm, "$input", "s_value"); + Replaceall(tm, "$R_class", rclassName); + Replaceall(tm, "$*R_class", rclassBase); + + Printf(setItem, "%s%s\n", tab4, tm); + } + + + + Printf(setItem, "%s.Call('%s', x@ref, as.integer(i-1), value, PACKAGE = '%s')\n", tab4, cSetName, DllName); + Printf(setItem, "%sx\n}\n", tab4); + + + + Printf(cGetItem->def, "SEXP\n%s(SEXP s_x, SEXP s_i)\n{\n", cGetName); + + String *tmp = NewStringf("%s *ptr", SwigType_lstr(base, 0)); + String *tmp1 = NewStringf("%s result", SwigType_lstr(base, 0)); + + Wrapper_add_localv(cGetItem, "r_vmax", "char *", "r_vmax = vmaxget()", NIL); + Wrapper_add_local(cGetItem, "ptr", tmp); + Wrapper_add_local(cGetItem, "r_ans", "SEXP r_ans"); + Wrapper_add_local(cGetItem, "result", tmp1); + Wrapper_add_local(cGetItem, "__r_nprotect", "int __r_nprotect = 0"); + + Printf(cGetItem->code, "ptr = (%s *) R_SWIG_resolveExternalRef(s_x, \"\", \"s_x\", 0);\n", SwigType_lstr(base, 0)); + Printf(cGetItem->code, "result = ptr[INTEGER(s_i)[0]];\n", tmp); + + + tm = Swig_typemap_lookup_new("out", n, "result", 0); + if(tm) { + Replaceall(tm, "$result", "r_ans"); + Replaceall(tm,"$owner", "R_SWIG_EXTERNAL"); + Printf(cGetItem->code, "%s\n", tm); + } + + Delete(tmp); Delete(tmp1); + + Printf(cGetItem->code, "%s\nreturn r_ans;\n}\n\n", UnProtectWrapupCode); + + + /******************************/ + /* + R_SWIG_..._set_item(SEXP x, SEXP s_i, SEXP s_value) { + char *r_vmax = vmaxget(); + int __r_nprotect = 0; + type *ptr, *el, value; + + ptr = (type *) R_SWIG_resolveExternalRef(s_x, "", "s_x", 0); + + ptr[INTEGER(s_i)[0]] = *el; + + cleanup + return + } + */ + Wrapper *cSetItem = NewWrapper(); + { + + Printf(cSetItem->def, "SEXP\n%s(SEXP s_x, SEXP s_i, SEXP s_value)\n{\n", cSetName); + + tmp = NewStringf("%s *ptr", SwigType_lstr(base, 0)); + tmp1 = NewStringf("%s value", SwigType_lstr(base, 0)); + + Wrapper_add_localv(cSetItem, "r_vmax", "char *", "r_vmax = vmaxget()", NIL); + Wrapper_add_local(cSetItem, "__r_nprotect", "int __r_nprotect = 0"); + + Wrapper_add_local(cSetItem, "ptr", tmp); + Wrapper_add_local(cSetItem, "value", tmp1); + Replaceall(tmp, "*ptr", "*el = &value"); + Wrapper_add_local(cSetItem, "el", tmp); + + Printf(cSetItem->code, + "ptr = (%s *) R_SWIG_resolveExternalRef(s_x, \"\", \"s_x\", 0);\n", + SwigType_lstr(base, 0)); + + + String *tm = Swig_typemap_lookup_new("in", n, "value", 0); + if(tm) { + String *rclassName = getRClassName(base); + String *rclassBase = getRClassName(base, 0); + Replaceall(tm, "$input", "s_value"); + Replaceall(tm, "$*1", "value"); + //XXX think about what we really mean here. + Replaceall(tm, "$1", "el"); + + Replaceall(tm, "$R_class", rclassName); + Replaceall(tm, "$*R_class", rclassBase); + + Printf(cSetItem->code, "%s\n", tm); + + Delete(rclassName); Delete(rclassBase); + } + Printf(cSetItem->code, "ptr[INTEGER(s_i)[0]] = *el;\n", tmp); + } + Printf(cSetItem->code, "%s\nreturn R_NilValue;\n}\n\n", UnProtectWrapupCode); + + /*************************/ + + + Wrapper_print(cGetItem, f_wrapper); + Wrapper_print(cSetItem, f_wrapper); + + String *elClass = NewStringf("_p%s", SwigType_manglestr(base)); + if(!Getattr(SClassDefs, elClass)) { + if (debugMode) + Printf(stderr, " Defining class %s\n", elClass); + Printf(s_classes, "setClass('%s', contains = 'ExternalReference')\n", elClass); + //Add to namespace + Setattr(SClassDefs, elClass, elClass); + } + Delete(elClass); + + if(!Getattr(SClassDefs, rclassName)) { + Setattr(SClassDefs, rclassName, rclassName); + Printf(s_classes, "setClass('%s', contains = 'SWIGArray')\n", rclassName); + } + + Printf(s_classes, "setMethod('[', '%s',\n%s)\n", rclassName, getItem); + Printf(s_classes, "setMethod('[<-', '%s',\n%s)\n", rclassName, setItem); + + + Delete(n); + DelWrapper(cGetItem); + DelWrapper(cSetItem); + Delete(rclass); + Delete(cGetName); + + return SWIG_OK; +} + + +/***************************************************** + Add the specified routine name to the collection of + generated routines that are called from R functions. + This is used to register the routines with R for + resolving symbols. + + rname - the name of the routine + nargs - the number of arguments it expects. +******************************************************/ +int R::addRegistrationRoutine(String *rname, int nargs) { + if(!registrationTable) + registrationTable = NewHash(); + + String *el = + NewStringf("{\"%s\", (DL_FUNC) &%s, %d}", rname, rname, nargs); + + Setattr(registrationTable, rname, el); + + return SWIG_OK; +} + +/***************************************************** + Write the registration information to an array and + create the initialization routine for registering + these. +******************************************************/ +int R::outputRegistrationRoutines(File *out) { + int i, n; + if(!registrationTable) + return(0); + if(inCPlusMode) + Printf(out, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n"); + + Printf(out, "#include \n\n"); + if(inCPlusMode) + Printf(out, "#ifdef __cplusplus\n}\n#endif\n\n"); + + Printf(out, "SWIGINTERN R_CallMethodDef CallEntries[] = {\n"); + + List *keys = Keys(registrationTable); + n = Len(keys); + for(i = 0; i < n; i++) + Printf(out, " %s,\n", Getattr(registrationTable, Getitem(keys, i))); + + Printf(out, " {NULL, NULL, 0}\n};\n\n"); + + if(!noInitializationCode) { + if (inCPlusMode) + Printv(out, "extern \"C\" ", NIL); + Printf(out, "SWIGEXPORT void R_init_%s_wrap(DllInfo *dll) {\n", Rpackage); + Printf(out, "%sR_registerRoutines(dll, NULL, CallEntries, NULL, NULL);\n", tab4); + if(Len(s_init_routine)) { + Printf(out, "\n%s\n", s_init_routine); + } + Printf(out, "}\n"); + } + + return n; +} + + + +/**************************************************************************** + Process a struct, union or class declaration in the source code, + or an anonymous typedef struct + +*****************************************************************************/ +//XXX What do we need to do here - +// Define an S4 class to refer to this. + +void R::registerClass(Node *n) { + String *name = Getattr(n, "name"); + String *kind = Getattr(n, "kind"); + + if (debugMode) + Swig_print_node(n); + String *sname = NewStringf("_p%s", SwigType_manglestr(name)); + if(!Getattr(SClassDefs, sname)) { + Setattr(SClassDefs, sname, sname); + String *base; + + if(Strcmp(kind, "class") == 0) { + base = NewString(""); + List *l = Getattr(n, "bases"); + if(Len(l)) { + Printf(base, "c("); + for(int i = 0; i < Len(l); i++) { + registerClass(Getitem(l, i)); + Printf(base, "'_p%s'%s", + SwigType_manglestr(Getattr(Getitem(l, i), "name")), + i < Len(l)-1 ? ", " : ""); + } + Printf(base, ")"); + } else { + base = NewString("'C++Reference'"); + } + } else + base = NewString("'ExternalReference'"); + + Printf(s_classes, "setClass('%s', contains = %s)\n", sname, base); + Delete(base); + } + +} + +int R::classDeclaration(Node *n) { + + String *name = Getattr(n, "name"); + String *kind = Getattr(n, "kind"); + + if (debugMode) + Swig_print_node(n); + registerClass(n); + + + /* If we have a typedef union { ... } U, then we never get to see the typedef + via a regular call to typedefHandler. Instead, */ + if(Getattr(n, "unnamed") && Strcmp(Getattr(n, "storage"), "typedef") == 0 + && Getattr(n, "tdname") && Strcmp(Getattr(n, "tdname"), name) == 0) { + if (debugMode) + Printf(stderr, "Typedef in the class declaration for %s\n", name); + // typedefHandler(n); + } + + bool opaque = GetFlag(n, "feature:opaque"); + + if(opaque) + opaqueClassDeclaration = name; + + int status = Language::classDeclaration(n); + + opaqueClassDeclaration = NULL; + + + // OutputArrayMethod(name, class_member_functions, sfile); + OutputMemberReferenceMethod(name, 0, class_member_functions, sfile); + OutputMemberReferenceMethod(name, 1, class_member_set_functions, sfile); + + if(class_member_functions) { + Delete(class_member_functions); + class_member_functions = NULL; + } + if(class_member_set_functions) { + Delete(class_member_set_functions); + class_member_set_functions = NULL; + } + if (Getattr(n, "has_destructor")) { + Printf(sfile, "setMethod('delete', '_p%s', function(obj) {delete%s(obj)})\n", + getRClassName(Getattr(n, "name")), + getRClassName(Getattr(n, "name"))); + + } + if(!opaque && !Strcmp(kind, "struct") && copyStruct) { + + String *def = + NewStringf("setClass(\"%s\",\n%srepresentation(\n", name, tab4); + bool firstItem = true; + + for(Node *c = firstChild(n); c; ) { + String *elName; + String *tp; + + elName = Getattr(c, "name"); + String *elKind = Getattr(c, "kind"); + if (Strcmp(elKind, "variable") != 0) { + c = nextSibling(c); + continue; + } + if (!Len(elName)) { + c = nextSibling(c); + continue; + } +#if 0 + tp = getRType(c); +#else + tp = Swig_typemap_lookup_new("rtype", c, "", 0); + if(!tp) { + c = nextSibling(c); + continue; + } + if (Strstr(tp, "R_class")) { + c = nextSibling(c); + continue; + } + if (Strcmp(tp, "character") && + Strstr(Getattr(c, "decl"), "p.")) { + c = nextSibling(c); + continue; + } + + if (!firstItem) { + Printf(def, ",\n"); + } + // else + //XXX How can we tell if this is already done. + // SwigType_push(elType, elDecl); + + + // returns "" tp = processType(elType, c, NULL); + // Printf(stderr, " elType %p\n", elType); + // tp = getRClassNameCopyStruct(Getattr(c, "type"), 1); +#endif + + Printf(def, "%s%s = \"%s\"", tab8, elName, tp); + firstItem = false; + Delete(tp); + c = nextSibling(c); + } + Printf(def, "),\n%scontains = \"RSWIGStruct\")\n", tab8); + Printf(s_classes, "%s\n\n# End class %s\n\n", def, name); + + generateCopyRoutines(n); + + Delete(def); + } + + return status; +} + + + +/*************************************************************** + Create the C routines that copy an S object of the class given + by the given struct definition in Node *n to the C value + and also the routine that goes from the C routine to an object + of this S class. +****************************************************************/ +/*XXX + Clean up the toCRef - make certain the names are correct for the types, etc. + in all cases. +*/ + +// This procedure is for reference +int R::generateCopyRoutinesObsolete(Node *n) { + Wrapper *toC = NewWrapper(); + Wrapper *toCRef = NewWrapper(); + Wrapper *toR = NewWrapper(); + + Wrapper *copyToR = NewWrapper(); + Wrapper *copyToC = NewWrapper(); + + + String *name = Getattr(n, "name"); + String *tdname = Getattr(n, "tdname"); + String *kind = Getattr(n, "kind"); + String *type; + + if(Len(tdname)) { + type = Copy(tdname); + } else { + type = NewStringf("%s %s", kind, name); + } + + +#ifdef R_SWIG_VERBOSE + if (debugMode) + Printf(stderr, "generateCopyRoutines: name = %s, %s\n", name, type); +#endif + + String *rclassNameRef = getRClassName(type, 1); + String *copyRefRefName = NewStringf("R_swig_copy_%sRef_%sRef", rclassNameRef, rclassNameRef); + String *toCName = NewStringf("R_swig_copy_%sRef_to_C", name); + String *toRName = NewStringf("R_swig_copy_%sRef_to_R", name); + + addRegistrationRoutine(copyRefRefName, 2); + addRegistrationRoutine(toCName, 2); + addRegistrationRoutine(toRName, 1); + + Printf(toC->def, "int\n%s(SEXP sobj, %s *value)", toCName, type); + Printf(toR->def, "SEXP\n%s(%s *value)", toRName, type); + Printf(toCRef->def, "SEXP\n%s(SEXP s_src, SEXP s_dest) {", copyRefRefName, type, type); + + Delete(toCName); + Delete(toRName); + + String *tmp = NewStringf("%s *src", type); + Wrapper_add_local(toCRef, "src", tmp); + Delete(tmp); + tmp = NewStringf("%s *dest", type); + Wrapper_add_local(toCRef, "dest", tmp); + Delete(tmp); + + Printf(toCRef->code, "src = (%s *) R_SWIG_resolveExternalRef(s_src, \"%sRef\", \"s_src\", (Rboolean) FALSE);\n", + type, rclassNameRef); + Printf(toCRef->code, "dest = (%s *) R_SWIG_resolveExternalRef(s_dest, \"%sRef\", \"s_dest\", (Rboolean) FALSE);\n", + type, rclassNameRef); + Printf(toCRef->code, "memcpy(dest, src, sizeof(*src));\nreturn R_NilValue;\n}\n\n"); + + + + Wrapper_add_localv(toR, "r_obj", "SEXP", "r_obj", NIL); + Wrapper_add_localv(toR, "r_vmax", "char *", "r_vmax = vmaxget()", NIL); + Wrapper_add_localv(toR, "_tmp_sexp", "SEXP", "_tmp_sexp", NIL); + Wrapper_add_local(toR, "__r_nprotect", "int __r_nprotect = 0"); + Wrapper_add_local(toC, "ecode", "int ecode = 0"); + + Printf(copyToR->def, "%sCopyToR = function(value, obj = new(\"%s\"))\n{\n", name, name); + Printf(copyToC->def, "%sCopyToC = function(value, obj)\n{\n", name); + + + Printf(toR->code, "PROTECT(r_obj = NEW_OBJECT(MAKE_CLASS(\"%s\")));\n__r_nprotect++;\n\n", name); + + Wrapper_add_localv(toC, "_tmp_sexp", "SEXP", "_tmp_sexp", NIL); + + Node *c = firstChild(n); + // Swig_typemap_attach_parms("in", c, toR); + // Swig_typemap_attach_parms("out", c, toR); + + for(; c; c = nextSibling(c)) { + String *elName = Getattr(c, "name"); + if (!Len(elName)) { + continue; + } + String *tp = Swig_typemap_lookup_new("rtype", c, "", 0); + if(!tp) { + continue; + } + /* The S functions to get and set the member value. */ + String *symname = Getattr(c, "sym:name"); + String *ClassPrefix = Getattr(n, "sym:name"); + String *get = Swig_name_get(Swig_name_member(Char(ClassPrefix), symname)); + String *set = Swig_name_set(Swig_name_member(Char(ClassPrefix), symname)); + + +#if 0 + This is already done now in getRType(). + If that for some reason no longer gets called, this had better go back. + SwigType *elTT = Getattr(c, "type"); + SwigType *decl = Getattr(c, "decl"); + SwigType_push(elTT, decl); +#endif + + + Printf(copyToR->code, "obj@%s = %s(value)\n", elName, get); + Printf(copyToC->code, "%s(obj, value@%s)\n", set, elName); + + + String *field = NewStringf("value->%s", elName); + SwigType *elType = Getattr(c, "type"); + + + String *tm = Swig_typemap_lookup_new("out", c, field, 0); + if(tm) { +#ifdef R_SWIG_VERBOSE + if (debugMode) + Printf(stderr, "Got conversion to R for '%s': '%s' '%s' -> '%s'\n", elName, elType, elTT, tm); +#endif + + //XXX Get the field in as the rhs. + // What about looking in the "memberin"/"memberout" typemaps. + Replaceall(tm, "$1", Char(field)); + Replaceall(tm, "$result", "_tmp_sexp"); + Replaceall(tm,"$owner", "R_SWIG_EXTERNAL"); + replaceRClass(tm,elType); + + + Printf(toR->code, "%s\nPROTECT(_tmp_sexp);\n__r_nprotect++;\n", tm); + Printf(toR->code, "PROTECT(r_obj = R_do_slot_assign(r_obj, mkString(\"%s\"), _tmp_sexp));\n__r_nprotect++;\n\n", elName); + } else { + Printf(stderr, "*** Can't convert field %s in \n", elName); + } + + + + char *field_p = Char(field); + tm = Swig_typemap_lookup_new("in", c, field_p, 0); + if(tm && !GetFlag(c, "feature:immutable")) { + replaceRClass(tm,elType); + if (debugMode) + Printf(stderr, "typemap (in) for %s => %s\n", + SwigType_str(elType, 0), tm); + String *tmp1 = + NewStringf("%s val", SwigType_lstr(elType, 0)); + Wrapper_add_local(toC, "val", tmp1); + Replaceall(tm, "$input", "_tmp_sexp"); + if (debugMode) + Printf(stderr, "Got conversion to C for %s: %s. %s\n", + elName, tm, field); +#ifdef R_SWIG_VERBOSE +#endif + Printf(toC->code, "_tmp_sexp = GET_SLOT(sobj, mkString(\"%s\"));\n%s\n\n", elName, tm); + Delete(field); + } + /* + + Replaceall(conversion, "$1", field); + Printf(toC->code, "value->%s = ;\n", name); + */ + } + + Printv(toR->code, UnProtectWrapupCode, + "\nreturn(r_obj);\n}\n", NIL); + + Printf(toC->code, "\nreturn(1);\n}\n"); + + + Printf(f_wrapper, "%s;\n", toR->def); + Printf(f_wrapper, "%s;\n", toC->def); + + Printf(toR->def, "\n{\n"); + Printf(toC->def, "\n{\n"); + + String *rclassName = getRClassName(type, 0); // without the Ref. + + Printf(copyToR->code, "obj\n}\n\n"); + + Printf(sfile, "# Start definition of copy functions & methods for %s\n", rclassName); + + Wrapper_print(copyToR, sfile); + Printf(copyToC->code, "obj\n}\n\n"); + Wrapper_print(copyToC, sfile); + + + Printf(sfile, "# Start definition of copy methods for %s\n", rclassName); + Printf(sfile, "setMethod('copyToR', '%sRef', %sCopyToR)\n", rclassName, name); + Printf(sfile, "setMethod('copyToC', '%s', %sCopyToC)\n\n", rclassName, name); + Printv(sfile, "setMethod('copyToC', c('", rclassName, "Ref', '", rclassName, "Ref'),", + " function(value, obj) {\n", + tab4, ".Call(\"", copyRefRefName, "\", value, obj, PACKAGE = \"", + DllName, "\")\n})\n\n", NIL); + Printf(sfile, "# End definition of copy methods for %s\n", rclassName); + Printf(sfile, "# End definition of copy functions & methods for %s\n", rclassName); + + String *m = NewStringf("%sCopyToR", name); + addNamespaceMethod(m); + char *tt = Char(m); tt[Len(m)-1] = 'C'; + addNamespaceMethod(m); + Delete(m); + + + Delete(rclassName); + + DelWrapper(copyToR); + DelWrapper(copyToC); + + Wrapper_print(toR, f_wrapper); + Wrapper_print(toC, f_wrapper); + Wrapper_print(toCRef, f_wrapper); + + DelWrapper(toR); + DelWrapper(toC); + DelWrapper(toCRef); + + return SWIG_OK; +} + +int R::generateCopyRoutines(Node *n) { + Wrapper *copyToR = NewWrapper(); + Wrapper *copyToC = NewWrapper(); + + String *name = Getattr(n, "name"); + String *tdname = Getattr(n, "tdname"); + String *kind = Getattr(n, "kind"); + String *type; + + if(Len(tdname)) { + type = Copy(tdname); + } else { + type = NewStringf("%s %s", kind, name); + } + + String *mangledName = SwigType_manglestr(name); + + if (debugMode) + Printf(stderr, "generateCopyRoutines: name = %s, %s\n", name, type); + + Printf(copyToR->def, "CopyToR%s = function(value, obj = new(\"%s\"))\n{\n", + mangledName, name); + Printf(copyToC->def, "CopyToC%s = function(value, obj)\n{\n", + mangledName); + + Node *c = firstChild(n); + + for(; c; c = nextSibling(c)) { + String *elName = Getattr(c, "name"); + if (!Len(elName)) { + continue; + } + String *elKind = Getattr(c, "kind"); + if (Strcmp(elKind, "variable") != 0) { + Delete(elKind); + continue; + } + + String *tp = Swig_typemap_lookup_new("rtype", c, "", 0); + if(!tp) { + continue; + } + if (Strstr(tp, "R_class")) { + continue; + } + if (Strcmp(tp, "character") && + Strstr(Getattr(c, "decl"), "p.")) { + continue; + } + + + /* The S functions to get and set the member value. */ + Printf(copyToR->code, "obj@%s = value$%s\n", elName, elName); + Printf(copyToC->code, "obj$%s = value@%s\n", elName, elName); + } + Printf(copyToR->code, "obj\n}\n\n"); + String *rclassName = getRClassNameCopyStruct(type, 0); // without the Ref. + Printf(sfile, "# Start definition of copy functions & methods for %s\n", rclassName); + + Wrapper_print(copyToR, sfile); + Printf(copyToC->code, "obj\n}\n\n"); + Wrapper_print(copyToC, sfile); + + + Printf(sfile, "# Start definition of copy methods for %s\n", rclassName); + Printf(sfile, "setMethod('copyToR', '_p_%s', CopyToR%s)\n", rclassName, + mangledName); + Printf(sfile, "setMethod('copyToC', '%s', CopyToC%s)\n\n", rclassName, + mangledName); + + Printf(sfile, "# End definition of copy methods for %s\n", rclassName); + Printf(sfile, "# End definition of copy functions & methods for %s\n", rclassName); + + String *m = NewStringf("%sCopyToR", name); + addNamespaceMethod(m); + char *tt = Char(m); tt[Len(m)-1] = 'C'; + addNamespaceMethod(m); + Delete(m); + Delete(rclassName); + Delete(mangledName); + DelWrapper(copyToR); + DelWrapper(copyToC); + + return SWIG_OK; +} + + + +/***** + Called when there is a typedef to be invoked. + + XXX Needs to be enhanced or split to handle the case where we have a + typedef within a classDeclaration emission because the struct/union/etc. + is anonymous. +******/ +int R::typedefHandler(Node *n) { + SwigType *tp = Getattr(n, "type"); + String *type = Getattr(n, "type"); + if (debugMode) + Printf(stderr, " %s\n", Getattr(n, "name")); + + processType(tp, n); + + if(Strncmp(type, "struct ", 7) == 0) { + String *name = Getattr(n, "name"); + char *trueName = Char(type); + trueName += 7; + if (debugMode) + Printf(stderr, " Defining S class %s\n", trueName); + Printf(s_classes, "setClass('_p%s', contains = 'ExternalReference')\n", + SwigType_manglestr(name)); + } + + return Language::typedefHandler(n); +} + + + +/********************* + Called when processing a field in a "class", i.e. struct, union or + actual class. We set a state variable so that we can correctly + interpret the resulting functionWrapper() call and understand that + it is for a field element. +**********************/ +int R::membervariableHandler(Node *n) { + SwigType *t(Getattr(n, "type")); + processType(t, n, NULL); + processing_member_access_function = 1; + member_name = Getattr(n,"sym:name"); + if (debugMode) + Printf(stderr, " name = %s, sym:name = %s\n", + Getattr(n, "name"), member_name); + + int status(Language::membervariableHandler(n)); + + if(opaqueClassDeclaration == NULL && debugMode) + Printf(stderr, " %s %s\n", Getattr(n, "name"), Getattr(n, "type")); + + processing_member_access_function = 0; + member_name = NULL; + + return status; +} + + +/* + This doesn't seem to get used so leave it out for the moment. +*/ +String * R::runtimeCode() { + String *s = Swig_include_sys("rrun.swg"); + if (!s) { + Printf(stderr, "*** Unable to open 'rrun.swg'\n"); + s = NewString(""); + } + return s; +} + + +/** + Called when SWIG wants to initialize this + We initialize anythin we want here. + Most importantly, tell SWIG where to find the files (e.g. r.swg) for this module. + Use Swig_mark_arg() to tell SWIG that it is understood and not to throw an error. +**/ +void R::main(int argc, char *argv[]) { + bool cppcast = true; + init(); + SWIG_library_directory("r"); + SWIG_config_file("r.swg"); + Preprocessor_define("SWIGR 1", 0); + debugMode = false; + copyStruct = true; + memoryProfile = false; + aggressiveGc = false; + inCPlusMode = false; + outputNamespaceInfo = false; + noInitializationCode = false; + + this->argc = argc; + this->argv = argv; + + allow_overloading();// can we support this? + + for(int i = 0; i < argc; i++) { + if(strcmp(argv[i], "-package") == 0) { + Swig_mark_arg(i); + i++; + Swig_mark_arg(i); + Rpackage = argv[i]; + DllName = argv[i]; + } else if(strcmp(argv[i], "-dll") == 0) { + Swig_mark_arg(i); + i++; + Swig_mark_arg(i); + DllName = argv[i]; + } else if(strcmp(argv[i], "-help") == 0) { + showUsage(); + } else if(strcmp(argv[i], "-namespace") == 0) { + outputNamespaceInfo = true; + Swig_mark_arg(i); + } else if(!strcmp(argv[i], "-no-init-code")) { + noInitializationCode = true; + Swig_mark_arg(i); + } else if(!strcmp(argv[i], "-c++")) { + inCPlusMode = true; + Swig_mark_arg(i); + Printf(s_classes, "setClass('C++Reference', contains = 'ExternalReference')\n"); + } else if(!strcmp(argv[i], "-debug")) { + debugMode = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i],"-cppcast")) { + cppcast = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i],"-nocppcast")) { + cppcast = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i],"-copystruct")) { + copyStruct = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-nocopystruct")) { + copyStruct = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-memoryprof")) { + memoryProfile = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-nomemoryprof")) { + memoryProfile = false; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-aggressivegc")) { + aggressiveGc = true; + Swig_mark_arg(i); + } else if (!strcmp(argv[i], "-noaggressivegc")) { + aggressiveGc = false; + Swig_mark_arg(i); + } + + if (cppcast) { + Preprocessor_define((DOH *) "SWIG_CPLUSPLUS_CAST", 0); + } + /// copyToR copyToC functions. + + } +} + +/* + Could make this work for String or File and then just store the resulting string + rather than the collection of arguments and argc. +*/ +int +R::outputCommandLineArguments(File *out) +{ + if(argc < 1 || !argv || !argv[0]) + return(-1); + + Printf(out, "## Generated via the command line invocation:\n##\t"); + for(int i = 0; i < argc ; i++) { + Printf(out, " %s", argv[i]); + } + Printf(out, "\n\n\n"); + + return argc; +} + + + +/* How SWIG instantiates an object from this module. + See swigmain.cxx */ +extern "C" +Language *swig_r(void) +{ + return new R(); +} + + + +/*************************************************************************************/ + +/* + Needs to be reworked. +*/ +String * R::processType(SwigType *t, Node *n, int *nargs) { + //XXX Need to handle typedefs, e.g. + // a type which is a typedef to a function pointer. + + SwigType *tmp = Getattr(n, "tdname"); + if (debugMode) + Printf(stderr, "processType %s (tdname = %s)\n", Getattr(n, "name"), tmp); + + SwigType *td = t; + if (expandTypedef(t) && + SwigType_istypedef(t)) { + SwigType *resolved = + SwigType_typedef_resolve_all(t); + if (expandTypedef(resolved)) { + td = Copy(resolved); + } + } + + if(!td) { + int count = 0; + String *b = getRTypeName(t, &count); + if(count && b && !Getattr(SClassDefs, b)) { + if (debugMode) + Printf(stderr, " Defining class %s\n", b); + + Printf(s_classes, "setClass('%s', contains = 'ExternalReference')\n", b); + Setattr(SClassDefs, b, b); + } + + } + + + if(td) + t = td; + + String *prefix = SwigType_prefix(t); + // String *base = SwigType_base(t); + + if(Strncmp(prefix, "p.f", 3) == 0) { + if (debugMode) + Printf(stderr, + " Defining pointer handler %s\n", t); + + String *tmp = createFunctionPointerHandler(t, n, nargs); + return tmp; + } + +#if 0 + SwigType_isfunction(t) && SwigType_ispointer(t) +#endif + + return NULL; +} + + + + + + + + + +/*************************************************************************************/ + + + + + diff --git a/Source/Modules/swigmain.cxx b/Source/Modules/swigmain.cxx index a5ba0cecc..47f4a46b0 100644 --- a/Source/Modules/swigmain.cxx +++ b/Source/Modules/swigmain.cxx @@ -45,6 +45,7 @@ extern "C" { Language *swig_clisp(void); Language *swig_cffi(void); Language *swig_uffi(void); + Language *swig_r(void); } struct swig_module { @@ -82,6 +83,7 @@ static swig_module modules[] = { {"-tcl8", swig_tcl, 0}, {"-uffi", swig_uffi, "Common Lisp / UFFI"}, {"-xml", swig_xml, "XML"}, + {"-r", swig_r, "R (aka GNU S)"}, {NULL, NULL, NULL} }; diff --git a/configure.in b/configure.in index 14c13d349..0ce8cb7b0 100644 --- a/configure.in +++ b/configure.in @@ -1923,6 +1923,7 @@ AC_CONFIG_FILES([ \ Examples/test-suite/clisp/Makefile \ Examples/test-suite/cffi/Makefile \ Examples/test-suite/uffi/Makefile \ + Examples/test-suite/r/Makefile ]) AC_CONFIG_FILES([preinst-swig], [chmod +x preinst-swig]) AC_OUTPUT