Eric Ehlers
2015-08-20 09:37:40 UTC
Hello,
I have encountered some behavior of SWIG which I do not expect and I
would be grateful if somebody could help me to understand it.
In a nutshell, if I put lines such as this at the top of each of my xxx.i interface files:
%feature("my_feature", "feature_value_aaa");
Then in my parse tree, under the include node for interface file file1.i, I see
the value of the feature from the top of file2.i, even though SWIG has not yet
started parsing file2.i.
Here is a complete and minimal example:
demo.i:
=======
%module demo
%include foo.i
%include bar.i
foo.i:
======
%feature("my_feature", "feature_value_foo");
class Foo {
Foo();
};
bar.i:
=======
%feature("my_feature", "feature_value_bar");
class Bar {
Bar();
};
I run it using the binary release of swigwin-3.0.7, like this:
swig -debug-top 4 -c++ demo.i
Here is the relevant subset of the output, the final part:
+++ include ----------------------------------------
| name - "demo.i"
| module - "demo"
| options - 0xa8cac8
+++ module ----------------------------------------
| name - "demo"
|
+++ include ----------------------------------------
| name - "foo.i"
+++ class ----------------------------------------
| feature:my_feature - "feature_value_foo"
| classtype - "Foo"
| name - "Foo"
| sym:symtab - 0x760498
| symtab - 0xa8cd08
| allows_typedef - "1"
| typepass:visit - "1"
| allocate:visit - "1"
| kind - "class"
| sym:name - "Foo"
| allocate:has_constructor - "1"
| allocate:copy_constructor - "1"
| allocate:default_destructor - "1"
| has_destructor - "1"
| allocate:destructor - "1"
| classtypeobj - "Foo"
| module - 0xa8cb38
| sym:overname - "__SWIG_0"
| typescope - 0xa8d318
+++ constructor ----------------------------------------
| ismember - "1"
| name - "Foo"
| decl - "f()."
| access - "private"
| feature:new - "1"
| feature:my_feature - "feature_value_foo"
| sym:symtab - 0xa8cd08
|
+++ access ----------------------------------------
| kind - "public"
|
+++ access ----------------------------------------
| kind - "public"
|
+++ destructor ----------------------------------------
| feature:my_feature - "feature_value_bar"
| name - "~Foo"
| sym:symtab - 0xa8cd08
| view - "destructorDeclaration"
| sym:name - "~Foo"
| wrap:parms - Foo *self
| decl - "f()."
| tmap:out - ""
| access - "public"
| wrap:action - "delete arg1;"
| wrap:name - "_wrap_delete_Foo"
| tmap:out:noblock - "1"
| sym:overname - "__SWIG_0"
|
+++ include ----------------------------------------
| name - "bar.i"
+++ class ----------------------------------------
| feature:my_feature - "feature_value_bar"
| classtype - "Bar"
| name - "Bar"
| sym:symtab - 0x760498
| symtab - 0xa8cfd8
| allows_typedef - "1"
| typepass:visit - "1"
| allocate:visit - "1"
| kind - "class"
| sym:name - "Bar"
| allocate:has_constructor - "1"
| allocate:copy_constructor - "1"
| allocate:default_destructor - "1"
| has_destructor - "1"
| allocate:destructor - "1"
| classtypeobj - "Bar"
| module - 0xa8cb38
| sym:overname - "__SWIG_0"
| typescope - 0xa8d428
+++ constructor ----------------------------------------
| ismember - "1"
| name - "Bar"
| decl - "f()."
| access - "private"
| feature:new - "1"
| feature:my_feature - "feature_value_bar"
| sym:symtab - 0xa8cfd8
|
+++ access ----------------------------------------
| kind - "public"
|
+++ access ----------------------------------------
| kind - "public"
|
+++ destructor ----------------------------------------
| feature:my_feature - "feature_value_bar"
| name - "~Bar"
| sym:symtab - 0xa8cfd8
| view - "destructorDeclaration"
| sym:name - "~Bar"
| wrap:parms - Bar *self
| decl - "f()."
| tmap:out - ""
| access - "public"
| wrap:action - "delete arg1;"
| wrap:name - "_wrap_delete_Bar"
| tmap:out:noblock - "1"
| sym:overname - "__SWIG_0"
|
You can see that the node for ~Foo has the property
"feature_value_bar", where I would expect (or want) it to have the
property "feature_value_foo", since at that point I have not yet even
hit file bar.i where "feature_value_bar" is defined.
What am I doing wrong?
I have found that if I put this at the bottom of every xxx.i file...
%feature("my_feature", "");
...then in the example above the ~Foo node does not contain the
feature at all which is an improvement but still not ideal for my
situation.
More generally, what I really want is to be able to set some parameters
at the top of each of my xxx.i files, and then to write some code which
extracts those parameters within my class:
class MY_CLASS : public Language { /* ... */ }
I don't really care whether I use %feature or something else, I just
want to extract some text every time I hit a new xxx.i file. So far I
can not figure out where in MY_CLASS to do this. Underneath a given
include node, it is impossible for me to know which will be the first
sub-node to contain the feature, it might be a namespace, function,
constructor, etc., it varies depending on what C++ code the user
chooses to put into the xxx.i file. So far the only solution that I
have found is to override all of the relevant member functions of
Language and to check for the feature in all of them e.g.
namespaceDeclaration()
functionHandler()
constructorDeclaration()
etc.
Is there a way that I can enter arbitrary text at the top of the xxx.i
file and have it attached to the corresponding include node? Then I
could always extract it within includeDirective().
I would be grateful for some help!
Kind Regards,
Eric Ehlers
------------------------------------------------------------------------------
I have encountered some behavior of SWIG which I do not expect and I
would be grateful if somebody could help me to understand it.
In a nutshell, if I put lines such as this at the top of each of my xxx.i interface files:
%feature("my_feature", "feature_value_aaa");
Then in my parse tree, under the include node for interface file file1.i, I see
the value of the feature from the top of file2.i, even though SWIG has not yet
started parsing file2.i.
Here is a complete and minimal example:
demo.i:
=======
%module demo
%include foo.i
%include bar.i
foo.i:
======
%feature("my_feature", "feature_value_foo");
class Foo {
Foo();
};
bar.i:
=======
%feature("my_feature", "feature_value_bar");
class Bar {
Bar();
};
I run it using the binary release of swigwin-3.0.7, like this:
swig -debug-top 4 -c++ demo.i
Here is the relevant subset of the output, the final part:
+++ include ----------------------------------------
| name - "demo.i"
| module - "demo"
| options - 0xa8cac8
+++ module ----------------------------------------
| name - "demo"
|
+++ include ----------------------------------------
| name - "foo.i"
+++ class ----------------------------------------
| feature:my_feature - "feature_value_foo"
| classtype - "Foo"
| name - "Foo"
| sym:symtab - 0x760498
| symtab - 0xa8cd08
| allows_typedef - "1"
| typepass:visit - "1"
| allocate:visit - "1"
| kind - "class"
| sym:name - "Foo"
| allocate:has_constructor - "1"
| allocate:copy_constructor - "1"
| allocate:default_destructor - "1"
| has_destructor - "1"
| allocate:destructor - "1"
| classtypeobj - "Foo"
| module - 0xa8cb38
| sym:overname - "__SWIG_0"
| typescope - 0xa8d318
+++ constructor ----------------------------------------
| ismember - "1"
| name - "Foo"
| decl - "f()."
| access - "private"
| feature:new - "1"
| feature:my_feature - "feature_value_foo"
| sym:symtab - 0xa8cd08
|
+++ access ----------------------------------------
| kind - "public"
|
+++ access ----------------------------------------
| kind - "public"
|
+++ destructor ----------------------------------------
| feature:my_feature - "feature_value_bar"
| name - "~Foo"
| sym:symtab - 0xa8cd08
| view - "destructorDeclaration"
| sym:name - "~Foo"
| wrap:parms - Foo *self
| decl - "f()."
| tmap:out - ""
| access - "public"
| wrap:action - "delete arg1;"
| wrap:name - "_wrap_delete_Foo"
| tmap:out:noblock - "1"
| sym:overname - "__SWIG_0"
|
+++ include ----------------------------------------
| name - "bar.i"
+++ class ----------------------------------------
| feature:my_feature - "feature_value_bar"
| classtype - "Bar"
| name - "Bar"
| sym:symtab - 0x760498
| symtab - 0xa8cfd8
| allows_typedef - "1"
| typepass:visit - "1"
| allocate:visit - "1"
| kind - "class"
| sym:name - "Bar"
| allocate:has_constructor - "1"
| allocate:copy_constructor - "1"
| allocate:default_destructor - "1"
| has_destructor - "1"
| allocate:destructor - "1"
| classtypeobj - "Bar"
| module - 0xa8cb38
| sym:overname - "__SWIG_0"
| typescope - 0xa8d428
+++ constructor ----------------------------------------
| ismember - "1"
| name - "Bar"
| decl - "f()."
| access - "private"
| feature:new - "1"
| feature:my_feature - "feature_value_bar"
| sym:symtab - 0xa8cfd8
|
+++ access ----------------------------------------
| kind - "public"
|
+++ access ----------------------------------------
| kind - "public"
|
+++ destructor ----------------------------------------
| feature:my_feature - "feature_value_bar"
| name - "~Bar"
| sym:symtab - 0xa8cfd8
| view - "destructorDeclaration"
| sym:name - "~Bar"
| wrap:parms - Bar *self
| decl - "f()."
| tmap:out - ""
| access - "public"
| wrap:action - "delete arg1;"
| wrap:name - "_wrap_delete_Bar"
| tmap:out:noblock - "1"
| sym:overname - "__SWIG_0"
|
You can see that the node for ~Foo has the property
"feature_value_bar", where I would expect (or want) it to have the
property "feature_value_foo", since at that point I have not yet even
hit file bar.i where "feature_value_bar" is defined.
What am I doing wrong?
I have found that if I put this at the bottom of every xxx.i file...
%feature("my_feature", "");
...then in the example above the ~Foo node does not contain the
feature at all which is an improvement but still not ideal for my
situation.
More generally, what I really want is to be able to set some parameters
at the top of each of my xxx.i files, and then to write some code which
extracts those parameters within my class:
class MY_CLASS : public Language { /* ... */ }
I don't really care whether I use %feature or something else, I just
want to extract some text every time I hit a new xxx.i file. So far I
can not figure out where in MY_CLASS to do this. Underneath a given
include node, it is impossible for me to know which will be the first
sub-node to contain the feature, it might be a namespace, function,
constructor, etc., it varies depending on what C++ code the user
chooses to put into the xxx.i file. So far the only solution that I
have found is to override all of the relevant member functions of
Language and to check for the feature in all of them e.g.
namespaceDeclaration()
functionHandler()
constructorDeclaration()
etc.
Is there a way that I can enter arbitrary text at the top of the xxx.i
file and have it attached to the corresponding include node? Then I
could always extract it within includeDirective().
I would be grateful for some help!
Kind Regards,
Eric Ehlers
------------------------------------------------------------------------------