diff options
author | William S Fulton <wsf@fultondesigns.co.uk> | 2013-12-14 15:12:07 +0000 |
---|---|---|
committer | William S Fulton <wsf@fultondesigns.co.uk> | 2013-12-14 15:12:07 +0000 |
commit | 314fae460b83389b87a83e003bfbc28271c495c1 (patch) | |
tree | aae5d33c0dd3bb4268a2c273716578350f66b36b | |
parent | 4cf5de797f15fa0c2a500cea12db7c9223f07fdc (diff) | |
parent | 0f4ceaf5923fd9a30eb9201048cd285a9bba8084 (diff) | |
download | swig-314fae460b83389b87a83e003bfbc28271c495c1.tar.gz |
Merge branch 'nested' - nested structs/classes support
* nested:
Deprecation of the 'nestedworkaround' feature
Ensure -c++out is not used with -c++
Add missing header to new source file
Nested C class setters restored in c++out mode for Octave
Classprefix fixed after private nested classes some comments and spaces added
Fix template partial specialization detection
Minor tweaks in Swig_feature_set
Swig_offset_string moved to misc.c
nested private classes are discarded while parsing nested relate functions are moved to nested.cxx and renamed accordingly
out-of-scope template definitions fixed nested_private test disabled again
fixed out-of-scope nested class definitions, added a test enabled nested C structs assignment (still disabled for Octave), added Java runtime test fixed nested_private test case for Java & C#
Testcase of private nested class usage causing segfault
C nested struct passed by value example
Add in Travis testing for nested branch
Add C++ nested class example
Minor code improvements
Cosmetics/code beautification of nested class support
Nested classes support
61 files changed, 2435 insertions, 1124 deletions
diff --git a/.travis.yml b/.travis.yml index 70cbb2f27..7f868ae91 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,3 +57,4 @@ script: branches: only: - master + - nested diff --git a/Doc/Manual/SWIGPlus.html b/Doc/Manual/SWIGPlus.html index 2ed450c01..3c3c7d564 100644 --- a/Doc/Manual/SWIGPlus.html +++ b/Doc/Manual/SWIGPlus.html @@ -185,7 +185,6 @@ The following C++ features are not currently supported:</p> <ul> <li>Overloaded versions of certain operators (new, delete, etc.) -<li>Nested classes, see <a href="#SWIGPlus_nested_classes">Nested classes</a> for workarounds. </ul> <p> @@ -4965,143 +4964,56 @@ public: <H2><a name="SWIGPlus_nested_classes"></a>6.27 Nested classes</H2> - -<p> -There is some support for nested structs and unions when wrapping C code, -see <a href="SWIG.html#SWIG_nested_structs">Nested structures</a> for further details. -The added complexity of C++ compared to C means this approach does not work well for -C++ code (when using the -c++ command line option). -For C++, a nested class is treated much like an opaque pointer, so anything useful within the nested class, such as its -methods and variables, are not accessible from the target language. -True nested class support may be added to SWIG in the future, however, -until then some of the following workarounds can be applied to improve the situation. -</p> - -<p> -It might be possible to use partial class information as often you can accept that the nested class is not needed, -especially if it is not actually used in any methods you need from the target language. -Imagine you are wrapping the following <tt>Outer</tt> class which contains a nested class <tt>Inner</tt>. -The easiest thing to do is turn a blind eye to the warning that SWIG generates, or simply suppress it: -</p> - -<div class="code"> -<pre> -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::Inner; - -class Outer { -public: - class Inner { - public: - ... - }; - Inner getInner(); - void useInner(const Inner& inner); - ... -}; -</pre> -</div> - <p> -Note that if <tt>Inner</tt> can be used as an opaque type, the default wrapping approach suffices. -For example, if the nested class does not need to be created from the target language, but can be obtained via a method -call, such as the <tt>getInner()</tt> method above, the returned value can then be passed around, such as passed into the -<tt>useInner()</tt> method. +If the target language supports the nested classes concept (like Java), the nested C++ classes +are wrapped as nested target language proxy classes. (In case of Java - "static" nested classes.) +Only public nested classes are wrapped. Otherwise there is little difference between nested and +normal classes. </p> - -<p> -With some more effort the above situation can be improved somewhat and a nested class can be constructed and used -from the target language much like any other non-nested class. Assuming we have the <tt>Outer</tt> class in a header file: -</p> - -<div class="code"> -<pre> -// File outer.h -class Outer { -public: - class Inner { - public: - int var; - Inner(int v = 0) : var(v) {} - }; - Inner getInner(); - void useInner(const Inner& inner); -}; -</pre> -</div> - <p> -The following interface file works around the nested class limitations by redefining the nested class as a global class. -A typedef for the compiler and the <tt>nestedworkaround</tt> -<a href="Customization.html#Customization_feature_flags">feature flag</a> is also required in -order for the generated wrappers to compile. This flag simply removes all the type information from SWIG, so SWIG treats -the nested class as if it had not been parsed at all. +If the target language doesn't support nested classes directly, or the support is not implemented in the +language module (like for python currently), then the visible nested classes are moved to the same name +space as the containing class (nesting hierarchy is "flattened"). The same behaviour may be turned on for +C# and Java by the %feature ("flatnested"); If there is a class with the same name in the outer namespace +the inner class (or the global one) may be renamed or ignored: </p> <div class="code"> <pre> -// File : example.i -%module example - -// Redefine nested class in global scope in order for SWIG to generate -// a proxy class. Only SWIG parses this definition. -class Inner { +%rename (Bar_Foo) Bar::Foo; +class Foo {}; +class Bar { public: - int var; - Inner(int v = 0) : var(v) {} + class Foo {}; }; - -%nestedworkaround Outer::Inner; - -%{ -#include "outer.h" -%} -%include "outer.h" - -// We've fooled SWIG into thinking that Inner is a global class, so now we need -// to trick the C++ compiler into understanding this apparent global type. -%{ -typedef Outer::Inner Inner; -%} </pre> </div> -<p> -The downside to this approach is a more complex interface file and having to maintain two definitions of <tt>Inner</tt>, -the real one and the one in the interface file that SWIG parses. -However, the upside is that all the methods/variables in the nested class are available from the target language -as a proxy class is generated instead of treating the nested class as an opaque type. -The proxy class can be constructed from the target language and passed into any methods accepting the nested class. -Also note that the original header file is parsed unmodified. -</p> <p> -Finally, conditional compilation can be used as a workaround to comment out nested class definitions in the actual headers, -assuming you are able to modify them. +<b>Compatibility Note:</b> +Prior to SWIG-3.0.0, there was limited nested class support. Nested classes were treated as opaque pointers. +However, there was a workaround for nested class support in these older versions requiring the user to replicate +the nested class in the global scope, adding in a typedef for the nested class in the global scope and +using the "nestedworkaround" feature on the nested class. This resulted in approximately the +same behaviour as the "flatnested" feature. With proper nested class support now available in SWIG-3.0.0, this +feature has been deprecated and no longer works requiring code changes. If you see the following warning: </p> -<div class="code"> +<div class="shell"> <pre> -// File outer.h -class Outer { -public: -#ifndef SWIG - class Inner { - public: - ... - }; -#endif - ... -}; +example.i:8: Warning 126: The nestedworkaround feature is deprecated </pre> </div> <p> -This workaround used to be common when SWIG could not deal with nested classes particulary well. -This should just be a last resort for unusual corner cases now as SWIG can parse nested classes and even handle nested template classes fairly well. +consider using the "flatnested" feature discussed above which generates a non-nested proxy class, like the +"nestedworkaround" feature did. Alternatively, use the default nested class code generation, which may generate an +equivalent to a nested proxy class in the target language, depending on the target language support. </p> <p> -<b>Compatibility Note:</b> SWIG-1.3.40 and earlier versions did not have the <tt>nestedworkaround</tt> feature +SWIG-1.3.40 and earlier versions did not have the <tt>nestedworkaround</tt> feature and the generated code resulting from parsing nested classes did not always compile. Nested class warnings could also not be suppressed using %warnfilter. </p> diff --git a/Doc/Manual/Warnings.html b/Doc/Manual/Warnings.html index e0debe41c..b4d27872c 100644 --- a/Doc/Manual/Warnings.html +++ b/Doc/Manual/Warnings.html @@ -382,6 +382,7 @@ example.i(4) : Syntax error in input. <li>119. Deprecated <tt>%typemap(ignore)</tt>. <li>120. Deprecated command line option (-runtime, -noruntime). <li>121. Deprecated <tt>%name</tt> directive. +<li>126. The 'nestedworkaround' feature is deprecated. </ul> <H3><a name="Warnings_nn11"></a>14.9.2 Preprocessor (200-299)</H3> diff --git a/Examples/csharp/check.list b/Examples/csharp/check.list index 5454d8531..a530a4b42 100644 --- a/Examples/csharp/check.list +++ b/Examples/csharp/check.list @@ -5,6 +5,7 @@ class enum extend funcptr +nested reference simple template diff --git a/Examples/csharp/nested/Makefile b/Examples/csharp/nested/Makefile new file mode 100644 index 000000000..bc3ce8ce8 --- /dev/null +++ b/Examples/csharp/nested/Makefile @@ -0,0 +1,19 @@ +TOP = ../.. +SWIG = $(TOP)/../preinst-swig +CXXSRCS = example.cxx +TARGET = example +INTERFACE = example.i +SWIGOPT = +CSHARPSRCS = *.cs +CSHARPFLAGS= -nologo -out:runme.exe + +check: build + $(MAKE) -f $(TOP)/Makefile csharp_run + +build: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' csharp_cpp + $(MAKE) -f $(TOP)/Makefile CSHARPSRCS='$(CSHARPSRCS)' CSHARPFLAGS='$(CSHARPFLAGS)' csharp_compile + +clean: + $(MAKE) -f $(TOP)/Makefile csharp_clean diff --git a/Examples/csharp/nested/example-cs.csproj b/Examples/csharp/nested/example-cs.csproj new file mode 100644 index 000000000..8004780fb --- /dev/null +++ b/Examples/csharp/nested/example-cs.csproj @@ -0,0 +1,94 @@ +<VisualStudioProject>
+ <CSHARP
+ ProjectType = "Local"
+ ProductVersion = "7.10.3077"
+ SchemaVersion = "2.0"
+ ProjectGuid = "{C17D27DF-4C57-4625-AEE0-A40C4F48FF1A}"
+ >
+ <Build>
+ <Settings
+ ApplicationIcon = ""
+ AssemblyKeyContainerName = ""
+ AssemblyName = "runme"
+ AssemblyOriginatorKeyFile = ""
+ DefaultClientScript = "JScript"
+ DefaultHTMLPageLayout = "Grid"
+ DefaultTargetSchema = "IE50"
+ DelaySign = "false"
+ OutputType = "Exe"
+ PreBuildEvent = ""
+ PostBuildEvent = ""
+ RootNamespace = "runme"
+ RunPostBuildEvent = "OnBuildSuccess"
+ StartupObject = ""
+ >
+ <Config
+ Name = "Debug"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "DEBUG;TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "true"
+ FileAlignment = "4096"
+ IncrementalBuild = "false"
+ NoStdLib = "false"
+ NoWarn = ""
+ Optimize = "false"
+ OutputPath = ".\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ <Config
+ Name = "Release"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "false"
+ FileAlignment = "4096"
+ IncrementalBuild = "false"
+ NoStdLib = "false"
+ NoWarn = ""
+ Optimize = "true"
+ OutputPath = ".\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ </Settings>
+ <References/>
+ </Build>
+ <Files>
+ <Include>
+ <File
+ RelPath = "example.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "examplePINVOKE.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "MotorCar.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "runme.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ </Include>
+ </Files>
+ </CSHARP>
+</VisualStudioProject>
+
diff --git a/Examples/csharp/nested/example-vc.vcproj b/Examples/csharp/nested/example-vc.vcproj new file mode 100644 index 000000000..5788bc9c7 --- /dev/null +++ b/Examples/csharp/nested/example-vc.vcproj @@ -0,0 +1,158 @@ +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="example"
+ ProjectGUID="{C2302635-D489-4678-96B4-70F5309DCBE6}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="2"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;EXAMPLEVC_EXPORTS"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="example.dll"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/example.pdb"
+ SubSystem="2"
+ ImportLibrary="$(OutDir)/example.lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="2"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;EXAMPLEVC_EXPORTS"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="example.dll"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ImportLibrary="$(OutDir)/example.lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="example.cxx">
+ </File>
+ <File
+ RelativePath="example_wrap.cxx">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="example.h">
+ </File>
+ </Filter>
+ <File
+ RelativePath=".\example.i">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="echo Invoking SWIG...
+echo on
+..\..\..\swig.exe -c++ -csharp "$(InputPath)"
+@echo off"
+ Outputs="$(InputName)_wrap.cxx"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="echo Invoking SWIG...
+echo on
+..\..\..\swig.exe -c++ -csharp "$(InputPath)"
+@echo off"
+ Outputs="$(InputName)_wrap.cxx"/>
+ </FileConfiguration>
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Examples/csharp/nested/example.cxx b/Examples/csharp/nested/example.cxx new file mode 100644 index 000000000..03bb74d9e --- /dev/null +++ b/Examples/csharp/nested/example.cxx @@ -0,0 +1,62 @@ +#include "example.h" + +int MotorCar::DesignOpinion::AceDesignCount = 0; +int MotorCar::DesignOpinion::TotalDesignCount = 0; + +int MotorCar::DesignOpinion::PercentScore() { + return AceDesignCount*100/TotalDesignCount; +} + +MotorCar::Wheels::Wheels(Shape shape, size_t count) : shape(shape), count(count) {} + +MotorCar::WindScreen::WindScreen(bool opaque) : opaque(opaque) {} + +MotorCar::MotorCar(const std::string &name, const Wheels &wheels, const WindScreen &windscreen) : name(name), wheels(wheels), windscreen(windscreen) {} + +MotorCar MotorCar::DesignFromComponents(const std::string &name, const Wheels &wheels, const WindScreen &windscreen) { + MotorCar car = MotorCar(name, wheels, windscreen); + DesignOpinion::TotalDesignCount++; + if (car.wheels.Opinion().itrocks && car.windscreen.Opinion().itrocks) + DesignOpinion::AceDesignCount++; + return car; +} + +MotorCar::DesignOpinion MotorCar::Wheels::Opinion() { + DesignOpinion opinion; + opinion.itrocks = true; + if (shape == Square) { + opinion.itrocks = false; + opinion.reason = "you'll have a few issues with wheel rotation"; + } + if (count <= 2) { + opinion.reason += opinion.itrocks ? "" : " and "; + opinion.itrocks = false; + opinion.reason += "a few more wheels are needed for stability"; + } + if (opinion.itrocks) + opinion.reason = "your choice of wheels was top notch"; + + return opinion; +} + +MotorCar::DesignOpinion MotorCar::WindScreen::Opinion() { + DesignOpinion opinion; + opinion.itrocks = !opaque; + opinion.reason = opinion.itrocks ? "the driver will have a commanding view out the window" : "you can't see out the windscreen"; + return opinion; +} + +std::string MotorCar::WillItWork() { + DesignOpinion wh = wheels.Opinion(); + DesignOpinion ws = windscreen.Opinion(); + std::string willit; + if (wh.itrocks && ws.itrocks) { + willit = "Great car design because " + wh.reason + " and " + ws.reason; + } else { + willit = "You need a rethink because "; + willit += wh.itrocks ? "" : wh.reason; + willit += (!wh.itrocks && !ws.itrocks) ? " and " : ""; + willit += ws.itrocks ? "" : ws.reason; + } + return willit; +} diff --git a/Examples/csharp/nested/example.h b/Examples/csharp/nested/example.h new file mode 100644 index 000000000..4fb107cb5 --- /dev/null +++ b/Examples/csharp/nested/example.h @@ -0,0 +1,48 @@ +#include <string> + +/** Design a motor car from various components */ +struct MotorCar { + + /** Information about an opinion of the design of a car component */ + struct DesignOpinion { + bool itrocks; + std::string reason; + static int AceDesignCount; + static int TotalDesignCount; + static int PercentScore(); + }; + + /** Wheels component */ + struct Wheels { + enum Shape { Round, Square }; + Wheels(Shape shape, size_t count); + DesignOpinion Opinion(); + private: + Shape shape; + size_t count; + }; + + /** Windscreen component */ + struct WindScreen { + WindScreen(bool opaque); + DesignOpinion Opinion(); + private: + bool opaque; + }; + + /** Factory method for creating a car */ + static MotorCar DesignFromComponents(const std::string &name, const Wheels &wheels, const WindScreen &windscreen); + + std::string Name() { + return name; + } + + /** Get an overall opinion on the car design */ + std::string WillItWork(); + +private: + MotorCar(const std::string &name, const Wheels &wheels, const WindScreen &windscreen); + std::string name; + Wheels wheels; + WindScreen windscreen; +}; diff --git a/Examples/csharp/nested/example.i b/Examples/csharp/nested/example.i new file mode 100644 index 000000000..c07c1521a --- /dev/null +++ b/Examples/csharp/nested/example.i @@ -0,0 +1,13 @@ +%module example + +// This example shows how wrappers for numerous aspects of C++ nested classes work: +// Nested static and instance variables and methods and nested enums + +%include <std_string.i> + +%{ +#include "example.h" +%} + +%include "example.h" + diff --git a/Examples/csharp/nested/example.sln b/Examples/csharp/nested/example.sln new file mode 100644 index 000000000..88995ffd3 --- /dev/null +++ b/Examples/csharp/nested/example.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example-cs", "example-cs.csproj", "{C17D27DF-4C57-4625-AEE0-A40C4F48FF1A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {C2302635-D489-4678-96B4-70F5309DCBE6} = {C2302635-D489-4678-96B4-70F5309DCBE6}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example-vc", "example-vc.vcproj", "{C2302635-D489-4678-96B4-70F5309DCBE6}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {C17D27DF-4C57-4625-AEE0-A40C4F48FF1A}.Debug.ActiveCfg = Debug|.NET
+ {C17D27DF-4C57-4625-AEE0-A40C4F48FF1A}.Debug.Build.0 = Debug|.NET
+ {C17D27DF-4C57-4625-AEE0-A40C4F48FF1A}.Release.ActiveCfg = Release|.NET
+ {C17D27DF-4C57-4625-AEE0-A40C4F48FF1A}.Release.Build.0 = Release|.NET
+ {C2302635-D489-4678-96B4-70F5309DCBE6}.Debug.ActiveCfg = Debug|Win32
+ {C2302635-D489-4678-96B4-70F5309DCBE6}.Debug.Build.0 = Debug|Win32
+ {C2302635-D489-4678-96B4-70F5309DCBE6}.Release.ActiveCfg = Release|Win32
+ {C2302635-D489-4678-96B4-70F5309DCBE6}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/Examples/csharp/nested/runme.cs b/Examples/csharp/nested/runme.cs new file mode 100644 index 000000000..facaefdb7 --- /dev/null +++ b/Examples/csharp/nested/runme.cs @@ -0,0 +1,27 @@ +// This example illustrates how C++ classes can be used from C# using SWIG. +// The C# class gets mapped onto the C++ class and behaves as if it is a C# class. + +using System; + +public class runme +{ + static void Main() + { + MotorCar car1 = MotorCar.DesignFromComponents("Bumpy", new MotorCar.Wheels(MotorCar.Wheels.Shape.Square, 4), new MotorCar.WindScreen(false)); + MotorCar car2 = MotorCar.DesignFromComponents("Wobbly", new MotorCar.Wheels(MotorCar.Wheels.Shape.Round, 2), new MotorCar.WindScreen(false)); + MotorCar car3 = MotorCar.DesignFromComponents("Batty", new MotorCar.Wheels(MotorCar.Wheels.Shape.Round, 4), new MotorCar.WindScreen(true)); + MotorCar car4 = MotorCar.DesignFromComponents("Spiffing", new MotorCar.Wheels(MotorCar.Wheels.Shape.Round, 4), new MotorCar.WindScreen(false)); + + Console.WriteLine("Expert opinion on " + car1.Name() + " : \n " + car1.WillItWork()); + Console.WriteLine("Expert opinion on " + car2.Name() + " : \n " + car2.WillItWork()); + Console.WriteLine("Expert opinion on " + car3.Name() + " : \n " + car3.WillItWork()); + Console.WriteLine("Expert opinion on " + car4.Name() + " : \n " + car4.WillItWork()); + + int count = MotorCar.DesignOpinion.AceDesignCount; + int total = MotorCar.DesignOpinion.TotalDesignCount; + int percent = MotorCar.DesignOpinion.PercentScore(); + Console.WriteLine("Overall opinion rating on car design is " + count + "/" + total + " = " + percent + "%"); + + Console.WriteLine("Single square wheel thoughts: " + new MotorCar.Wheels(MotorCar.Wheels.Shape.Square, 1).Opinion().reason); + } +} diff --git a/Examples/java/check.list b/Examples/java/check.list index 9728342f2..825d04a6d 100644 --- a/Examples/java/check.list +++ b/Examples/java/check.list @@ -7,6 +7,7 @@ extend funcptr multimap native +nested pointer reference simple diff --git a/Examples/java/nested/Makefile b/Examples/java/nested/Makefile new file mode 100644 index 000000000..8f274e7cb --- /dev/null +++ b/Examples/java/nested/Makefile @@ -0,0 +1,18 @@ +TOP = ../.. +SWIG = $(TOP)/../preinst-swig +CXXSRCS = example.cxx +TARGET = example +INTERFACE = example.i +SWIGOPT = +JAVASRCS = *.java + +check: build + $(MAKE) -f $(TOP)/Makefile java_run + +build: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' java_cpp + $(MAKE) -f $(TOP)/Makefile JAVASRCS='$(JAVASRCS)' JAVAFLAGS='$(JAVAFLAGS)' java_compile + +clean: + $(MAKE) -f $(TOP)/Makefile java_clean diff --git a/Examples/java/nested/example.cxx b/Examples/java/nested/example.cxx new file mode 100644 index 000000000..03bb74d9e --- /dev/null +++ b/Examples/java/nested/example.cxx @@ -0,0 +1,62 @@ +#include "example.h" + +int MotorCar::DesignOpinion::AceDesignCount = 0; +int MotorCar::DesignOpinion::TotalDesignCount = 0; + +int MotorCar::DesignOpinion::PercentScore() { + return AceDesignCount*100/TotalDesignCount; +} + +MotorCar::Wheels::Wheels(Shape shape, size_t count) : shape(shape), count(count) {} + +MotorCar::WindScreen::WindScreen(bool opaque) : opaque(opaque) {} + +MotorCar::MotorCar(const std::string &name, const Wheels &wheels, const WindScreen &windscreen) : name(name), wheels(wheels), windscreen(windscreen) {} + +MotorCar MotorCar::DesignFromComponents(const std::string &name, const Wheels &wheels, const WindScreen &windscreen) { + MotorCar car = MotorCar(name, wheels, windscreen); + DesignOpinion::TotalDesignCount++; + if (car.wheels.Opinion().itrocks && car.windscreen.Opinion().itrocks) + DesignOpinion::AceDesignCount++; + return car; +} + +MotorCar::DesignOpinion MotorCar::Wheels::Opinion() { + DesignOpinion opinion; + opinion.itrocks = true; + if (shape == Square) { + opinion.itrocks = false; + opinion.reason = "you'll have a few issues with wheel rotation"; + } + if (count <= 2) { + opinion.reason += opinion.itrocks ? "" : " and "; + opinion.itrocks = false; + opinion.reason += "a few more wheels are needed for stability"; + } + if (opinion.itrocks) + opinion.reason = "your choice of wheels was top notch"; + + return opinion; +} + +MotorCar::DesignOpinion MotorCar::WindScreen::Opinion() { + DesignOpinion opinion; + opinion.itrocks = !opaque; + opinion.reason = opinion.itrocks ? "the driver will have a commanding view out the window" : "you can't see out the windscreen"; + return opinion; +} + +std::string MotorCar::WillItWork() { + DesignOpinion wh = wheels.Opinion(); + DesignOpinion ws = windscreen.Opinion(); + std::string willit; + if (wh.itrocks && ws.itrocks) { + willit = "Great car design because " + wh.reason + " and " + ws.reason; + } else { + willit = "You need a rethink because "; + willit += wh.itrocks ? "" : wh.reason; + willit += (!wh.itrocks && !ws.itrocks) ? " and " : ""; + willit += ws.itrocks ? "" : ws.reason; + } + return willit; +} diff --git a/Examples/java/nested/example.dsp b/Examples/java/nested/example.dsp new file mode 100644 index 000000000..f52544b95 --- /dev/null +++ b/Examples/java/nested/example.dsp @@ -0,0 +1,162 @@ +# Microsoft Developer Studio Project File - Name="example" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=example - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "example.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "example.mak" CFG="example - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "example - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "example - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "example - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "$(JAVA_INCLUDE)" /I "$(JAVA_INCLUDE)\win32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE_EXPORTS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /dll /debug /machine:I386 /out:"example.dll" /pdbtype:sept
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Java compile post-build step
+PostBuild_Cmds=echo on "%JAVA_BIN%\javac" *.java
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "example - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "$(JAVA_INCLUDE)" /I "$(JAVA_INCLUDE)\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXAMPLE_EXPORTS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /dll /machine:I386 /out:"example.dll"
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Desc=Java compile post-build step
+PostBuild_Cmds=echo on "%JAVA_BIN%\javac" *.java
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "example - Win32 Debug"
+# Name "example - Win32 Release"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\example.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\example_wrap.cxx
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\example.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Source File
+
+SOURCE=.\example.i
+
+!IF "$(CFG)" == "example - Win32 Debug"
+
+# Begin Custom Build
+InputPath=.\example.i
+InputName=example
+
+"$(InputName)_wrap.cxx" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ echo In order to function correctly, please ensure the following environment variables are correctly set:
+ echo JAVA_INCLUDE: %JAVA_INCLUDE%
+ echo JAVA_BIN: %JAVA_BIN%
+ echo on
+ ..\..\..\swig.exe -c++ -java "$(InputPath)"
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "example - Win32 Release"
+
+# Begin Custom Build
+InputPath=.\example.i
+InputName=example
+
+"$(InputName)_wrap.cxx" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ echo In order to function correctly, please ensure the following environment variables are correctly set:
+ echo JAVA_INCLUDE: %JAVA_INCLUDE%
+ echo JAVA_BIN: %JAVA_BIN%
+ echo on
+ ..\..\..\swig.exe -c++ -java "$(InputPath)"
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/Examples/java/nested/example.h b/Examples/java/nested/example.h new file mode 100644 index 000000000..4fb107cb5 --- /dev/null +++ b/Examples/java/nested/example.h @@ -0,0 +1,48 @@ +#include <string> + +/** Design a motor car from various components */ +struct MotorCar { + + /** Information about an opinion of the design of a car component */ + struct DesignOpinion { + bool itrocks; + std::string reason; + static int AceDesignCount; + static int TotalDesignCount; + static int PercentScore(); + }; + + /** Wheels component */ + struct Wheels { + enum Shape { Round, Square }; + Wheels(Shape shape, size_t count); + DesignOpinion Opinion(); + private: + Shape shape; + size_t count; + }; + + /** Windscreen component */ + struct WindScreen { + WindScreen(bool opaque); + DesignOpinion Opinion(); + private: + bool opaque; + }; + + /** Factory method for creating a car */ + static MotorCar DesignFromComponents(const std::string &name, const Wheels &wheels, const WindScreen &windscreen); + + std::string Name() { + return name; + } + + /** Get an overall opinion on the car design */ + std::string WillItWork(); + +private: + MotorCar(const std::string &name, const Wheels &wheels, const WindScreen &windscreen); + std::string name; + Wheels wheels; + WindScreen windscreen; +}; diff --git a/Examples/java/nested/example.i b/Examples/java/nested/example.i new file mode 100644 index 000000000..c07c1521a --- /dev/null +++ b/Examples/java/nested/example.i @@ -0,0 +1,13 @@ +%module example + +// This example shows how wrappers for numerous aspects of C++ nested classes work: +// Nested static and instance variables and methods and nested enums + +%include <std_string.i> + +%{ +#include "example.h" +%} + +%include "example.h" + diff --git a/Examples/java/nested/runme.java b/Examples/java/nested/runme.java new file mode 100644 index 000000000..855dbea91 --- /dev/null +++ b/Examples/java/nested/runme.java @@ -0,0 +1,32 @@ +// This example illustrates wrapping of nested C++ classes + +public class runme { + static { + try { + System.loadLibrary("example"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + public static void main(String argv[]) + { + MotorCar car1 = MotorCar.DesignFromComponents("Bumpy", new MotorCar.Wheels(MotorCar.Wheels.Shape.Square, 4), new MotorCar.WindScreen(false)); + MotorCar car2 = MotorCar.DesignFromComponents("Wobbly", new MotorCar.Wheels(MotorCar.Wheels.Shape.Round, 2), new MotorCar.WindScreen(false)); + MotorCar car3 = MotorCar.DesignFromComponents("Batty", new MotorCar.Wheels(MotorCar.Wheels.Shape.Round, 4), new MotorCar.WindScreen(true)); + MotorCar car4 = MotorCar.DesignFromComponents("Spiffing", new MotorCar.Wheels(MotorCar.Wheels.Shape.Round, 4), new MotorCar.WindScreen(false)); + + System.out.println("Expert opinion on " + car1.Name() + " : \n " + car1.WillItWork()); + System.out.println("Expert opinion on " + car2.Name() + " : \n " + car2.WillItWork()); + System.out.println("Expert opinion on " + car3.Name() + " : \n " + car3.WillItWork()); + System.out.println("Expert opinion on " + car4.Name() + " : \n " + car4.WillItWork()); + + int count = MotorCar.DesignOpinion.getAceDesignCount(); + int total = MotorCar.DesignOpinion.getTotalDesignCount(); + int percent = MotorCar.DesignOpinion.PercentScore(); + System.out.println("Overall opinion rating on car design is " + count + "/" + total + " = " + percent + "%"); + + System.out.println("Single square wheel thoughts: " + new MotorCar.Wheels(MotorCar.Wheels.Shape.Square, 1).Opinion().getReason()); + } +} diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index c65fd7901..7972b28d8 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -84,6 +84,7 @@ CPP_TEST_BROKEN += \ extend_variable \ li_std_vector_ptr \ li_boost_shared_ptr_template \ + nested_private \ overload_complicated \ template_default_pointer \ template_expr \ @@ -279,6 +280,7 @@ CPP_TEST_CASES += \ naturalvar_more \ nested_class \ nested_comment \ + nested_scope \ nested_workaround \ newobject1 \ null_pointer \ diff --git a/Examples/test-suite/derived_nested.i b/Examples/test-suite/derived_nested.i index 29114d5a0..e374cf70f 100644 --- a/Examples/test-suite/derived_nested.i +++ b/Examples/test-suite/derived_nested.i @@ -3,14 +3,12 @@ This was reported in bug #909389 */ %module derived_nested -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) BB::CC; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) BB::DD; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) BB::EE; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) BB::FF; - %inline %{ -class A { int x; }; +class A { +public: + int x; +}; class B { class C { int y; }; //generates a warning class D : public A { int z; }; //ok diff --git a/Examples/test-suite/java/nested_class_runme.java b/Examples/test-suite/java/nested_class_runme.java index f1c67a0af..f75613e65 100644 --- a/Examples/test-suite/java/nested_class_runme.java +++ b/Examples/test-suite/java/nested_class_runme.java @@ -14,59 +14,59 @@ public class nested_class_runme { public static void main(String argv[]) { Outer outer = new Outer(); - SWIGTYPE_p_Outer__InnerStruct1 is1 = outer.makeInnerStruct1(); - SWIGTYPE_p_Outer__InnerClass1 ic1 = outer.makeInnerClass1(); - SWIGTYPE_p_Outer__InnerUnion1 iu1 = outer.makeInnerUnion1(); + Outer.InnerStruct1 is1 = outer.makeInnerStruct1(); + Outer.InnerClass1 ic1 = outer.makeInnerClass1(); + Outer.InnerUnion1 iu1 = outer.makeInnerUnion1(); - SWIGTYPE_p_Outer__InnerStruct2 is2 = outer.makeInnerStruct2(); - SWIGTYPE_p_Outer__InnerClass2 ic2 = outer.makeInnerClass2(); - SWIGTYPE_p_Outer__InnerUnion2 iu2 = outer.makeInnerUnion2(); + Outer.InnerStruct2 is2 = outer.makeInnerStruct2(); + Outer.InnerClass2 ic2 = outer.makeInnerClass2(); + Outer.InnerUnion2 iu2 = outer.makeInnerUnion2(); - SWIGTYPE_p_Outer__InnerClass4Typedef ic4 = outer.makeInnerClass4Typedef(); - SWIGTYPE_p_Outer__InnerStruct4Typedef is4 = outer.makeInnerStruct4Typedef(); - SWIGTYPE_p_Outer__InnerUnion4Typedef iu4 = outer.makeInnerUnion4Typedef(); + Outer.InnerClass4Typedef ic4 = outer.makeInnerClass4Typedef(); + Outer.InnerStruct4Typedef is4 = outer.makeInnerStruct4Typedef(); + Outer.InnerUnion4Typedef iu4 = outer.makeInnerUnion4Typedef(); - SWIGTYPE_p_Outer__InnerClass5 ic5 = outer.makeInnerClass5(); - SWIGTYPE_p_Outer__InnerStruct5 is5 = outer.makeInnerStruct5(); - SWIGTYPE_p_Outer__InnerUnion5 iu5 = outer.makeInnerUnion5(); + Outer.InnerClass5Typedef ic5 = outer.makeInnerClass5(); + Outer.InnerStruct5Typedef is5 = outer.makeInnerStruct5(); + Outer.InnerUnion5Typedef iu5 = outer.makeInnerUnion5(); ic5 = outer.makeInnerClass5Typedef(); is5 = outer.makeInnerStruct5Typedef(); iu5 = outer.makeInnerUnion5Typedef(); { - SWIGTYPE_p_Outer__InnerMultiple im1 = outer.getMultipleInstance1(); - SWIGTYPE_p_Outer__InnerMultiple im2 = outer.getMultipleInstance2(); - SWIGTYPE_p_Outer__InnerMultiple im3 = outer.getMultipleInstance3(); - SWIGTYPE_p_Outer__InnerMultiple im4 = outer.getMultipleInstance4(); + Outer.InnerMultiple im1 = outer.getMultipleInstance1(); + Outer.InnerMultiple im2 = outer.getMultipleInstance2(); + Outer.InnerMultiple im3 = outer.getMultipleInstance3(); + Outer.InnerMultiple im4 = outer.getMultipleInstance4(); } { - SWIGTYPE_p_Outer__InnerMultipleDerived im1 = outer.getMultipleDerivedInstance1(); - SWIGTYPE_p_Outer__InnerMultipleDerived im2 = outer.getMultipleDerivedInstance2(); - SWIGTYPE_p_Outer__InnerMultipleDerived im3 = outer.getMultipleDerivedInstance3(); - SWIGTYPE_p_Outer__InnerMultipleDerived im4 = outer.getMultipleDerivedInstance4(); + Outer.InnerMultipleDerived im1 = outer.getMultipleDerivedInstance1(); + Outer.InnerMultipleDerived im2 = outer.getMultipleDerivedInstance2(); + Outer.InnerMultipleDerived im3 = outer.getMultipleDerivedInstance3(); + Outer.InnerMultipleDerived im4 = outer.getMultipleDerivedInstance4(); } { - SWIGTYPE_p_Outer__InnerMultipleDerived im1 = outer.getMultipleDerivedInstance1(); - SWIGTYPE_p_Outer__InnerMultipleDerived im2 = outer.getMultipleDerivedInstance2(); - SWIGTYPE_p_Outer__InnerMultipleDerived im3 = outer.getMultipleDerivedInstance3(); - SWIGTYPE_p_Outer__InnerMultipleDerived im4 = outer.getMultipleDerivedInstance4(); + Outer.InnerMultipleDerived im1 = outer.getMultipleDerivedInstance1(); + Outer.InnerMultipleDerived im2 = outer.getMultipleDerivedInstance2(); + Outer.InnerMultipleDerived im3 = outer.getMultipleDerivedInstance3(); + Outer.InnerMultipleDerived im4 = outer.getMultipleDerivedInstance4(); } { - SWIGTYPE_p_Outer__InnerMultipleAnonTypedef1 mat1 = outer.makeInnerMultipleAnonTypedef1(); - SWIGTYPE_p_Outer__InnerMultipleAnonTypedef2 mat2 = outer.makeInnerMultipleAnonTypedef2(); - SWIGTYPE_p_Outer__InnerMultipleAnonTypedef3 mat3 = outer.makeInnerMultipleAnonTypedef3(); + Outer.InnerMultipleAnonTypedef1 mat1 = outer.makeInnerMultipleAnonTypedef1(); + Outer.InnerMultipleAnonTypedef1 mat2 = outer.makeInnerMultipleAnonTypedef2(); + SWIGTYPE_p_p_Outer__InnerMultipleAnonTypedef1 mat3 = outer.makeInnerMultipleAnonTypedef3(); - SWIGTYPE_p_Outer__InnerMultipleNamedTypedef mnt = outer.makeInnerMultipleNamedTypedef(); - SWIGTYPE_p_Outer__InnerMultipleNamedTypedef mnt1 = outer.makeInnerMultipleNamedTypedef1(); - SWIGTYPE_p_Outer__InnerMultipleNamedTypedef mnt2 = outer.makeInnerMultipleNamedTypedef2(); + Outer.InnerMultipleNamedTypedef1 mnt = outer.makeInnerMultipleNamedTypedef(); + Outer.InnerMultipleNamedTypedef1 mnt1 = outer.makeInnerMultipleNamedTypedef1(); + Outer.InnerMultipleNamedTypedef1 mnt2 = outer.makeInnerMultipleNamedTypedef2(); SWIGTYPE_p_p_Outer__InnerMultipleNamedTypedef mnt3 = outer.makeInnerMultipleNamedTypedef3(); } { - SWIGTYPE_p_Outer__InnerSameName isn = outer.makeInnerSameName(); + Outer.InnerSameName isn = outer.makeInnerSameName(); } } } diff --git a/Examples/test-suite/java/nested_structs_runme.java b/Examples/test-suite/java/nested_structs_runme.java index 6e103cd12..43c5e2897 100644 --- a/Examples/test-suite/java/nested_structs_runme.java +++ b/Examples/test-suite/java/nested_structs_runme.java @@ -17,21 +17,28 @@ public class nested_structs_runme { nested_structs.setValues(outer, 10); Outer_inner1 inner1 = outer.getInner1(); - Outer_inner2 inner2 = outer.getInner2(); - Outer_inner3 inner3 = outer.getInner3(); - Outer_inner4 inner4 = outer.getInner4(); + Outer_inner1 inner2 = outer.getInner2(); + Outer_inner1 inner3 = outer.getInner3(); + Outer_inner1 inner4 = outer.getInner4(); if (inner1.getVal() != 10) throw new RuntimeException("failed inner1"); if (inner2.getVal() != 20) throw new RuntimeException("failed inner2"); if (inner3.getVal() != 20) throw new RuntimeException("failed inner3"); if (inner4.getVal() != 40) throw new RuntimeException("failed inner4"); - Outer_inside1 inside1 = outer.getInside1(); - Outer_inside2 inside2 = outer.getInside2(); - Outer_inside3 inside3 = outer.getInside3(); - Outer_inside4 inside4 = outer.getInside4(); + Named inside1 = outer.getInside1(); + Named inside2 = outer.getInside2(); + Named inside3 = outer.getInside3(); + Named inside4 = outer.getInside4(); if (inside1.getVal() != 100) throw new RuntimeException("failed inside1"); if (inside2.getVal() != 200) throw new RuntimeException("failed inside2"); if (inside3.getVal() != 200) throw new RuntimeException("failed inside3"); if (inside4.getVal() != 400) throw new RuntimeException("failed inside4"); + + outer.getInner1().setVal(11); + if (inner1.getVal() != 11) throw new RuntimeException("failed inner1 assignment"); + Named named = new Named(); + named.setVal(22); + outer.setInside2(named); + if (outer.getInside2().getVal() != 22) throw new RuntimeException("failed inside2 assignment"); } } diff --git a/Examples/test-suite/java/template_nested_runme.java b/Examples/test-suite/java/template_nested_runme.java index 407821674..422e7ea9e 100644 --- a/Examples/test-suite/java/template_nested_runme.java +++ b/Examples/test-suite/java/template_nested_runme.java @@ -25,6 +25,10 @@ public class template_nested_runme { T_NestedOuterTemplateDouble tn = new T_NestedOuterTemplateDouble(); if (tn.hohum(-12.3) != -12.3) throw new RuntimeException("it failed"); + OuterClass.T_OuterClassInner1Int inner1 = new OuterClass().useInner1(new OuterClass.T_OuterClassInner1Int()); + OuterClass.T_OuterClassInner2NormalClass inner2 = new OuterClass.T_OuterClassInner2NormalClass(); + inner2.setEmbeddedVar(2); + OuterClass.T_OuterClassInner2NormalClass inner22 = new OuterClass().useInner2Again(inner2); } } diff --git a/Examples/test-suite/namespace_class.i b/Examples/test-suite/namespace_class.i index aea5362d1..113bbeb35 100644 --- a/Examples/test-suite/namespace_class.i +++ b/Examples/test-suite/namespace_class.i @@ -1,6 +1,5 @@ %module namespace_class -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Ala::Ola; #ifdef SWIGD %warnfilter(SWIGWARN_IGNORE_OPERATOR_LT); @@ -216,9 +215,6 @@ namespace a %} -// %copyctor doesn't work with nested class workaround -%nocopyctor; - %inline %{ class Ala { public : @@ -236,12 +232,6 @@ namespace a }; %} -%rename(Ala__Ola) Ala::Ola; -class Ala::Ola { -public: - Ola() {} - void eek() {} -}; %template(hi) Ala::hi<int>; diff --git a/Examples/test-suite/namespace_union.i b/Examples/test-suite/namespace_union.i index 85885f399..84e38b4d5 100644 --- a/Examples/test-suite/namespace_union.i +++ b/Examples/test-suite/namespace_union.i @@ -1,7 +1,5 @@ %module namespace_union -#pragma SWIG nowarn=SWIGWARN_PARSE_UNNAMED_NESTED_CLASS - %inline %{ namespace SpatialIndex { diff --git a/Examples/test-suite/nested_class.i b/Examples/test-suite/nested_class.i index d67440ac9..0d418192d 100644 --- a/Examples/test-suite/nested_class.i +++ b/Examples/test-suite/nested_class.i @@ -1,25 +1,5 @@ %module nested_class -#pragma SWIG nowarn=SWIGWARN_PARSE_UNNAMED_NESTED_CLASS -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerStruct1; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerClass1; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerUnion1; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerClass2; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerStruct2; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerUnion2; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerClass4Typedef; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerStruct4Typedef; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerUnion4Typedef; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerClass5; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerStruct5; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerUnion5; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerMultiple; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerMultipleDerived; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerMultipleAnonTypedef1; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerMultipleNamedTypedef; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer::InnerSameName; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) Outer2::IgnoreMe; - %inline %{ struct Outer { typedef int Integer; @@ -39,7 +19,7 @@ struct Outer { }; /////////////////////////////////////////// -#ifdef SWIG +#if defined(__GNUC__) || defined(_MSC_VER) || defined(SWIG) /* some compilers do not accept these */ class { public: @@ -154,7 +134,7 @@ struct Outer { Integer xx; } MultipleInstanceAnonDerived1, MultipleInstanceAnonDerived2, *MultipleInstanceAnonDerived3, MultipleInstanceAnonDerived4[2]; -#ifdef SWIG +#if defined(__GNUC__) || defined(_MSC_VER) || defined(SWIG) /* some compilers do not accept these */ struct : public InnerMultiple { Integer xx; diff --git a/Examples/test-suite/nested_comment.i b/Examples/test-suite/nested_comment.i index 99d0ffb43..df160b157 100644 --- a/Examples/test-suite/nested_comment.i +++ b/Examples/test-suite/nested_comment.i @@ -1,7 +1,5 @@ %module nested_comment -#pragma SWIG nowarn=SWIGWARN_PARSE_UNNAMED_NESTED_CLASS - // this example shows a problem with 'dump_nested' (parser.y). // bug #949654 diff --git a/Examples/test-suite/nested_private.i b/Examples/test-suite/nested_private.i new file mode 100644 index 000000000..a573fdd5a --- /dev/null +++ b/Examples/test-suite/nested_private.i @@ -0,0 +1,32 @@ +%module nested_private + +// segfault due to private nested class usage + +%inline %{ +#include <string> +class MotorCar { + + struct DesignOpinion { + std::string reason; + }; + +public: + struct WindScreen { + WindScreen(bool opaque) : opaque(opaque) {} + DesignOpinion Opinion(); + private: + bool opaque; + }; + + std::string WindScreenOpinion() { + return MotorCar::WindScreen(true).Opinion().reason; + } +}; + +MotorCar::DesignOpinion MotorCar::WindScreen::Opinion() { + DesignOpinion opinion; + opinion.reason = !opaque ? "great design" : "you can't see out the windscreen"; + return opinion; +} + +%} diff --git a/Examples/test-suite/nested_scope.i b/Examples/test-suite/nested_scope.i new file mode 100644 index 000000000..358dbbb61 --- /dev/null +++ b/Examples/test-suite/nested_scope.i @@ -0,0 +1,14 @@ +%module nested_scope + +%inline %{ +namespace ns { + struct Global { + struct Outer { + struct Nested; + }; + struct Outer::Nested { + int data; + } instance; + }; +} +%}
\ No newline at end of file diff --git a/Examples/test-suite/nested_structs.i b/Examples/test-suite/nested_structs.i index c15623085..44ff994ba 100644 --- a/Examples/test-suite/nested_structs.i +++ b/Examples/test-suite/nested_structs.i @@ -25,5 +25,21 @@ void setValues(struct Outer *outer, int val) { outer->inside4[0].val = val * 4; outer->inside5 = &outer->inside3; } + +int getInside1Val(struct Outer *n) { return n->inside1.val; } +%} + +/* +Below was causing problems in Octave as wrappers were compiled as C++. +Solution requires regenerating the inner struct into +the global C++ namespace (which is where it is intended to be in C). +*/ +%inline %{ +int nestedByVal(struct Named s); +int nestedByPtr(struct Named *s); +%} +%{ +int nestedByVal(struct Named s) { return s.val; } +int nestedByPtr(struct Named *s) { return s->val; } %} diff --git a/Examples/test-suite/nested_workaround.i b/Examples/test-suite/nested_workaround.i index 9727dacee..bb69a5bbd 100644 --- a/Examples/test-suite/nested_workaround.i +++ b/Examples/test-suite/nested_workaround.i @@ -1,14 +1,6 @@ %module nested_workaround -// Similar to "Nested classes" documentation example. - -class Inner { - int val; - public: - Inner(int v = 0) : val(v) {} - void setValue(int v) { val = v; } - int getValue() const { return val; } -}; -%nestedworkaround Outer::Inner; +// "flatnested" emulates deprecated feature "nested_workaround" for the languages not supporting nested classes +%feature ("flatnested"); %inline %{ class Outer { @@ -28,11 +20,3 @@ public: } }; %} - -// We've fooled SWIG into thinking that Inner is a global class, so now we need -// to trick the C++ compiler into understanding this apparent global type. -%{ -typedef Outer::Inner Inner; -%} - - diff --git a/Examples/test-suite/octave/nested_structs_runme.m b/Examples/test-suite/octave/nested_structs_runme.m new file mode 100644 index 000000000..a04aaa672 --- /dev/null +++ b/Examples/test-suite/octave/nested_structs_runme.m @@ -0,0 +1,14 @@ +nested_structs + +named = nested_structs.Named(); +named.val = 999; +assert(nested_structs.nestedByVal(named), 999); +assert(nested_structs.nestedByPtr(named), 999); + +outer = nested_structs.Outer(); +outer.inside1.val = 456; +assert(nested_structs.getInside1Val(outer), 456); + +outer.inside1 = named; +assert(nested_structs.getInside1Val(outer), 999); + diff --git a/Examples/test-suite/template_nested.i b/Examples/test-suite/template_nested.i index 1bb1c686a..bbca9502c 100644 --- a/Examples/test-suite/template_nested.i +++ b/Examples/test-suite/template_nested.i @@ -2,13 +2,6 @@ // Test nested templates - that is template classes and template methods within a class. -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) ns::OuterClass::Inner1; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) ns::OuterClass::Inner2; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) ns::OuterTemplate::NestedInnerTemplate1; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) ns::OuterTemplate::NestedInnerTemplate2; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) ns::OuterTemplate::NestedInnerTemplate3; -%warnfilter(SWIGWARN_PARSE_NAMED_NESTED_CLASS) ns::OuterTemplate::NestedStruct; - namespace ns { template <class T> struct ForwardTemplate; } @@ -33,7 +26,13 @@ namespace ns { template <class T> struct NormalTemplate { void tmethod(T t) {} }; +} +%} +%template(T_NormalTemplateNormalClass) ns::NormalTemplate<ns::NormalClass>; +%template(T_NormalTemplateInt) ns::NormalTemplate<int>; +%inline %{ +namespace ns { class OuterClass { public: template <class T> struct Inner1 { @@ -70,6 +69,7 @@ namespace ns { }; }; Inner2<int> useInner2(const Inner2<int>& inner) { return inner; } + Inner2<NormalClass> useInner2Again(const Inner2<NormalClass>& inner) { return inner; } int iii; }; struct ABC { @@ -108,9 +108,10 @@ namespace ns { %} -%template(T_NormalTemplateNormalClass) ns::NormalTemplate<ns::NormalClass>; %template(T_OuterTMethodNormalClass) ns::OuterClass::InnerTMethod<ns::NormalClass>; %template(T_TemplateFuncs1Int) ns::TemplateFuncs::templateMethod1<int>; %template(T_TemplateFuncs2Double) ns::TemplateFuncs::templateMethod2<double>; %template(T_NestedOuterTemplateDouble) ns::OuterTemplate<double>; - +%template(T_OuterClassInner1Int) ns::OuterClass::Inner1<int>; +%template(T_OuterClassInner2NormalClass) ns::OuterClass::Inner2<ns::NormalClass>; +%template(T_OuterClassInner2Int) ns::OuterClass::Inner2<int>; diff --git a/Examples/test-suite/template_nested_typemaps.i b/Examples/test-suite/template_nested_typemaps.i index 54f5bc503..b40e7e291 100644 --- a/Examples/test-suite/template_nested_typemaps.i +++ b/Examples/test-suite/template_nested_typemaps.i @@ -4,18 +4,22 @@ // Testing that the typemaps invoked within a class via %template are picked up by appropriate methods +%inline %{ template <typename T> struct Typemap { +#ifdef SWIG %typemap(in) T { $1 = -99; } +#endif }; template <> struct Typemap<short> { // Note explicit specialization +#ifdef SWIG %typemap(in) short { $1 = -77; } +#endif }; -%inline %{ int globalInt1(int s) { return s; } short globalShort1(short s) { return s; } diff --git a/Examples/test-suite/union_scope.i b/Examples/test-suite/union_scope.i index b7307cb29..67093eff6 100644 --- a/Examples/test-suite/union_scope.i +++ b/Examples/test-suite/union_scope.i @@ -2,7 +2,6 @@ %warnfilter(SWIGWARN_RUBY_WRONG_NAME) nRState; // Ruby, wrong class name %warnfilter(SWIGWARN_RUBY_WRONG_NAME) nRState_rstate; // Ruby, wrong class name -#pragma SWIG nowarn=SWIGWARN_PARSE_UNNAMED_NESTED_CLASS %inline %{ class nRState { diff --git a/Lib/swig.swg b/Lib/swig.swg index 241d93f3f..edadf036d 100644 --- a/Lib/swig.swg +++ b/Lib/swig.swg @@ -9,7 +9,7 @@ * User Directives * ----------------------------------------------------------------------------- */ -/* Deprecated SWIG directives */ +/* Deprecated SWIG-1.1 directives */ #define %disabledoc %warn "104:%disabledoc is deprecated" #define %enabledoc %warn "105:%enabledoc is deprecated" @@ -136,11 +136,16 @@ #define %nocallback %feature("callback","0") #define %clearcallback %feature("callback","") -/* the %nestedworkaround directive */ +/* the %nestedworkaround directive (deprecated) */ #define %nestedworkaround %feature("nestedworkaround") #define %nonestedworkaround %feature("nestedworkaround","0") #define %clearnestedworkaround %feature("nestedworkaround","") +/* the %flatnested directive */ +#define %flatnested %feature("flatnested") +#define %noflatnested %feature("flatnested","0") +#define %clearflatnested %feature("flatnested","") + /* the %fastdispatch directive */ #define %fastdispatch %feature("fastdispatch") #define %nofastdispatch %feature("fastdispatch","0") @@ -302,7 +307,7 @@ static int NAME(TYPE x) { %define %$ismemberset "match$memberset"="1" %enddef %define %$classname %$ismember,"match$parentNode$name" %enddef - +%define %$isnested "match$nested"="1" %enddef /* ----------------------------------------------------------------------------- * Include all the warnings labels and macros * ----------------------------------------------------------------------------- */ diff --git a/Lib/typemaps/swigtype.swg b/Lib/typemaps/swigtype.swg index 5e92790d8..6c0affbe2 100644 --- a/Lib/typemaps/swigtype.swg +++ b/Lib/typemaps/swigtype.swg @@ -159,7 +159,7 @@ %typemap(memberin) SWIGTYPE [ANY] { if ($input) { size_t ii = 0; - for (; ii < (size_t)$1_dim0; ++ii) $1[ii] = $input[ii]; + for (; ii < (size_t)$1_dim0; ++ii) *($1_ltype)&$1[ii] = ($*1_ltype)$input[ii]; } else { %variable_nullref("$type","$name"); } @@ -168,7 +168,7 @@ %typemap(globalin) SWIGTYPE [ANY] { if ($input) { size_t ii = 0; - for (; ii < (size_t)$1_dim0; ++ii) $1[ii] = $input[ii]; + for (; ii < (size_t)$1_dim0; ++ii) *($1_ltype)&$1[ii] = ($*1_ltype)$input[ii]; } else { %variable_nullref("$type","$name"); } @@ -181,7 +181,7 @@ %variable_fail(res, "$type", "$name"); } else if (inp) { size_t ii = 0; - for (; ii < (size_t)$1_dim0; ++ii) $1[ii] = inp[ii]; + for (; ii < (size_t)$1_dim0; ++ii) *($1_ltype)&$1[ii] = ($*1_ltype)inp[ii]; } else { %variable_nullref("$type", "$name"); } diff --git a/Source/CParse/cparse.h b/Source/CParse/cparse.h index 922bbfcdc..6d7342a45 100644 --- a/Source/CParse/cparse.h +++ b/Source/CParse/cparse.h @@ -25,12 +25,15 @@ extern "C" { extern String *cparse_file; extern int cparse_line; extern int cparse_cplusplus; + extern int cparse_cplusplusout; extern int cparse_start_line; extern void Swig_cparse_cplusplus(int); + extern void Swig_cparse_cplusplusout(int); extern void scanner_file(File *); extern void scanner_next_token(int); extern void skip_balanced(int startchar, int endchar); + extern String *get_raw_text_balanced(int startchar, int endchar); extern void skip_decl(void); extern void scanner_check_typedef(void); extern void scanner_ignore_typedef(void); diff --git a/Source/CParse/cscanner.c b/Source/CParse/cscanner.c index c04ce4688..2dfc2c479 100644 --- a/Source/CParse/cscanner.c +++ b/Source/CParse/cscanner.c @@ -37,6 +37,9 @@ int cparse_start_line = 0; /* C++ mode */ int cparse_cplusplus = 0; +/* Generate C++ compatible code when wrapping C code */ +int cparse_cplusplusout = 0; + /* Private vars */ static int scan_init = 0; static int num_brace = 0; @@ -52,6 +55,14 @@ void Swig_cparse_cplusplus(int v) { cparse_cplusplus = v; } +/* ----------------------------------------------------------------------------- + * Swig_cparse_cplusplusout() + * ----------------------------------------------------------------------------- */ + +void Swig_cparse_cplusplusout(int v) { + cparse_cplusplusout = v; +} + /* ---------------------------------------------------------------------------- * scanner_init() * @@ -118,6 +129,16 @@ void skip_balanced(int startchar, int endchar) { return; } +/* ----------------------------------------------------------------------------- + * get_raw_text_balanced() + * + * Returns raw text between 2 braces + * ----------------------------------------------------------------------------- */ + +String *get_raw_text_balanced(int startchar, int endchar) { + return Scanner_get_raw_text_balanced(scan, startchar, endchar); +} + /* ---------------------------------------------------------------------------- * void skip_decl(void) * diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index 3384dcc5b..203284402 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -51,7 +51,7 @@ static Node *module_node = 0; static String *Classprefix = 0; static String *Namespaceprefix = 0; static int inclass = 0; -static int nested_template = 0; /* template class/function definition within a class */ +static Node *currentOuterClass = 0; /* for nested classes */ static char *last_cpptype = 0; static int inherit_list = 0; static Parm *template_parameters = 0; @@ -60,10 +60,6 @@ static int compact_default_args = 0; static int template_reduce = 0; static int cparse_externc = 0; -static int max_class_levels = 0; -static int class_level = 0; -static Node **class_decl = NULL; - /* ----------------------------------------------------------------------------- * Assist Functions * ----------------------------------------------------------------------------- */ @@ -165,7 +161,6 @@ static Node *copy_node(Node *n) { static char *typemap_lang = 0; /* Current language setting */ static int cplus_mode = 0; -static String *class_rename = 0; /* C++ modes */ @@ -237,6 +232,25 @@ static String *feature_identifier_fix(String *s) { } } +static void set_access_mode(Node *n) { + if (cplus_mode == CPLUS_PUBLIC) + Setattr(n, "access", "public"); + else if (cplus_mode == CPLUS_PROTECTED) + Setattr(n, "access", "protected"); + else + Setattr(n, "access", "private"); +} + +static void restore_access_mode(Node *n) { + String *mode = Getattr(n, "access"); + if (Strcmp(mode, "private") == 0) + cplus_mode = CPLUS_PRIVATE; + else if (Strcmp(mode, "protected") == 0) + cplus_mode = CPLUS_PROTECTED; + else + cplus_mode = CPLUS_PUBLIC; +} + /* Generate the symbol table name for an object */ /* This is a bit of a mess. Need to clean up */ static String *add_oldname = 0; @@ -283,13 +297,6 @@ static void add_symbols(Node *n) { String *decl; String *wrn = 0; - if (nested_template) { - if (!(n && Equal(nodeType(n), "template"))) { - return; - } - /* continue if template function, but not template class, declared within a class */ - } - if (inclass && n) { cparse_normalize_void(n); } @@ -301,9 +308,6 @@ static void add_symbols(Node *n) { int isfriend = inclass && is_friend(n); int iscdecl = Cmp(nodeType(n),"cdecl") == 0; int only_csymbol = 0; - if (extendmode) { - Setattr(n,"isextension","1"); - } if (inclass) { String *name = Getattr(n, "name"); @@ -349,9 +353,6 @@ static void add_symbols(Node *n) { Delete(prefix); } - /* - if (!Getattr(n,"parentNode") && class_level) set_parentNode(n,class_decl[class_level - 1]); - */ Setattr(n,"ismember","1"); } } @@ -793,53 +794,31 @@ static String *make_class_name(String *name) { return nname; } -static List *make_inherit_list(String *clsname, List *names) { - int i, ilen; - String *derived; - List *bases = NewList(); - - if (Namespaceprefix) derived = NewStringf("%s::%s", Namespaceprefix,clsname); - else derived = NewString(clsname); - - ilen = Len(names); - for (i = 0; i < ilen; i++) { - Node *s; - String *base; - String *n = Getitem(names,i); - /* Try to figure out where this symbol is */ - s = Swig_symbol_clookup(n,0); - if (s) { - while (s && (Strcmp(nodeType(s),"class") != 0)) { - /* Not a class. Could be a typedef though. */ - String *storage = Getattr(s,"storage"); - if (storage && (Strcmp(storage,"typedef") == 0)) { - String *nn = Getattr(s,"type"); - s = Swig_symbol_clookup(nn,Getattr(s,"sym:symtab")); - } else { - break; - } - } - if (s && ((Strcmp(nodeType(s),"class") == 0) || (Strcmp(nodeType(s),"template") == 0))) { - String *q = Swig_symbol_qualified(s); - Append(bases,s); - if (q) { - base = NewStringf("%s::%s", q, Getattr(s,"name")); - Delete(q); - } else { - base = NewString(Getattr(s,"name")); - } - } else { - base = NewString(n); - } - } else { - base = NewString(n); - } - if (base) { - Swig_name_inherit(base,derived); - Delete(base); +/* Use typedef name as class name */ + +static void add_typedef_name(Node *n, Node *decl, String *oldName, Symtab *cscope, String *scpname) { + String *class_rename = 0; + SwigType *decltype = Getattr(decl, "decl"); + if (!decltype || !Len(decltype)) { + String *cname; + String *tdscopename; + String *class_scope = Swig_symbol_qualifiedscopename(cscope); + String *name = Getattr(decl, "name"); + cname = Copy(name); + Setattr(n, "tdname", cname); + tdscopename = class_scope ? NewStringf("%s::%s", class_scope, name) : Copy(name); + class_rename = Getattr(n, "class_rename"); + if (class_rename && (Strcmp(class_rename, oldName) == 0)) + Setattr(n, "class_rename", NewString(name)); + if (!classes_typedefs) classes_typedefs = NewHash(); + if (!Equal(scpname, tdscopename) && !Getattr(classes_typedefs, tdscopename)) { + Setattr(classes_typedefs, tdscopename, n); } + Setattr(n, "decl", decltype); + Delete(class_scope); + Delete(cname); + Delete(tdscopename); } - return bases; } /* If the class name is qualified. We need to create or lookup namespace entries */ @@ -1059,352 +1038,33 @@ static String *resolve_create_node_scope(String *cname) { return cname; } - - -/* Structures for handling code fragments built for nested classes */ - -typedef struct Nested { - String *code; /* Associated code fragment */ - int line; /* line number where it starts */ - const char *name; /* Name associated with this nested class */ - const char *kind; /* Kind of class */ - int unnamed; /* unnamed class */ - SwigType *type; /* Datatype associated with the name */ - struct Nested *next; /* Next code fragment in list */ -} Nested; - -/* Some internal variables for saving nested class information */ - -static Nested *nested_list = 0; - -/* Add a function to the nested list */ - -static void add_nested(Nested *n) { - if (!nested_list) { - nested_list = n; - } else { - Nested *n1 = nested_list; - while (n1->next) - n1 = n1->next; - n1->next = n; - } -} - -/* ----------------------------------------------------------------------------- - * nested_new_struct() - * - * Nested struct handling for C code only creates a global struct from the nested struct. - * - * Nested structure. This is a sick "hack". If we encounter - * a nested structure, we're going to grab the text of its definition and - * feed it back into the scanner. In the meantime, we need to grab - * variable declaration information and generate the associated wrapper - * code later. Yikes! - * - * This really only works in a limited sense. Since we use the - * code attached to the nested class to generate both C code - * it can't have any SWIG directives in it. It also needs to be parsable - * by SWIG or this whole thing is going to puke. - * ----------------------------------------------------------------------------- */ - -static void nested_new_struct(const char *kind, String *struct_code, Node *cpp_opt_declarators) { - String *name; - String *decl; - - /* Create a new global struct declaration which is just a copy of the nested struct */ - Nested *nested = (Nested *) malloc(sizeof(Nested)); - Nested *n = nested; - - name = Getattr(cpp_opt_declarators, "name"); - decl = Getattr(cpp_opt_declarators, "decl"); - - n->code = NewStringEmpty(); - Printv(n->code, "typedef ", kind, " ", struct_code, " $classname_", name, ";\n", NIL); - n->name = Swig_copy_string(Char(name)); - n->line = cparse_start_line; - n->type = NewStringEmpty(); - n->kind = kind; - n->unnamed = 0; - SwigType_push(n->type, decl); - n->next = 0; - - /* Repeat for any multiple instances of the nested struct */ - { - Node *p = cpp_opt_declarators; - p = nextSibling(p); - while (p) { - Nested *nn = (Nested *) malloc(sizeof(Nested)); - - name = Getattr(p, "name"); - decl = Getattr(p, "decl"); - - nn->code = NewStringEmpty(); - Printv(nn->code, "typedef ", kind, " ", struct_code, " $classname_", name, ";\n", NIL); - nn->name = Swig_copy_string(Char(name)); - nn->line = cparse_start_line; - nn->type = NewStringEmpty(); - nn->kind = kind; - nn->unnamed = 0; - SwigType_push(nn->type, decl); - nn->next = 0; - n->next = nn; - n = nn; - p = nextSibling(p); - } - } - - add_nested(nested); -} - -/* ----------------------------------------------------------------------------- - * nested_forward_declaration() - * - * Nested struct handling for C++ code only. - * - * Treat the nested class/struct/union as a forward declaration until a proper - * nested class solution is implemented. - * ----------------------------------------------------------------------------- */ - -static Node *nested_forward_declaration(const char *storage, const char *kind, String *sname, String *name, Node *cpp_opt_declarators) { - Node *nn = 0; - int warned = 0; - - if (sname) { - /* Add forward declaration of the nested type */ - Node *n = new_node("classforward"); - Setattr(n, "kind", kind); - Setattr(n, "name", sname); - Setattr(n, "storage", storage); - Setattr(n, "sym:weak", "1"); - add_symbols(n); - nn = n; - } - - /* Add any variable instances. Also add in any further typedefs of the nested type. - Note that anonymous typedefs (eg typedef struct {...} a, b;) are treated as class forward declarations */ - if (cpp_opt_declarators) { - int storage_typedef = (storage && (strcmp(storage, "typedef") == 0)); - int variable_of_anonymous_type = !sname && !storage_typedef; - if (!variable_of_anonymous_type) { - int anonymous_typedef = !sname && (storage && (strcmp(storage, "typedef") == 0)); - Node *n = cpp_opt_declarators; - SwigType *type = name; - while (n) { - Setattr(n, "type", type); - Setattr(n, "storage", storage); - if (anonymous_typedef) { - Setattr(n, "nodeType", "classforward"); - Setattr(n, "sym:weak", "1"); - } - n = nextSibling(n); - } - add_symbols(cpp_opt_declarators); - - if (nn) { - set_nextSibling(nn, cpp_opt_declarators); - } else { - nn = cpp_opt_declarators; +/* look for simple typedef name in typedef list */ +static String *try_to_find_a_name_for_unnamed_structure(const char *storage, Node *decls) { + String *name = 0; + Node *n = decls; + if (storage && (strcmp(storage, "typedef") == 0)) { + for (; n; n = nextSibling(n)) { + if (!Len(Getattr(n, "decl"))) { + name = Copy(Getattr(n, "name")); + break; } } } - - if (nn && Equal(nodeType(nn), "classforward")) { - Node *n = nn; - if (GetFlag(n, "feature:nestedworkaround")) { - Swig_symbol_remove(n); - nn = 0; - warned = 1; - } else { - SWIG_WARN_NODE_BEGIN(n); - Swig_warning(WARN_PARSE_NAMED_NESTED_CLASS, cparse_file, cparse_line,"Nested %s not currently supported (%s ignored)\n", kind, sname ? sname : name); - SWIG_WARN_NODE_END(n); - warned = 1; - } - } - - if (!warned) - Swig_warning(WARN_PARSE_UNNAMED_NESTED_CLASS, cparse_file, cparse_line, "Nested %s not currently supported (ignored).\n", kind); - - return nn; + return name; } -/* Strips C-style and C++-style comments from string in-place. */ -static void strip_comments(char *string) { - int state = 0; /* - * 0 - not in comment - * 1 - in c-style comment - * 2 - in c++-style comment - * 3 - in string - * 4 - after reading / not in comments - * 5 - after reading * in c-style comments - * 6 - after reading \ in strings - */ - char * c = string; - while (*c) { - switch (state) { - case 0: - if (*c == '\"') - state = 3; - else if (*c == '/') - state = 4; - break; - case 1: - if (*c == '*') - state = 5; - *c = ' '; - break; - case 2: - if (*c == '\n') - state = 0; - else - *c = ' '; - break; - case 3: - if (*c == '\"') - state = 0; - else if (*c == '\\') - state = 6; - break; - case 4: - if (*c == '/') { - *(c-1) = ' '; - *c = ' '; - state = 2; - } else if (*c == '*') { - *(c-1) = ' '; - *c = ' '; - state = 1; - } else - state = 0; - break; - case 5: - if (*c == '/') - state = 0; - else - state = 1; - *c = ' '; - break; - case 6: - state = 3; - break; - } - ++c; +/* traverse copied tree segment, and update outer class links*/ +static void update_nested_classes(Node *n) +{ + Node *c = firstChild(n); + while (c) { + if (Getattr(c, "nested:outer")) + Setattr(c, "nested:outer", n); + update_nested_classes(c); + c = nextSibling(c); } } -/* Dump all of the nested class declarations to the inline processor - * However. We need to do a few name replacements and other munging - * first. This function must be called before closing a class! */ - -static Node *dump_nested(const char *parent) { - Nested *n,*n1; - Node *ret = 0; - Node *last = 0; - n = nested_list; - if (!parent) { - nested_list = 0; - return 0; - } - while (n) { - Node *retx; - SwigType *nt; - /* Token replace the name of the parent class */ - Replace(n->code, "$classname", parent, DOH_REPLACE_ANY); - - /* Fix up the name of the datatype (for building typedefs and other stuff) */ - Append(n->type,parent); - Append(n->type,"_"); - Append(n->type,n->name); - - /* Add the appropriate declaration to the C++ processor */ - retx = new_node("cdecl"); - Setattr(retx,"name",n->name); - nt = Copy(n->type); - Setattr(retx,"type",nt); - Delete(nt); - Setattr(retx,"nested",parent); - if (n->unnamed) { - Setattr(retx,"unnamed","1"); - } - - add_symbols(retx); - if (ret) { - set_nextSibling(last, retx); - Delete(retx); - } else { - ret = retx; - } - last = retx; - - /* Strip comments - further code may break in presence of comments. */ - strip_comments(Char(n->code)); - - /* Make all SWIG created typedef structs/unions/classes unnamed else - redefinition errors occur - nasty hack alert.*/ - - { - const char* types_array[3] = {"struct", "union", "class"}; - int i; - for (i=0; i<3; i++) { - char* code_ptr = Char(n->code); - while (code_ptr) { - /* Replace struct name (as in 'struct name {...}' ) with whitespace - name will be between struct and opening brace */ - - code_ptr = strstr(code_ptr, types_array[i]); - if (code_ptr) { - char *open_bracket_pos; - code_ptr += strlen(types_array[i]); - open_bracket_pos = strchr(code_ptr, '{'); - if (open_bracket_pos) { - /* Make sure we don't have something like struct A a; */ - char* semi_colon_pos = strchr(code_ptr, ';'); - if (!(semi_colon_pos && (semi_colon_pos < open_bracket_pos))) - while (code_ptr < open_bracket_pos) - *code_ptr++ = ' '; - } - } - } - } - } - - { - /* Remove SWIG directive %constant which may be left in the SWIG created typedefs */ - char* code_ptr = Char(n->code); - while (code_ptr) { - code_ptr = strstr(code_ptr, "%constant"); - if (code_ptr) { - char* directive_end_pos = strchr(code_ptr, ';'); - if (directive_end_pos) { - while (code_ptr <= directive_end_pos) - *code_ptr++ = ' '; - } - } - } - } - { - Node *newnode = new_node("insert"); - String *code = NewStringEmpty(); - Wrapper_pretty_print(n->code, code); - Setattr(newnode,"code", code); - Delete(code); - set_nextSibling(last, newnode); - Delete(newnode); - last = newnode; - } - - /* Dump the code to the scanner */ - start_inline(Char(Getattr(last, "code")),n->line); - - n1 = n->next; - Delete(n->code); - free(n); - n = n1; - } - nested_list = 0; - return ret; -} - Node *Swig_cparse(File *f) { scanner_file(f); top = 0; @@ -1420,6 +1080,10 @@ static void single_new_feature(const char *featurename, String *val, Hash *featu /* Printf(stdout, "single_new_feature: [%s] [%s] [%s] [%s] [%s] [%s]\n", featurename, val, declaratorid, t, ParmList_str_defaultargs(declaratorparms), qualifier); */ + /* Warn about deprecated features */ + if (strcmp(featurename, "nestedworkaround") == 0) + Swig_warning(WARN_DEPRECATED_NESTED_WORKAROUND, cparse_file, cparse_line, "The 'nestedworkaround' feature is deprecated.\n"); + fname = NewStringf("feature:%s",featurename); if (declaratorid) { fixname = feature_identifier_fix(declaratorid); @@ -1768,7 +1432,7 @@ static void tag_nodes(Node *n, const_String_or_char_ptr attrname, DOH *value) { %type <node> cpp_declaration cpp_class_decl cpp_forward_class_decl cpp_template_decl cpp_alternate_rettype; %type <node> cpp_members cpp_member; %type <node> cpp_constructor_decl cpp_destructor_decl cpp_protection_decl cpp_conversion_operator cpp_static_assert; -%type <node> cpp_swig_directive cpp_temp_possible cpp_nested cpp_opt_declarators ; +%type <node> cpp_swig_directive cpp_temp_possible cpp_opt_declarators ; %type <node> cpp_using_decl cpp_namespace_decl cpp_catch_decl cpp_lambda_decl; %type <node> kwargs options; @@ -1930,6 +1594,7 @@ swig_directive : extend_directive { $$ = $1; } extend_directive : EXTEND options idcolon LBRACE { Node *cls; String *clsname; + extendmode = 1; cplus_mode = CPLUS_PUBLIC; if (!classes) classes = NewHash(); if (!classes_typedefs) classes_typedefs = NewHash(); @@ -1955,7 +1620,6 @@ extend_directive : EXTEND options idcolon LBRACE { Note that %extend before the class typedef never worked, only %extend after the class typdef. */ prev_symtab = Swig_symbol_setscope(Getattr(cls, "symtab")); current_class = cls; - extendmode = 1; SWIG_WARN_NODE_BEGIN(cls); Swig_warning(WARN_PARSE_EXTEND_NAME, cparse_file, cparse_line, "Deprecated %%extend name used - the %s name '%s' should be used instead of the typedef name '%s'.\n", Getattr(cls, "kind"), SwigType_namestr(Getattr(cls, "name")), $3); SWIG_WARN_NODE_END(cls); @@ -1964,7 +1628,6 @@ extend_directive : EXTEND options idcolon LBRACE { /* Previous class definition. Use its symbol table */ prev_symtab = Swig_symbol_setscope(Getattr(cls,"symtab")); current_class = cls; - extendmode = 1; } Classprefix = NewString($3); Namespaceprefix= Swig_symbol_qualifiedscopename(0); @@ -2999,6 +2662,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va } templnode = copy_node(nn); + update_nested_classes(templnode); /* We need to set the node name based on name used to instantiate */ Setattr(templnode,"name",tname); Delete(tname); @@ -3007,7 +2671,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va } else { Setattr(templnode,"sym:typename","1"); } - if ($3 && !inclass) { + if ($3) { /* Comment this out for 1.3.28. We need to re-enable it later but first we need to @@ -3026,16 +2690,15 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va Setattr(templnode,"sym:name",nname); Delete(nname); Setattr(templnode,"feature:onlychildren", "typemap,typemapitem,typemapcopy,typedef,types,fragment"); - - if ($3) { - Swig_warning(WARN_PARSE_NESTED_TEMPLATE, cparse_file, cparse_line, "Named nested template instantiations not supported. Processing as if no name was given to %%template().\n"); - } } Delattr(templnode,"templatetype"); Setattr(templnode,"template",nn); Setfile(templnode,cparse_file); Setline(templnode,cparse_line); Delete(temparms); + if (currentOuterClass) { + SetFlag(templnode, "nested"); + } add_symbols_copy(templnode); @@ -3051,7 +2714,7 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va csyms = Swig_symbol_current(); Swig_symbol_setscope(Getattr(templnode,"symtab")); if (baselist) { - List *bases = make_inherit_list(Getattr(templnode,"name"),baselist); + List *bases = Swig_make_inherit_list(Getattr(templnode,"name"),baselist, Namespaceprefix); if (bases) { Iterator s; for (s = First(bases); s.item; s = Next(s)) { @@ -3703,10 +3366,10 @@ cpp_declaration : cpp_class_decl { $$ = $1; } /* A simple class/struct/union definition */ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { - if (nested_template == 0) { String *prefix; List *bases = 0; Node *scope = 0; + String *code; $<node>$ = new_node("class"); Setline($<node>$,cparse_start_line); Setattr($<node>$,"kind",$2); @@ -3718,41 +3381,30 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { Setattr($<node>$,"allows_typedef","1"); /* preserve the current scope */ - prev_symtab = Swig_symbol_current(); + Setattr($<node>$,"prev_symtab",Swig_symbol_current()); /* If the class name is qualified. We need to create or lookup namespace/scope entries */ scope = resolve_create_node_scope($3); + /* save nscope_inner to the class - it may be overwritten in nested classes*/ + Setattr($<node>$, "nested:innerscope", nscope_inner); + Setattr($<node>$, "nested:nscope", nscope); Setfile(scope,cparse_file); Setline(scope,cparse_line); $3 = scope; - - /* support for old nested classes "pseudo" support, such as: - - %rename(Ala__Ola) Ala::Ola; - class Ala::Ola { - public: - Ola() {} - }; - - this should disappear when a proper implementation is added. - */ - if (nscope_inner && Strcmp(nodeType(nscope_inner),"namespace") != 0) { - if (Namespaceprefix) { - String *name = NewStringf("%s::%s", Namespaceprefix, $3); - $3 = name; - Namespaceprefix = 0; - nscope_inner = 0; - } - } Setattr($<node>$,"name",$3); - Delete(class_rename); - class_rename = make_name($<node>$,$3,0); + if (currentOuterClass) { + SetFlag($<node>$, "nested"); + Setattr($<node>$, "nested:outer", currentOuterClass); + set_access_mode($<node>$); + } + /* save yyrename to the class attribute, to be used later in add_symbols()*/ + Setattr($<node>$, "class_rename", make_name($<node>$, $3, 0)); + Setattr($<node>$, "Classprefix", $3); Classprefix = NewString($3); /* Deal with inheritance */ - if ($4) { - bases = make_inherit_list($3,Getattr($4,"public")); - } + if ($4) + bases = Swig_make_inherit_list($3,Getattr($4,"public"),Namespaceprefix); prefix = SwigType_istemplate_templateprefix($3); if (prefix) { String *fbase, *tbase; @@ -3774,18 +3426,7 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { } Swig_symbol_newscope(); Swig_symbol_setscopename($3); - if (bases) { - Iterator s; - for (s = First(bases); s.item; s = Next(s)) { - Symtab *st = Getattr(s.item,"symtab"); - if (st) { - Setfile(st,Getfile(s.item)); - Setline(st,Getline(s.item)); - Swig_symbol_inherit(st); - } - } - Delete(bases); - } + Swig_inherit_base_symbols(bases); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); cparse_start_line = cparse_line; @@ -3804,31 +3445,34 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { Delete(tpname); } } - if (class_level >= max_class_levels) { - if (!max_class_levels) { - max_class_levels = 16; - } else { - max_class_levels *= 2; - } - class_decl = (Node**) realloc(class_decl, sizeof(Node*) * max_class_levels); - if (!class_decl) { - Swig_error(cparse_file, cparse_line, "realloc() failed\n"); - } - } - class_decl[class_level++] = $<node>$; Delete(prefix); inclass = 1; - } + currentOuterClass = $<node>$; + if (cparse_cplusplusout) { + /* save the structure declaration to declare it in global scope for C++ to see */ + code = get_raw_text_balanced('{', '}'); + Setattr($<node>$, "code", code); + Delete(code); + } } cpp_members RBRACE cpp_opt_declarators { - (void) $<node>6; - if (nested_template == 0) { Node *p; SwigType *ty; - Symtab *cscope = prev_symtab; + Symtab *cscope; Node *am = 0; String *scpname = 0; - $$ = class_decl[--class_level]; - inclass = 0; + (void) $<node>6; + $$ = currentOuterClass; + currentOuterClass = Getattr($$, "nested:outer"); + nscope_inner = Getattr($<node>$, "nested:innerscope"); + nscope = Getattr($<node>$, "nested:nscope"); + Delattr($<node>$, "nested:innerscope"); + Delattr($<node>$, "nested:nscope"); + if (nscope_inner && Strcmp(nodeType(nscope_inner), "class") == 0) /* actual parent class for this class */ + Setattr($$, "nested:outer", nscope_inner); + if (!currentOuterClass) + inclass = 0; + cscope = Getattr($$, "prev_symtab"); + Delattr($$, "prev_symtab"); /* Check for pure-abstract class */ Setattr($$,"abstracts", pure_abstracts($7)); @@ -3837,131 +3481,144 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { if (extendhash) { String *clsname = Swig_symbol_qualifiedscopename(0); - am = Getattr(extendhash,clsname); + am = Getattr(extendhash, clsname); if (am) { - merge_extensions($$,am); - Delattr(extendhash,clsname); + merge_extensions($$, am); + Delattr(extendhash, clsname); } Delete(clsname); } if (!classes) classes = NewHash(); scpname = Swig_symbol_qualifiedscopename(0); - Setattr(classes,scpname,$$); + Setattr(classes, scpname, $$); - appendChild($$,$7); + appendChild($$, $7); - if (am) append_previous_extension($$,am); + if (am) + append_previous_extension($$, am); p = $9; - if (p) { - set_nextSibling($$,p); + if (p && !nscope_inner) { + if (!cparse_cplusplus && currentOuterClass) + appendChild(currentOuterClass, p); + else + appendSibling($$, p); } - if (cparse_cplusplus && !cparse_externc) { + if (nscope_inner) { + ty = NewString(scpname); /* if the class is declared out of scope, let the declarator use fully qualified type*/ + } else if (cparse_cplusplus && !cparse_externc) { ty = NewString($3); } else { - ty = NewStringf("%s %s", $2,$3); + ty = NewStringf("%s %s", $2, $3); } while (p) { - Setattr(p,"storage",$1); - Setattr(p,"type",ty); - p = nextSibling(p); - } - /* Class typedefs */ - { - String *name = $3; - if ($9) { - SwigType *decltype = Getattr($9,"decl"); - if (Cmp($1,"typedef") == 0) { - if (!decltype || !Len(decltype)) { - String *cname; - String *tdscopename; - String *class_scope = Swig_symbol_qualifiedscopename(cscope); - name = Getattr($9,"name"); - cname = Copy(name); - Setattr($$,"tdname",cname); - tdscopename = class_scope ? NewStringf("%s::%s", class_scope, name) : Copy(name); - - /* Use typedef name as class name */ - if (class_rename && (Strcmp(class_rename,$3) == 0)) { - Delete(class_rename); - class_rename = NewString(name); - } - if (!classes_typedefs) classes_typedefs = NewHash(); - if (!Equal(scpname, tdscopename) && !Getattr(classes_typedefs, tdscopename)) { - Setattr(classes_typedefs, tdscopename, $$); - } - Setattr($$,"decl",decltype); - Delete(class_scope); - Delete(cname); - Delete(tdscopename); - } - } + Setattr(p, "storage", $1); + Setattr(p, "type" ,ty); + if (!cparse_cplusplus && currentOuterClass && (!Getattr(currentOuterClass, "name"))) { + SetFlag(p, "hasconsttype"); + SetFlag(p, "feature:immutable"); } - appendChild($$,dump_nested(Char(name))); + p = nextSibling(p); } + if ($9 && Cmp($1,"typedef") == 0) + add_typedef_name($$, $9, $3, cscope, scpname); Delete(scpname); if (cplus_mode != CPLUS_PUBLIC) { /* we 'open' the class at the end, to allow %template to add new members */ Node *pa = new_node("access"); - Setattr(pa,"kind","public"); + Setattr(pa, "kind", "public"); cplus_mode = CPLUS_PUBLIC; - appendChild($$,pa); + appendChild($$, pa); Delete(pa); } - - Setattr($$,"symtab",Swig_symbol_popscope()); - - Classprefix = 0; - if (nscope_inner) { + if (currentOuterClass) + restore_access_mode($$); + Setattr($$, "symtab", Swig_symbol_popscope()); + Classprefix = Getattr($<node>$, "Classprefix"); + Delattr($<node>$, "Classprefix"); + if (cplus_mode == CPLUS_PRIVATE) { + $$ = 0; /* skip private nested classes */ + } else if (nscope_inner) { /* this is tricky */ /* we add the declaration in the original namespace */ - appendChild(nscope_inner,$$); - Swig_symbol_setscope(Getattr(nscope_inner,"symtab")); + appendChild(nscope_inner, $$); + Swig_symbol_setscope(Getattr(nscope_inner, "symtab")); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); + yyrename = Copy(Getattr($<node>$, "class_rename")); add_symbols($$); - if (nscope) $$ = nscope; + Delattr($$, "class_rename"); /* but the variable definition in the current scope */ Swig_symbol_setscope(cscope); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); add_symbols($9); + if (nscope) { + $$ = nscope; /* here we return recreated namespace tower instead of the class itself */ + if ($9) + appendSibling($$, $9); + } + else if (!SwigType_istemplate(ty) && template_parameters == 0) /* for tempalte we need the class itself */ + $$ = $9; } else { Delete(yyrename); - yyrename = Copy(class_rename); + yyrename = 0; Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); - - add_symbols($$); - add_symbols($9); + if (!cparse_cplusplus && currentOuterClass) { /* nested C structs go into global scope*/ + Node *outer = currentOuterClass; + while (Getattr(outer, "nested:outer")) + outer = Getattr(outer, "nested:outer"); + appendSibling(outer, $$); + add_symbols($9); + set_scope_to_global(); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + yyrename = Copy(Getattr($<node>$, "class_rename")); + add_symbols($$); + if (!cparse_cplusplusout) + Delattr($$, "nested:outer"); + Delattr($$, "class_rename"); + $$ = 0; + } else { + yyrename = Copy(Getattr($<node>$, "class_rename")); + add_symbols($$); + add_symbols($9); + Delattr($$, "class_rename"); + } } + Delete(ty); Swig_symbol_setscope(cscope); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); - } else { - $$ = new_node("class"); - Setattr($$,"kind",$2); - Setattr($$,"name",NewString($3)); - SetFlag($$,"nestedtemplateclass"); - } } /* An unnamed struct, possibly with a typedef */ - | storage_class cpptype LBRACE { + | storage_class cpptype inherit LBRACE { String *unnamed; + String *code; unnamed = make_unnamed(); $<node>$ = new_node("class"); Setline($<node>$,cparse_start_line); Setattr($<node>$,"kind",$2); + if ($3) { + Setattr($<node>$,"baselist", Getattr($3,"public")); + Setattr($<node>$,"protectedbaselist", Getattr($3,"protected")); + Setattr($<node>$,"privatebaselist", Getattr($3,"private")); + } Setattr($<node>$,"storage",$1); Setattr($<node>$,"unnamed",unnamed); Setattr($<node>$,"allows_typedef","1"); - Delete(class_rename); - class_rename = make_name($<node>$,0,0); + if (currentOuterClass) { + SetFlag($<node>$, "nested"); + Setattr($<node>$, "nested:outer", currentOuterClass); + set_access_mode($<node>$); + } + Setattr($<node>$, "class_rename", make_name($<node>$,0,0)); if (strcmp($2,"class") == 0) { cplus_mode = CPLUS_PRIVATE; } else { @@ -3969,108 +3626,111 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE { } Swig_symbol_newscope(); cparse_start_line = cparse_line; - if (class_level >= max_class_levels) { - if (!max_class_levels) { - max_class_levels = 16; - } else { - max_class_levels *= 2; - } - class_decl = (Node**) realloc(class_decl, sizeof(Node*) * max_class_levels); - if (!class_decl) { - Swig_error(cparse_file, cparse_line, "realloc() failed\n"); - } - } - class_decl[class_level++] = $<node>$; + currentOuterClass = $<node>$; inclass = 1; Classprefix = NewStringEmpty(); Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); - } cpp_members RBRACE declarator initializer c_decl_tail { + /* save the structure declaration to make a typedef for it later*/ + code = get_raw_text_balanced('{', '}'); + Setattr($<node>$, "code", code); + Delete(code); + } cpp_members RBRACE cpp_opt_declarators { String *unnamed; + List *bases = 0; + String *name = 0; Node *n; - (void) $<node>4; Classprefix = 0; - $$ = class_decl[--class_level]; - inclass = 0; + $$ = currentOuterClass; + currentOuterClass = Getattr($$, "nested:outer"); + if (!currentOuterClass) + inclass = 0; + else + restore_access_mode($$); unnamed = Getattr($$,"unnamed"); - - /* Check for pure-abstract class */ - Setattr($$,"abstracts", pure_abstracts($5)); - - n = new_node("cdecl"); - Setattr(n,"name",$7.id); - Setattr(n,"unnamed",unnamed); - Setattr(n,"type",unnamed); - Setattr(n,"decl",$7.type); - Setattr(n,"parms",$7.parms); - Setattr(n,"storage",$1); - if ($9) { - Node *p = $9; - set_nextSibling(n,p); - while (p) { - String *type = Copy(unnamed); - Setattr(p,"name",$7.id); - Setattr(p,"unnamed",unnamed); - Setattr(p,"type",type); - Delete(type); - Setattr(p,"storage",$1); - p = nextSibling(p); - } - } - set_nextSibling($$,n); - Delete(n); - { + /* Check for pure-abstract class */ + Setattr($$,"abstracts", pure_abstracts($6)); + n = $8; + if (n) { + appendSibling($$,n); /* If a proper typedef name was given, we'll use it to set the scope name */ - String *name = 0; - if ($1 && (strcmp($1,"typedef") == 0)) { - if (!Len($7.type)) { - String *scpname = 0; - name = $7.id; - Setattr($$,"tdname",name); - Setattr($$,"name",name); - Swig_symbol_setscopename(name); + name = try_to_find_a_name_for_unnamed_structure($1, n); + if (name) { + String *scpname = 0; + SwigType *ty; + Setattr($$,"tdname",name); + Setattr($$,"name",name); + Swig_symbol_setscopename(name); + if ($3) + bases = Swig_make_inherit_list(name,Getattr($3,"public"),Namespaceprefix); + Swig_inherit_base_symbols(bases); /* If a proper name was given, we use that as the typedef, not unnamed */ - Clear(unnamed); - Append(unnamed, name); - + Clear(unnamed); + Append(unnamed, name); + if (cparse_cplusplus && !cparse_externc) { + ty = NewString(name); + } else { + ty = NewStringf("%s %s", $2,name); + } + while (n) { + Setattr(n,"storage",$1); + Setattr(n, "type", ty); + if (!cparse_cplusplus && currentOuterClass && (!Getattr(currentOuterClass, "name"))) { + SetFlag(n,"hasconsttype"); + SetFlag(n,"feature:immutable"); + } n = nextSibling(n); - set_nextSibling($$,n); - + } + n = $8; /* Check for previous extensions */ - if (extendhash) { - String *clsname = Swig_symbol_qualifiedscopename(0); - Node *am = Getattr(extendhash,clsname); - if (am) { + if (extendhash) { + String *clsname = Swig_symbol_qualifiedscopename(0); + Node *am = Getattr(extendhash,clsname); + if (am) { /* Merge the extension into the symbol table */ - merge_extensions($$,am); - append_previous_extension($$,am); - Delattr(extendhash,clsname); - } - Delete(clsname); + merge_extensions($$,am); + append_previous_extension($$,am); + Delattr(extendhash,clsname); } - if (!classes) classes = NewHash(); - scpname = Swig_symbol_qualifiedscopename(0); - Setattr(classes,scpname,$$); - Delete(scpname); - } else { - Swig_symbol_setscopename("<unnamed>"); + Delete(clsname); + } + if (!classes) classes = NewHash(); + scpname = Swig_symbol_qualifiedscopename(0); + Setattr(classes,scpname,$$); + Delete(scpname); + } else { /* no suitable name was found for a struct */ + Setattr($$, "nested:unnamed", Getattr(n, "name")); /* save the name of the first declarator for later use in name generation*/ + while (n) { /* attach unnamed struct to the declarators, so that they would receive proper type later*/ + Setattr(n, "nested:unnamedtype", $$); + Setattr(n, "storage", $1); + n = nextSibling(n); } + n = $8; + Swig_symbol_setscopename("<unnamed>"); } - appendChild($$,$5); - appendChild($$,dump_nested(Char(name))); - } - /* Pop the scope */ - Setattr($$,"symtab",Swig_symbol_popscope()); - if (class_rename) { - Delete(yyrename); - yyrename = NewString(class_rename); + appendChild($$,$6); + /* Pop the scope */ + Setattr($$,"symtab",Swig_symbol_popscope()); + if (name) { + Delete(yyrename); + yyrename = Copy(Getattr($<node>$, "class_rename")); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols($$); + add_symbols(n); + Delattr($$, "class_rename"); + }else if (cparse_cplusplus) + $$ = 0; /* ignore unnamed structs for C++ */ + Delete(unnamed); + } else { /* unnamed struct w/o declarator*/ + Swig_symbol_popscope(); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols($6); + Delete($$); + $$ = $6; /* pass member list to outer class/namespace (instead of self)*/ } - Delete(Namespaceprefix); - Namespaceprefix = Swig_symbol_qualifiedscopename(0); - add_symbols($$); - add_symbols(n); - Delete(unnamed); } ; @@ -4106,41 +3766,10 @@ cpp_forward_class_decl : storage_class cpptype idcolon SEMI { ------------------------------------------------------------ */ cpp_template_decl : TEMPLATE LESSTHAN template_parms GREATERTHAN { + if (currentOuterClass) + Setattr(currentOuterClass, "template_parameters", template_parameters); template_parameters = $3; - if (inclass) - nested_template++; - } cpp_temp_possible { - - /* Don't ignore templated functions declared within a class, unless the templated function is within a nested class */ - if (nested_template <= 1) { - int is_nested_template_class = $6 && GetFlag($6, "nestedtemplateclass"); - if (is_nested_template_class) { - $$ = 0; - /* Nested template classes would probably better be ignored like ordinary nested classes using cpp_nested, but that introduces shift/reduce conflicts */ - if (cplus_mode == CPLUS_PUBLIC) { - /* Treat the nested class/struct/union as a forward declaration until a proper nested class solution is implemented */ - String *kind = Getattr($6, "kind"); - String *name = Getattr($6, "name"); - $$ = new_node("template"); - Setattr($$,"kind",kind); - Setattr($$,"name",name); - Setattr($$,"sym:weak", "1"); - Setattr($$,"templatetype","classforward"); - Setattr($$,"templateparms", $3); - add_symbols($$); - - if (GetFlag($$, "feature:nestedworkaround")) { - Swig_symbol_remove($$); - $$ = 0; - } else { - SWIG_WARN_NODE_BEGIN($$); - Swig_warning(WARN_PARSE_NAMED_NESTED_CLASS, cparse_file, cparse_line, "Nested template %s not currently supported (%s ignored).\n", kind, name); - SWIG_WARN_NODE_END($$); - } - } - Delete($6); - } else { String *tname = 0; int error = 0; @@ -4386,13 +4015,10 @@ cpp_template_decl : TEMPLATE LESSTHAN template_parms GREATERTHAN { Delete(Namespaceprefix); Namespaceprefix = Swig_symbol_qualifiedscopename(0); if (error) $$ = 0; - } - } else { - $$ = 0; - } - template_parameters = 0; - if (inclass) - nested_template--; + if (currentOuterClass) + template_parameters = Getattr(currentOuterClass, "template_parameters"); + else + template_parameters = 0; } /* Explicit template instantiation */ @@ -4621,6 +4247,8 @@ cpp_members : cpp_member cpp_members { p = nextSibling(p); } set_nextSibling(pp,$2); + if ($2) + set_previousSibling($2, pp); } else { $$ = $2; } @@ -4656,7 +4284,7 @@ cpp_members : cpp_member cpp_members { cpp_member : c_declaration { $$ = $1; } | cpp_constructor_decl { $$ = $1; - if (extendmode) { + if (extendmode && current_class) { String *symname; symname= make_name($$,Getattr($$,"name"), Getattr($$,"decl")); if (Strcmp(symname,Getattr($$,"name")) == 0) { @@ -4677,7 +4305,7 @@ cpp_member : c_declaration { $$ = $1; } | cpp_swig_directive { $$ = $1; } | cpp_conversion_operator { $$ = $1; } | cpp_forward_class_decl { $$ = $1; } - | cpp_nested { $$ = $1; } + | cpp_class_decl { $$ = $1; } | storage_class idcolon SEMI { $$ = 0; } | cpp_using_decl { $$ = $1; } | cpp_template_decl { $$ = $1; } @@ -4697,7 +4325,7 @@ cpp_member : c_declaration { $$ = $1; } */ cpp_constructor_decl : storage_class type LPAREN parms RPAREN ctor_end { - if (Classprefix) { + if (inclass || extendmode) { SwigType *decl = NewStringEmpty(); $$ = new_node("constructor"); Setattr($$,"storage",$1); @@ -4905,82 +4533,6 @@ cpp_protection_decl : PUBLIC COLON { cplus_mode = CPLUS_PROTECTED; } ; - - -/* ------------------------------------------------------------ - Named nested structs: - struct sname { }; - struct sname { } id; - struct sname : bases { }; - struct sname : bases { } id; - typedef sname struct { } td; - typedef sname struct : bases { } td; - - Adding inheritance, ie replacing 'ID' with 'idcolon inherit' - added one shift/reduce - ------------------------------------------------------------ */ - -cpp_nested : storage_class cpptype idcolon inherit LBRACE { - cparse_start_line = cparse_line; - skip_balanced('{','}'); - $<str>$ = NewString(scanner_ccode); /* copied as initializers overwrite scanner_ccode */ - } cpp_opt_declarators { - $$ = 0; - if (cplus_mode == CPLUS_PUBLIC) { - if (cparse_cplusplus) { - String *name = Copy($3); - $$ = nested_forward_declaration($1, $2, $3, name, $7); - } else if ($7) { - nested_new_struct($2, $<str>6, $7); - } - } - Delete($<str>6); - } - -/* ------------------------------------------------------------ - Unnamed/anonymous nested structs: - struct { }; - struct { } id; - struct : bases { }; - struct : bases { } id; - typedef struct { } td; - typedef struct : bases { } td; - ------------------------------------------------------------ */ - - | storage_class cpptype inherit LBRACE { - cparse_start_line = cparse_line; - skip_balanced('{','}'); - $<str>$ = NewString(scanner_ccode); /* copied as initializers overwrite scanner_ccode */ - } cpp_opt_declarators { - $$ = 0; - if (cplus_mode == CPLUS_PUBLIC) { - if (cparse_cplusplus) { - String *name = $6 ? Copy(Getattr($6, "name")) : 0; - $$ = nested_forward_declaration($1, $2, 0, name, $6); - } else { - if ($6) { - nested_new_struct($2, $<str>5, $6); - } else { - Swig_warning(WARN_PARSE_UNNAMED_NESTED_CLASS, cparse_file, cparse_line, "Nested %s not currently supported (ignored).\n", $2); - } - } - } - Delete($<str>5); - } - - -/* This unfortunately introduces 4 shift/reduce conflicts, so instead the somewhat hacky nested_template is used for ignore nested template classes. */ -/* - | TEMPLATE LESSTHAN template_parms GREATERTHAN cpptype idcolon LBRACE { cparse_start_line = cparse_line; skip_balanced('{','}'); - } SEMI { - $$ = 0; - if (cplus_mode == CPLUS_PUBLIC) { - Swig_warning(WARN_PARSE_NAMED_NESTED_CLASS, cparse_file, cparse_line,"Nested %s not currently supported (%s ignored)\n", $5, $6); - } - } -*/ - ; - /* These directives can be included inside a class definition */ cpp_swig_directive: pragma_directive { $$ = $1; } diff --git a/Source/Include/swigwarn.h b/Source/Include/swigwarn.h index 65ff70dd9..ea1cf7fe4 100644 --- a/Source/Include/swigwarn.h +++ b/Source/Include/swigwarn.h @@ -52,6 +52,7 @@ #define WARN_DEPRECATED_NODEFAULT 123 #define WARN_DEPRECATED_TYPEMAP_LANG 124 #define WARN_DEPRECATED_INPUT_FILE 125 +#define WARN_DEPRECATED_NESTED_WORKAROUND 126 /* -- Preprocessor -- */ @@ -75,7 +76,6 @@ #define WARN_PARSE_PRIVATE_INHERIT 309 #define WARN_PARSE_TEMPLATE_REPEAT 310 #define WARN_PARSE_TEMPLATE_PARTIAL 311 -#define WARN_PARSE_UNNAMED_NESTED_CLASS 312 #define WARN_PARSE_UNDEFINED_EXTERN 313 #define WARN_PARSE_KEYWORD 314 #define WARN_PARSE_USING_UNDEF 315 @@ -88,7 +88,6 @@ #define WARN_PARSE_REDUNDANT 322 #define WARN_PARSE_REC_INHERITANCE 323 #define WARN_PARSE_NESTED_TEMPLATE 324 -#define WARN_PARSE_NAMED_NESTED_CLASS 325 #define WARN_PARSE_EXTEND_NAME 326 #define WARN_CPP11_LAMBDA 340 diff --git a/Source/Makefile.am b/Source/Makefile.am index 0c28a95b6..49d571236 100644 --- a/Source/Makefile.am +++ b/Source/Makefile.am @@ -54,6 +54,7 @@ eswig_SOURCES = CParse/cscanner.c \ Modules/modula3.cxx \ Modules/module.cxx \ Modules/mzscheme.cxx \ + Modules/nested.cxx \ Modules/ocaml.cxx \ Modules/octave.cxx \ Modules/overload.cxx \ diff --git a/Source/Modules/allocate.cxx b/Source/Modules/allocate.cxx index b7daae59c..7f1d13678 100644 --- a/Source/Modules/allocate.cxx +++ b/Source/Modules/allocate.cxx @@ -559,6 +559,8 @@ Allocate(): virtual int classDeclaration(Node *n) { Symtab *symtab = Swig_symbol_current(); Swig_symbol_setscope(Getattr(n, "symtab")); + Node *oldInclass = inclass; + AccessMode oldAcessMode = cplus_mode; if (!CPlusPlus) { /* Always have default constructors/destructors in C */ @@ -580,7 +582,6 @@ Allocate(): } } } - inclass = n; String *kind = Getattr(n, "kind"); if (Strcmp(kind, "class") == 0) { @@ -728,7 +729,8 @@ Allocate(): /* Only care about default behavior. Remove temporary values */ Setattr(n, "allocate:visit", "1"); - inclass = 0; + inclass = oldInclass; + cplus_mode = oldAcessMode; Swig_symbol_setscope(symtab); return SWIG_OK; } diff --git a/Source/Modules/contract.cxx b/Source/Modules/contract.cxx index ffd799cfd..7e0eaf9e0 100644 --- a/Source/Modules/contract.cxx +++ b/Source/Modules/contract.cxx @@ -342,11 +342,13 @@ int Contracts::namespaceDeclaration(Node *n) { int Contracts::classDeclaration(Node *n) { int ret = SWIG_OK; + int oldInClass = InClass; + Node *oldClass = CurrentClass; InClass = 1; CurrentClass = n; emit_children(n); - InClass = 0; - CurrentClass = 0; + InClass = oldInClass; + CurrentClass = oldClass; return ret; } diff --git a/Source/Modules/csharp.cxx b/Source/Modules/csharp.cxx index 6b9219750..9197b4b17 100644 --- a/Source/Modules/csharp.cxx +++ b/Source/Modules/csharp.cxx @@ -53,7 +53,6 @@ class CSHARP:public Language { String *proxy_class_code; String *module_class_code; String *proxy_class_name; // proxy class name - String *full_proxy_class_name;// fully qualified proxy class name when using nspace feature, otherwise same as proxy_class_name String *full_imclass_name; // fully qualified intermediary class name when using nspace feature, otherwise same as imclass_name String *variable_name; //Name of a variable being wrapped String *proxy_class_constants_code; @@ -87,6 +86,7 @@ class CSHARP:public Language { int n_directors; int first_class_dmethod; int curr_class_dmethod; + int nesting_depth; enum EnumFeature { SimpleEnum, TypeunsafeEnum, TypesafeEnum, ProperEnum }; @@ -125,7 +125,6 @@ public: proxy_class_code(NULL), module_class_code(NULL), proxy_class_name(NULL), - full_proxy_class_name(NULL), full_imclass_name(NULL), variable_name(NULL), proxy_class_constants_code(NULL), @@ -156,7 +155,8 @@ public: n_dmethods(0), n_directors(0), first_class_dmethod(0), - curr_class_dmethod(0) { + curr_class_dmethod(0), + nesting_depth(0){ /* for now, multiple inheritance in directors is disabled, this should be easy to implement though */ director_multiple_inheritance = 0; @@ -179,7 +179,13 @@ public: proxyname = Getattr(n, "proxyname"); if (!proxyname) { String *nspace = Getattr(n, "sym:nspace"); - String *symname = Getattr(n, "sym:name"); + String *symname = Copy(Getattr(n, "sym:name")); + if (symname && !GetFlag(n, "feature:flatnested")) { + for (Node *outer_class = Getattr(n, "nested:outer"); outer_class; outer_class = Getattr(outer_class, "nested:outer")) { + Push(symname, "."); + Push(symname, Getattr(outer_class, "sym:name")); + } + } if (nspace) { if (namespce) proxyname = NewStringf("%s.%s.%s", namespce, nspace, symname); @@ -190,12 +196,33 @@ public: } Setattr(n, "proxyname", proxyname); Delete(proxyname); + Delete(symname); } } } return proxyname; } + /* ----------------------------------------------------------------------------- + * directorClassName() + * ----------------------------------------------------------------------------- */ + + String *directorClassName(Node *n) { + String *dirclassname; + const char *attrib = "director:classname"; + + if (!(dirclassname = Getattr(n, attrib))) { + String *classname = getClassPrefix(); + + dirclassname = NewStringf("SwigDirector_%s", classname); + Setattr(n, attrib, dirclassname); + } + else + dirclassname = Copy(dirclassname); + + return dirclassname; + } + /* ------------------------------------------------------------ * main() * ------------------------------------------------------------ */ @@ -1025,7 +1052,7 @@ public: */ if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { // Capitalize the first letter in the variable in the getter/setter function name - bool getter_flag = Cmp(symname, Swig_name_set(getNSpace(), Swig_name_member(0, proxy_class_name, variable_name))) != 0; + bool getter_flag = Cmp(symname, Swig_name_set(getNSpace(), Swig_name_member(0, getClassPrefix(), variable_name))) != 0; String *getter_setter_name = NewString(""); if (!getter_flag) @@ -1589,6 +1616,7 @@ public: String *c_baseclassname = NULL; SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); bool feature_director = Swig_directorclass(n) ? true : false; + bool has_outerclass = Getattr(n, "nested:outer") != 0 && !GetFlag(n, "feature:flatnested"); // Inheritance from pure C# classes Node *attributes = NewHash(); @@ -1648,7 +1676,8 @@ public: // Pure C# interfaces const String *pure_interfaces = typemapLookup(n, derived ? "csinterfaces_derived" : "csinterfaces", typemap_lookup_type, WARN_NONE); // Start writing the proxy class - Printv(proxy_class_def, typemapLookup(n, "csimports", typemap_lookup_type, WARN_NONE), // Import statements + if (!has_outerclass) + Printv(proxy_class_def, typemapLookup(n, "csimports", typemap_lookup_type, WARN_NONE), // Import statements "\n", NIL); // Class attributes @@ -1719,7 +1748,7 @@ public: Printf(proxy_class_code, " if (SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s))\n", method, methid); Printf(proxy_class_code, " swigDelegate%s = new SwigDelegate%s_%s(SwigDirector%s);\n", methid, proxy_class_name, methid, overname); } - String *director_connect_method_name = Swig_name_member(getNSpace(), proxy_class_name, "director_connect"); + String *director_connect_method_name = Swig_name_member(getNSpace(), getClassPrefix(), "director_connect"); Printf(proxy_class_code, " %s.%s(swigCPtr", imclass_name, director_connect_method_name); for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { UpcallData *udata = Getitem(dmethods_seq, i); @@ -1795,7 +1824,7 @@ public: // Add code to do C++ casting to base class (only for classes in an inheritance hierarchy) if (derived) { String *smartptr = Getattr(n, "feature:smartptr"); - String *upcast_method = Swig_name_member(getNSpace(), proxy_class_name, smartptr != 0 ? "SWIGSmartPtrUpcast" : "SWIGUpcast"); + String *upcast_method = Swig_name_member(getNSpace(), getClassPrefix(), smartptr != 0 ? "SWIGSmartPtrUpcast" : "SWIGUpcast"); String *wname = Swig_name_wrapper(upcast_method); Printv(imclass_cppcasts_code, "\n [global::System.Runtime.InteropServices.DllImport(\"", dllimport, "\", EntryPoint=\"", wname, "\")]\n", NIL); @@ -1846,11 +1875,35 @@ public: String *nspace = getNSpace(); File *f_proxy = NULL; + // save class local variables + String *old_proxy_class_name = proxy_class_name; + String *old_full_imclass_name = full_imclass_name; + String *old_destructor_call = destructor_call; + String *old_proxy_class_constants_code = proxy_class_constants_code; + String *old_proxy_class_def = proxy_class_def; + String *old_proxy_class_code = proxy_class_code; + if (proxy_flag) { proxy_class_name = NewString(Getattr(n, "sym:name")); + if (Node *outer = Getattr(n, "nested:outer")) { + String *outerClassesPrefix = Copy(Getattr(outer, "sym:name")); + for (outer = Getattr(outer, "nested:outer"); outer != 0; outer = Getattr(outer, "nested:outer")) { + Push(outerClassesPrefix, "::"); + Push(outerClassesPrefix, Getattr(outer, "sym:name")); + } + String *fnspace = nspace ? NewStringf("%s::%s", nspace, outerClassesPrefix) : outerClassesPrefix; + if (!addSymbol(proxy_class_name, n, fnspace)) + return SWIG_ERROR; + if (nspace) + Delete(fnspace); + Delete(outerClassesPrefix); + } + else { + if (!addSymbol(proxy_class_name, n, nspace)) + return SWIG_ERROR; + } if (!nspace) { - full_proxy_class_name = NewStringf("%s", proxy_class_name); full_imclass_name = NewStringf("%s", imclass_name); if (Cmp(proxy_class_name, imclass_name) == 0) { Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name); @@ -1863,36 +1916,34 @@ public: } } else { if (namespce) { - full_proxy_class_name = NewStringf("%s.%s.%s", namespce, nspace, proxy_class_name); full_imclass_name = NewStringf("%s.%s", namespce, imclass_name); } else { - full_proxy_class_name = NewStringf("%s.%s", nspace, proxy_class_name); full_imclass_name = NewStringf("%s", imclass_name); } } - if (!addSymbol(proxy_class_name, n, nspace)) - return SWIG_ERROR; - - String *output_directory = outputDirectory(nspace); - String *filen = NewStringf("%s%s.cs", output_directory, proxy_class_name); - f_proxy = NewFile(filen, "w", SWIG_output_files()); - if (!f_proxy) { - FileErrorDisplay(filen); - SWIG_exit(EXIT_FAILURE); - } - Append(filenames_list, Copy(filen)); - Delete(filen); - filen = NULL; - - // Start writing out the proxy class file - emitBanner(f_proxy); - - addOpenNamespace(nspace, f_proxy); + // inner class doesn't need this prologue + if (!Getattr(n, "nested:outer")) { + String *output_directory = outputDirectory(nspace); + String *filen = NewStringf("%s%s.cs", output_directory, proxy_class_name); + f_proxy = NewFile(filen, "w", SWIG_output_files()); + if (!f_proxy) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; - Clear(proxy_class_def); - Clear(proxy_class_code); + // Start writing out the proxy class file + emitBanner(f_proxy); + addOpenNamespace(nspace, f_proxy); + } + else + ++nesting_depth; + proxy_class_def = NewString(""); + proxy_class_code = NewString(""); destructor_call = NewString(""); proxy_class_constants_code = NewString(""); } @@ -1903,7 +1954,7 @@ public: emitProxyClassDefAndCPPCasts(n); - String *csclazzname = Swig_name_member(getNSpace(), proxy_class_name, ""); // mangled full proxy class name + String *csclazzname = Swig_name_member(getNSpace(), getClassPrefix(), ""); // mangled full proxy class name Replaceall(proxy_class_def, "$csclassname", proxy_class_name); Replaceall(proxy_class_code, "$csclassname", proxy_class_name); @@ -1924,17 +1975,36 @@ public: Replaceall(proxy_class_def, "$dllimport", dllimport); Replaceall(proxy_class_code, "$dllimport", dllimport); Replaceall(proxy_class_constants_code, "$dllimport", dllimport); - - Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + bool has_outerclass = Getattr(n, "nested:outer") != 0 && !GetFlag(n, "feature:flatnested"); + if (!has_outerclass) + Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + else { + Swig_offset_string(proxy_class_def, nesting_depth); + Append(old_proxy_class_code, proxy_class_def); + Swig_offset_string(proxy_class_code, nesting_depth); + Append(old_proxy_class_code, proxy_class_code); + } // Write out all the constants - if (Len(proxy_class_constants_code) != 0) - Printv(f_proxy, proxy_class_constants_code, NIL); - - Printf(f_proxy, "}\n"); - addCloseNamespace(nspace, f_proxy); - Delete(f_proxy); - f_proxy = NULL; + if (Len(proxy_class_constants_code) != 0) { + if (!has_outerclass) + Printv(f_proxy, proxy_class_constants_code, NIL); + else { + Swig_offset_string(proxy_class_constants_code, nesting_depth); + Append(old_proxy_class_code, proxy_class_constants_code); + } + } + if (!has_outerclass) { + Printf(f_proxy, "}\n"); + addCloseNamespace(nspace, f_proxy); + Delete(f_proxy); + f_proxy = NULL; + } else { + for (int i = 0; i < nesting_depth; ++i) + Append(old_proxy_class_code, " "); + Append(old_proxy_class_code, "}\n\n"); + --nesting_depth; + } /* Output the downcast method, if necessary. Note: There's no other really good place to put this code, since Abstract Base Classes (ABCs) can and should have @@ -1971,17 +2041,18 @@ public: Delete(csclazzname); Delete(proxy_class_name); - proxy_class_name = NULL; - Delete(full_proxy_class_name); - full_proxy_class_name = NULL; + proxy_class_name = old_proxy_class_name; Delete(full_imclass_name); - full_imclass_name = NULL; + full_imclass_name = old_full_imclass_name; Delete(destructor_call); - destructor_call = NULL; + destructor_call = old_destructor_call; Delete(proxy_class_constants_code); - proxy_class_constants_code = NULL; + proxy_class_constants_code = old_proxy_class_constants_code; + Delete(proxy_class_def); + proxy_class_def = old_proxy_class_def; + Delete(proxy_class_code); + proxy_class_code = old_proxy_class_code; } - return SWIG_OK; } @@ -1994,7 +2065,7 @@ public: if (proxy_flag) { String *overloaded_name = getOverloadedName(n); - String *intermediary_function_name = Swig_name_member(getNSpace(), proxy_class_name, overloaded_name); + String *intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name); Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); Setattr(n, "imfuncname", intermediary_function_name); proxyClassFunctionHandler(n); @@ -2014,7 +2085,7 @@ public: if (proxy_flag) { String *overloaded_name = getOverloadedName(n); - String *intermediary_function_name = Swig_name_member(getNSpace(), proxy_class_name, overloaded_name); + String *intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name); Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); Setattr(n, "imfuncname", intermediary_function_name); proxyClassFunctionHandler(n); @@ -2094,7 +2165,7 @@ public: if (wrapping_member_flag && !enum_constant_flag) { // Properties - setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), Swig_name_member(0, proxy_class_name, variable_name))) == 0); + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), Swig_name_member(0, getClassPrefix(), variable_name))) == 0); if (setter_flag) Swig_typemap_attach_parms("csvarin", l, NULL); } @@ -2264,7 +2335,7 @@ public: Node *explicit_n = Getattr(n, "explicitcallnode"); if (explicit_n) { String *ex_overloaded_name = getOverloadedName(explicit_n); - String *ex_intermediary_function_name = Swig_name_member(getNSpace(), proxy_class_name, ex_overloaded_name); + String *ex_intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), ex_overloaded_name); String *ex_imcall = Copy(imcall); Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); @@ -3376,14 +3447,21 @@ public: // Output the director connect method: String *norm_name = SwigType_namestr(Getattr(n, "name")); - String *swig_director_connect = Swig_name_member(getNSpace(), proxy_class_name, "director_connect"); + String *dirclassname = directorClassName(n); + String *swig_director_connect = Swig_name_member(getNSpace(), getClassPrefix(), "director_connect"); String *wname = Swig_name_wrapper(swig_director_connect); String *sym_name = Getattr(n, "sym:name"); String *qualified_classname = Copy(sym_name); String *nspace = getNSpace(); String *dirClassName = directorClassName(n); String *smartptr = Getattr(n, "feature:smartptr"); + if (!GetFlag(n, "feature:flatnested")) { + for (Node *outer_class = Getattr(n, "nested:outer"); outer_class; outer_class = Getattr(outer_class, "nested:outer")) { + Push(qualified_classname, "."); + Push(qualified_classname, Getattr(outer_class, "sym:name")); + } + } if (nspace) Insert(qualified_classname, 0, NewStringf("%s.", nspace)); @@ -3415,7 +3493,7 @@ public: Printf(code_wrap->def, ", "); if (i != first_class_dmethod) Printf(code_wrap->code, ", "); - Printf(code_wrap->def, "%s::SWIG_Callback%s_t callback%s", dirClassName, methid, methid); + Printf(code_wrap->def, "%s::SWIG_Callback%s_t callback%s", dirclassname, methid, methid); Printf(code_wrap->code, "callback%s", methid); Printf(imclass_class_code, ", %s.SwigDelegate%s_%s delegate%s", qualified_classname, sym_name, methid, methid); } @@ -3432,7 +3510,7 @@ public: Delete(wname); Delete(swig_director_connect); Delete(qualified_classname); - Delete(dirClassName); + Delete(dirclassname); } /* --------------------------------------------------------------- @@ -3485,7 +3563,7 @@ public: // we're consistent with the sym:overload name in functionWrapper. (?? when // does the overloaded method name get set?) - imclass_dmethod = NewStringf("SwigDirector_%s", Swig_name_member(getNSpace(), classname, overloaded_name)); + imclass_dmethod = NewStringf("SwigDirector_%s", Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name)); qualified_return = SwigType_rcaststr(returntype, "c_result"); @@ -3931,6 +4009,7 @@ public: Delete(proxy_method_types); Delete(callback_def); Delete(callback_code); + Delete(dirclassname); DelWrapper(w); return status; @@ -3970,13 +4049,11 @@ public: String *basetype = Getattr(parent, "classtype"); String *target = Swig_method_decl(0, decl, dirclassname, parms, 0, 0); String *call = Swig_csuperclass_call(0, basetype, superparms); - String *classtype = SwigType_namestr(Getattr(n, "name")); Printf(f_directors, "%s::%s : %s, %s {\n", dirclassname, target, call, Getattr(parent, "director:ctor")); Printf(f_directors, " swig_init_callbacks();\n"); Printf(f_directors, "}\n\n"); - Delete(classtype); Delete(target); Delete(call); } @@ -4047,6 +4124,29 @@ public: return Language::classDirectorInit(n); } + int classDeclaration(Node *n) { + String *old_director_callback_typedefs = director_callback_typedefs; + String *old_director_callbacks = director_callbacks; + String *old_director_delegate_callback = director_delegate_callback; + String *old_director_delegate_definitions = director_delegate_definitions; + String *old_director_delegate_instances = director_delegate_instances; + String *old_director_method_types = director_method_types; + String *old_director_connect_parms = director_connect_parms; + + int ret = Language::classDeclaration(n); + + // these variables are deleted in emitProxyClassDefAndCPPCasts, hence no Delete here + director_callback_typedefs = old_director_callback_typedefs; + director_callbacks = old_director_callbacks; + director_delegate_callback = old_director_delegate_callback; + director_delegate_definitions = old_director_delegate_definitions; + director_delegate_instances = old_director_delegate_instances; + director_method_types = old_director_method_types; + director_connect_parms = old_director_connect_parms; + + return ret; + } + /* ---------------------------------------------------------------------- * classDirectorDestructor() * ---------------------------------------------------------------------- */ @@ -4079,7 +4179,7 @@ public: int classDirectorEnd(Node *n) { int i; - String *director_classname = directorClassName(n); + String *dirclassname = directorClassName(n); Wrapper *w = NewWrapper(); @@ -4089,7 +4189,7 @@ public: Printf(f_directors_h, " void swig_connect_director("); - Printf(w->def, "void %s::swig_connect_director(", director_classname); + Printf(w->def, "void %s::swig_connect_director(", dirclassname); for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { UpcallData *udata = Getitem(dmethods_seq, i); @@ -4116,7 +4216,7 @@ public: Printf(f_directors_h, "};\n\n"); Printf(w->code, "}\n\n"); - Printf(w->code, "void %s::swig_init_callbacks() {\n", director_classname); + Printf(w->code, "void %s::swig_init_callbacks() {\n", dirclassname); for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { UpcallData *udata = Getitem(dmethods_seq, i); String *overname = Getattr(udata, "overname"); @@ -4127,6 +4227,7 @@ public: Wrapper_print(w, f_directors); DelWrapper(w); + Delete(dirclassname); return Language::classDirectorEnd(n); } @@ -4159,8 +4260,8 @@ public: String *base = Getattr(n, "classtype"); String *class_ctor = NewString("Swig::Director()"); - String *directorname = directorClassName(n); - String *declaration = Swig_class_declaration(n, directorname); + String *dirclassname = directorClassName(n); + String *declaration = Swig_class_declaration(n, dirclassname); Printf(declaration, " : public %s, public Swig::Director", base); @@ -4168,9 +4269,12 @@ public: Setattr(n, "director:decl", declaration); Setattr(n, "director:ctor", class_ctor); - Delete(directorname); + Delete(dirclassname); } + bool nestedClassesSupported() const { + return true; + } }; /* class CSHARP */ /* ----------------------------------------------------------------------------- diff --git a/Source/Modules/java.cxx b/Source/Modules/java.cxx index 6576ad544..fdc678dbf 100644 --- a/Source/Modules/java.cxx +++ b/Source/Modules/java.cxx @@ -86,6 +86,7 @@ class JAVA:public Language { int n_directors; int first_class_dmethod; int curr_class_dmethod; + int nesting_depth; enum EnumFeature { SimpleEnum, TypeunsafeEnum, TypesafeEnum, ProperEnum }; @@ -154,7 +155,8 @@ public: n_dmethods(0), n_directors(0), first_class_dmethod(0), - curr_class_dmethod(0) { + curr_class_dmethod(0), + nesting_depth(0){ /* for now, multiple inheritance in directors is disabled, this should be easy to implement though */ director_multiple_inheritance = 0; @@ -204,7 +206,13 @@ public: proxyname = Getattr(n, "proxyname"); if (!proxyname || jnidescriptor) { String *nspace = Getattr(n, "sym:nspace"); - String *symname = Getattr(n, "sym:name"); + String *symname = Copy(Getattr(n, "sym:name")); + if (symname && !GetFlag(n, "feature:flatnested")) { + for (Node *outer_class = Getattr(n, "nested:outer"); outer_class; outer_class = Getattr(outer_class, "nested:outer")) { + Push(symname, "."); + Push(symname, Getattr(outer_class, "sym:name")); + } + } if (nspace) { if (package && !jnidescriptor) proxyname = NewStringf("%s.%s.%s", package, nspace, symname); @@ -217,6 +225,7 @@ public: Setattr(n, "proxyname", proxyname); // Cache it Delete(proxyname); } + Delete(symname); } } } @@ -1134,7 +1143,7 @@ public: */ if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { // Capitalize the first letter in the variable to create a JavaBean type getter/setter function name - bool getter_flag = Cmp(symname, Swig_name_set(getNSpace(), Swig_name_member(0, proxy_class_name, variable_name))) != 0; + bool getter_flag = Cmp(symname, Swig_name_set(getNSpace(), Swig_name_member(0, getClassPrefix(), variable_name))) != 0; String *getter_setter_name = NewString(""); if (!getter_flag) @@ -1713,6 +1722,7 @@ public: String *c_baseclassname = NULL; SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); bool feature_director = Swig_directorclass(n) ? true : false; + bool has_outerclass = Getattr(n, "nested:outer") != 0 && !GetFlag(n, "feature:flatnested"); // Inheritance from pure Java classes Node *attributes = NewHash(); @@ -1773,8 +1783,11 @@ public: const String *pure_interfaces = typemapLookup(n, "javainterfaces", typemap_lookup_type, WARN_NONE); // Start writing the proxy class - Printv(proxy_class_def, typemapLookup(n, "javaimports", typemap_lookup_type, WARN_NONE), // Import statements - "\n", typemapLookup(n, "javaclassmodifiers", typemap_lookup_type, WARN_JAVA_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + if (!has_outerclass) // Import statements + Printv(proxy_class_def, typemapLookup(n, "javaimports", typemap_lookup_type, WARN_NONE),"\n", NIL); + else + Printv(proxy_class_def, "static ", NIL); // C++ nested classes correspond to static java classes + Printv(proxy_class_def, typemapLookup(n, "javaclassmodifiers", typemap_lookup_type, WARN_JAVA_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers " $javaclassname", // Class name and bases (*Char(wanted_base)) ? " extends " : "", wanted_base, *Char(pure_interfaces) ? // Pure Java interfaces " implements " : "", pure_interfaces, " {", derived ? typemapLookup(n, "javabody_derived", typemap_lookup_type, WARN_JAVA_TYPEMAP_JAVABODY_UNDEF) : // main body of class @@ -1825,7 +1838,7 @@ public: /* Also insert the swigTakeOwnership and swigReleaseOwnership methods */ if (feature_director) { String *destruct_jnicall, *release_jnicall, *take_jnicall; - String *changeown_method_name = Swig_name_member(getNSpace(), proxy_class_name, "change_ownership"); + String *changeown_method_name = Swig_name_member(getNSpace(), getClassPrefix(), "change_ownership"); destruct_jnicall = NewStringf("%s()", destruct_methodname); release_jnicall = NewStringf("%s.%s(this, swigCPtr, false)", full_imclass_name, changeown_method_name); @@ -1851,7 +1864,7 @@ public: // Add code to do C++ casting to base class (only for classes in an inheritance hierarchy) if (derived) { String *smartptr = Getattr(n, "feature:smartptr"); - String *upcast_method = Swig_name_member(getNSpace(), proxy_class_name, smartptr != 0 ? "SWIGSmartPtrUpcast" : "SWIGUpcast"); + String *upcast_method = Swig_name_member(getNSpace(), getClassPrefix(), smartptr != 0 ? "SWIGSmartPtrUpcast" : "SWIGUpcast"); String *jniname = makeValidJniName(upcast_method); String *wname = Swig_name_wrapper(jniname); Printf(imclass_cppcasts_code, " public final static native long %s(long jarg1);\n", upcast_method); @@ -1908,13 +1921,29 @@ public: virtual int classHandler(Node *n) { File *f_proxy = NULL; + String *old_proxy_class_name = proxy_class_name; + String *old_full_proxy_class_name = full_proxy_class_name; + String *old_full_imclass_name = full_imclass_name; + String *old_destructor_call = destructor_call; + String *old_destructor_throws_clause = destructor_throws_clause; + String *old_proxy_class_constants_code = proxy_class_constants_code; + String *old_proxy_class_def = proxy_class_def; + String *old_proxy_class_code = proxy_class_code; if (proxy_flag) { proxy_class_name = NewString(Getattr(n, "sym:name")); String *nspace = getNSpace(); constructIntermediateClassName(n); + String *outerClassesPrefix = 0; + if (Node *outer = Getattr(n, "nested:outer")) { + outerClassesPrefix = Copy(Getattr(outer, "sym:name")); + for (outer = Getattr(outer, "nested:outer"); outer != 0; outer = Getattr(outer, "nested:outer")) { + Push(outerClassesPrefix, "."); + Push(outerClassesPrefix, Getattr(outer, "sym:name")); + } + } if (!nspace) { - full_proxy_class_name = NewStringf("%s", proxy_class_name); + full_proxy_class_name = outerClassesPrefix ? NewStringf("%s.%s", outerClassesPrefix, proxy_class_name) : NewStringf("%s", proxy_class_name); if (Cmp(proxy_class_name, imclass_name) == 0) { Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name); @@ -1926,54 +1955,73 @@ public: SWIG_exit(EXIT_FAILURE); } } else { - if (package) - full_proxy_class_name = NewStringf("%s.%s.%s", package, nspace, proxy_class_name); - else - full_proxy_class_name = NewStringf("%s.%s", nspace, proxy_class_name); + if (outerClassesPrefix) { + if (package) + full_proxy_class_name = NewStringf("%s.%s.%s.%s", package, nspace, outerClassesPrefix, proxy_class_name); + else + full_proxy_class_name = NewStringf("%s.%s.%s", nspace, outerClassesPrefix, proxy_class_name); + } else { + if (package) + full_proxy_class_name = NewStringf("%s.%s.%s", package, nspace, proxy_class_name); + else + full_proxy_class_name = NewStringf("%s.%s", nspace, proxy_class_name); + } } - if (!addSymbol(proxy_class_name, n, nspace)) - return SWIG_ERROR; - - String *output_directory = outputDirectory(nspace); - String *filen = NewStringf("%s%s.java", output_directory, proxy_class_name); - f_proxy = NewFile(filen, "w", SWIG_output_files()); - if (!f_proxy) { - FileErrorDisplay(filen); - SWIG_exit(EXIT_FAILURE); + if (outerClassesPrefix) { + Replaceall(outerClassesPrefix, ".", "::"); + String *fnspace = nspace ? NewStringf("%s::%s", nspace, outerClassesPrefix) : outerClassesPrefix; + if (!addSymbol(proxy_class_name, n, fnspace)) + return SWIG_ERROR; + if (nspace) + Delete(fnspace); + Delete(outerClassesPrefix); + } + else { + if (!addSymbol(proxy_class_name, n, nspace)) + return SWIG_ERROR; } - Append(filenames_list, Copy(filen)); - Delete(filen); - filen = NULL; - // Start writing out the proxy class file - emitBanner(f_proxy); + if (!Getattr(n, "nested:outer")) { + String *output_directory = outputDirectory(nspace); + String *filen = NewStringf("%s%s.java", output_directory, proxy_class_name); + f_proxy = NewFile(filen, "w", SWIG_output_files()); + if (!f_proxy) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + Delete(output_directory); - if (package || nspace) { - Printf(f_proxy, "package "); - if (package) - Printv(f_proxy, package, nspace ? "." : "", NIL); - if (nspace) - Printv(f_proxy, nspace, NIL); - Printf(f_proxy, ";\n"); - } + // Start writing out the proxy class file + emitBanner(f_proxy); - Clear(proxy_class_def); - Clear(proxy_class_code); + if (package || nspace) { + Printf(f_proxy, "package "); + if (package) + Printv(f_proxy, package, nspace ? "." : "", NIL); + if (nspace) + Printv(f_proxy, nspace, NIL); + Printf(f_proxy, ";\n"); + } + } + else + ++nesting_depth; + proxy_class_def = NewString(""); + proxy_class_code = NewString(""); destructor_call = NewString(""); destructor_throws_clause = NewString(""); proxy_class_constants_code = NewString(""); - Delete(output_directory); } - Language::classHandler(n); if (proxy_flag) { emitProxyClassDefAndCPPCasts(n); - String *javaclazzname = Swig_name_member(getNSpace(), proxy_class_name, ""); // mangled full proxy class name + String *javaclazzname = Swig_name_member(getNSpace(), getClassPrefix(), ""); // mangled full proxy class name Replaceall(proxy_class_def, "$javaclassname", proxy_class_name); Replaceall(proxy_class_code, "$javaclassname", proxy_class_name); @@ -1991,22 +2039,43 @@ public: Replaceall(proxy_class_code, "$imclassname", full_imclass_name); Replaceall(proxy_class_constants_code, "$imclassname", full_imclass_name); - Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + bool has_outerclass = Getattr(n, "nested:outer") != 0 && !GetFlag(n, "feature:flatnested"); + if (!has_outerclass) + Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + else { + Swig_offset_string(proxy_class_def, nesting_depth); + Append(old_proxy_class_code, proxy_class_def); + Swig_offset_string(proxy_class_code, nesting_depth); + Append(old_proxy_class_code, proxy_class_code); + } // Write out all the constants - if (Len(proxy_class_constants_code) != 0) - Printv(f_proxy, proxy_class_constants_code, NIL); + if (Len(proxy_class_constants_code) != 0) { + if (!has_outerclass) + Printv(f_proxy, proxy_class_constants_code, NIL); + else { + Swig_offset_string(proxy_class_constants_code, nesting_depth); + Append(old_proxy_class_code, proxy_class_constants_code); + } + } - Printf(f_proxy, "}\n"); - Delete(f_proxy); - f_proxy = NULL; + if (!has_outerclass) { + Printf(f_proxy, "}\n"); + Delete(f_proxy); + f_proxy = NULL; + } else { + for (int i = 0; i < nesting_depth; ++i) + Append(old_proxy_class_code, " "); + Append(old_proxy_class_code, "}\n\n"); + --nesting_depth; + } /* Output the downcast method, if necessary. Note: There's no other really good place to put this code, since Abstract Base Classes (ABCs) can and should have downcasts, making the constructorHandler() a bad place (because ABCs don't get to have constructors emitted.) */ if (GetFlag(n, "feature:javadowncast")) { - String *downcast_method = Swig_name_member(getNSpace(), proxy_class_name, "SWIGDowncast"); + String *downcast_method = Swig_name_member(getNSpace(), getClassPrefix(), "SWIGDowncast"); String *jniname = makeValidJniName(downcast_method); String *wname = Swig_name_wrapper(jniname); @@ -2038,17 +2107,21 @@ public: Delete(javaclazzname); Delete(proxy_class_name); - proxy_class_name = NULL; + proxy_class_name = old_proxy_class_name; Delete(full_proxy_class_name); - full_proxy_class_name = NULL; + full_proxy_class_name = old_full_proxy_class_name; Delete(full_imclass_name); - full_imclass_name = NULL; + full_imclass_name = old_full_imclass_name; Delete(destructor_call); - destructor_call = NULL; + destructor_call = old_destructor_call; Delete(destructor_throws_clause); - destructor_throws_clause = NULL; + destructor_throws_clause = old_destructor_throws_clause; Delete(proxy_class_constants_code); - proxy_class_constants_code = NULL; + proxy_class_constants_code = old_proxy_class_constants_code; + Delete(proxy_class_def); + proxy_class_def = old_proxy_class_def; + Delete(proxy_class_code); + proxy_class_code = old_proxy_class_code; } return SWIG_OK; @@ -2064,7 +2137,7 @@ public: if (proxy_flag) { String *overloaded_name = getOverloadedName(n); - String *intermediary_function_name = Swig_name_member(getNSpace(), proxy_class_name, overloaded_name); + String *intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name); Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); Setattr(n, "imfuncname", intermediary_function_name); proxyClassFunctionHandler(n); @@ -2086,7 +2159,7 @@ public: if (proxy_flag) { String *overloaded_name = getOverloadedName(n); - String *intermediary_function_name = Swig_name_member(getNSpace(), proxy_class_name, overloaded_name); + String *intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), overloaded_name); Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); Setattr(n, "imfuncname", intermediary_function_name); proxyClassFunctionHandler(n); @@ -2162,7 +2235,7 @@ public: if (wrapping_member_flag && !enum_constant_flag) { // For wrapping member variables (Javabean setter) - setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), Swig_name_member(0, proxy_class_name, variable_name))) == 0); + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(getNSpace(), Swig_name_member(0, getClassPrefix(), variable_name))) == 0); } /* Start generating the proxy function */ @@ -2316,7 +2389,7 @@ public: Node *explicit_n = Getattr(n, "explicitcallnode"); if (explicit_n) { String *ex_overloaded_name = getOverloadedName(explicit_n); - String *ex_intermediary_function_name = Swig_name_member(getNSpace(), proxy_class_name, ex_overloaded_name); + String *ex_intermediary_function_name = Swig_name_member(getNSpace(), getClassPrefix(), ex_overloaded_name); String *ex_imcall = Copy(imcall); Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); @@ -3399,7 +3472,7 @@ public: // Output the director connect method: String *jni_imclass_name = makeValidJniName(imclass_name); String *norm_name = SwigType_namestr(Getattr(n, "name")); - String *swig_director_connect = Swig_name_member(getNSpace(), proxy_class_name, "director_connect"); + String *swig_director_connect = Swig_name_member(getNSpace(), getClassPrefix(), "director_connect"); String *swig_director_connect_jni = makeValidJniName(swig_director_connect); String *smartptr = Getattr(n, "feature:smartptr"); String *dirClassName = directorClassName(n); @@ -3439,7 +3512,7 @@ public: Delete(swig_director_connect); // Output the swigReleaseOwnership, swigTakeOwnership methods: - String *changeown_method_name = Swig_name_member(getNSpace(), proxy_class_name, "change_ownership"); + String *changeown_method_name = Swig_name_member(getNSpace(), getClassPrefix(), "change_ownership"); String *changeown_jnimethod_name = makeValidJniName(changeown_method_name); Printf(imclass_class_code, " public final static native void %s(%s obj, long cptr, boolean take_or_release);\n", changeown_method_name, full_proxy_class_name); @@ -4519,6 +4592,9 @@ public: Setattr(n, "director:ctor", class_ctor); } + bool nestedClassesSupported() const { + return true; + } }; /* class JAVA */ /* ----------------------------------------------------------------------------- diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx index e50a50a6d..78c37dbb9 100644 --- a/Source/Modules/lang.cxx +++ b/Source/Modules/lang.cxx @@ -20,7 +20,7 @@ static int director_mode = 0; static int director_protected_mode = 1; static int all_protected_mode = 0; static int naturalvar_mode = 0; -Language* Language::this_ = 0; +Language *Language::this_ = 0; /* Set director_protected_mode */ void Wrapper_director_mode_set(int flag) { @@ -355,7 +355,7 @@ Language::~Language() { String *dirclassname; String *nspace = NewString(Getattr(n, "sym:nspace")); const char *attrib = "director:classname"; - String *classname = Getattr(n, "sym:name"); + String *classname = getClassPrefix(); Replace(nspace, NSPACE_SEPARATOR, "_", DOH_REPLACE_ANY); if (Len(nspace) > 0) @@ -1015,8 +1015,6 @@ int Language::cDeclaration(Node *n) { /* Some kind of variable declaration */ String *declaration = Copy(decl); Delattr(n, "decl"); - if (Getattr(n, "nested")) - SetFlag(n, "feature:immutable"); if (!CurrentClass) { if (Swig_storage_isextern(n) || ForceExtern) { if (AddExtern) { @@ -2362,6 +2360,15 @@ int Language::classDeclaration(Node *n) { return SWIG_NOWRAP; } + // save class local variables for nested classes support + int oldInClass = InClass; + String *oldClassType = ClassType; + String *oldClassPrefix = ClassPrefix; + String *oldClassName = ClassName; + String *oldDirectorClassName = DirectorClassName; + String *oldNSpace = NSpace; + Node *oldCurrentClass = CurrentClass; + String *kind = Getattr(n, "kind"); String *name = Getattr(n, "name"); String *tdname = Getattr(n, "tdname"); @@ -2370,6 +2377,8 @@ int Language::classDeclaration(Node *n) { int strip = CPlusPlus ? 1 : unnamed && tdname; + if (cplus_mode != PUBLIC) + return SWIG_NOWRAP; if (!name) { Swig_warning(WARN_LANG_CLASS_UNNAMED, input_file, line_number, "Can't generate wrappers for unnamed struct/class.\n"); return SWIG_NOWRAP; @@ -2380,15 +2389,21 @@ int Language::classDeclaration(Node *n) { Swig_warning(WARN_LANG_IDENTIFIER, input_file, line_number, "Can't wrap class %s unless renamed to a valid identifier.\n", SwigType_namestr(symname)); return SWIG_NOWRAP; } - + AccessMode oldAccessMode = cplus_mode; + Node *outerClass = Getattr(n, "nested:outer"); + if (outerClass && oldAccessMode != PUBLIC) + return SWIG_NOWRAP; + ClassName = Copy(name); + ClassPrefix = Copy(symname); if (Cmp(kind, "class") == 0) { cplus_mode = PRIVATE; } else { cplus_mode = PUBLIC; } - - ClassName = Copy(name); - ClassPrefix = Copy(symname); + for (; outerClass; outerClass = Getattr(outerClass, "nested:outer")) { + Push(ClassPrefix, "_"); + Push(ClassPrefix, Getattr(outerClass, "sym:name")); + } if (strip) { ClassType = Copy(name); } else { @@ -2399,9 +2414,8 @@ int Language::classDeclaration(Node *n) { InClass = 1; CurrentClass = n; - - String *oldNSpace = NSpace; NSpace = Getattr(n, "sym:nspace"); + int oldAbstract = Abstract; /* Call classHandler() here */ if (!ImportMode) { @@ -2443,25 +2457,27 @@ int Language::classDeclaration(Node *n) { classDirector(n); } /* check for abstract after resolving directors */ - Abstract = abstractClassTest(n); + Abstract = abstractClassTest(n); classHandler(n); } else { Abstract = abstractClassTest(n); Language::classHandler(n); } + Abstract = oldAbstract; + cplus_mode = oldAccessMode; NSpace = oldNSpace; - InClass = 0; - CurrentClass = 0; + InClass = oldInClass; + CurrentClass = oldCurrentClass; Delete(ClassType); - ClassType = 0; + ClassType = oldClassType; Delete(ClassPrefix); - ClassPrefix = 0; + ClassPrefix = oldClassPrefix; Delete(ClassName); - ClassName = 0; + ClassName = oldClassName; Delete(DirectorClassName); - DirectorClassName = 0; + DirectorClassName = oldDirectorClassName; return SWIG_OK; } @@ -2640,7 +2656,7 @@ int Language::constructorDeclaration(Node *n) { String *scope = Swig_scopename_check(ClassName) ? Swig_scopename_prefix(ClassName) : 0; String *actual_name = scope ? NewStringf("%s::%s", scope, name) : NewString(name); Delete(scope); - if (!Equal(actual_name, expected_name) && !(Getattr(n, "template"))) { + if (!Equal(actual_name, expected_name) && !SwigType_istemplate(expected_name)) { bool illegal_name = true; if (Extend) { // Check for typedef names used as a constructor name in %extend. This is deprecated except for anonymous @@ -3426,6 +3442,9 @@ bool Language::extraDirectorProtectedCPPMethodsRequired() const { return true; } +bool Language::nestedClassesSupported() const { + return false; +} /* ----------------------------------------------------------------------------- * Language::is_wrapping_class() * ----------------------------------------------------------------------------- */ @@ -3612,3 +3631,4 @@ Language *Language::instance() { Hash *Language::getClassHash() const { return classhash; } + diff --git a/Source/Modules/main.cxx b/Source/Modules/main.cxx index 4076b9206..f3aff2349 100644 --- a/Source/Modules/main.cxx +++ b/Source/Modules/main.cxx @@ -483,6 +483,10 @@ void SWIG_getoptions(int argc, char *argv[]) { Preprocessor_define((DOH *) "__cplusplus __cplusplus", 0); Swig_cparse_cplusplus(1); Swig_mark_arg(i); + } else if (strcmp(argv[i], "-c++out") == 0) { + // Undocumented + Swig_cparse_cplusplusout(1); + Swig_mark_arg(i); } else if (strcmp(argv[i], "-fcompact") == 0) { Wrapper_compact_print_mode_set(1); Swig_mark_arg(i); @@ -855,8 +859,9 @@ void SWIG_getoptions(int argc, char *argv[]) { } } - - +static void flatten_nested() { + Swig_feature_set(Swig_cparse_features(), "", 0, "feature:flatnested", "1", 0); +} int SWIG_main(int argc, char *argv[], Language *l) { @@ -947,6 +952,11 @@ int SWIG_main(int argc, char *argv[], Language *l) { // Don't check for an input file if -external-runtime is passed Swig_check_options(external_runtime ? 0 : 1); + if (CPlusPlus && cparse_cplusplusout) { + Printf(stderr, "The -c++out option is for C input but C++ input has been requested via -c++\n"); + SWIG_exit(EXIT_FAILURE); + } + install_opts(argc, argv); // Add language dependent directory to the search path @@ -1151,6 +1161,10 @@ int SWIG_main(int argc, char *argv[], Language *l) { fflush(stdout); } + // add "ignore" directive if nested classes are not supported + if (!lang->nestedClassesSupported()) + flatten_nested(); + Node *top = Swig_cparse(cpps); if (dump_top & STAGE1) { @@ -1161,6 +1175,11 @@ int SWIG_main(int argc, char *argv[], Language *l) { Printf(stdout, "debug-module stage 1\n"); Swig_print_tree(Getattr(top, "module")); } + if (!CPlusPlus) { + if (Verbose) + Printf(stdout, "Processing unnamed structs...\n"); + Swig_nested_name_unnamed_c_structs(top); + } if (Verbose) { Printf(stdout, "Processing types...\n"); @@ -1181,6 +1200,12 @@ int SWIG_main(int argc, char *argv[], Language *l) { } Swig_default_allocators(top); + if (CPlusPlus) { + if (Verbose) + Printf(stdout, "Processing nested classes...\n"); + Swig_nested_process_classes(top); + } + if (dump_top & STAGE3) { Printf(stdout, "debug-top stage 3\n"); Swig_print_tree(top); diff --git a/Source/Modules/nested.cxx b/Source/Modules/nested.cxx new file mode 100644 index 000000000..a62a9e9da --- /dev/null +++ b/Source/Modules/nested.cxx @@ -0,0 +1,444 @@ +/* ----------------------------------------------------------------------------- + * This file is part of SWIG, which is licensed as a whole under version 3 + * (or any later version) of the GNU General Public License. Some additional + * terms also apply to certain portions of SWIG. The full details of the SWIG + * license and copyrights can be found in the LICENSE and COPYRIGHT files + * included with the SWIG source code as distributed by the SWIG developers + * and at http://www.swig.org/legal.html. + * + * nested.cxx + * + * Nested structs support + * ----------------------------------------------------------------------------- */ + +#include "swigmod.h" +#include "cparse.h" + +// Nested classes processing section +static Hash *classhash = 0; + +static String *make_name(Node *n, String *name, SwigType *decl) { + int destructor = name && (*(Char(name)) == '~'); + if (String *yyrename = Getattr(n, "class_rename")) { + String *s = NewString(yyrename); + Delattr(n, "class_rename"); + if (destructor && (*(Char(s)) != '~')) { + Insert(s, 0, "~"); + } + return s; + } + + if (!name) + return 0; + return Swig_name_make(n, 0, name, decl, 0); +} + +// C version of add_symbols() +static void add_symbols_c(Node *n) { + String *decl; + String *wrn = 0; + String *symname = 0; + int iscdecl = Cmp(nodeType(n), "cdecl") == 0; + Setattr(n, "ismember", "1"); + Setattr(n, "access", "public"); + if (Getattr(n, "sym:name")) + return; + decl = Getattr(n, "decl"); + if (!SwigType_isfunction(decl)) { + String *name = Getattr(n, "name"); + String *makename = Getattr(n, "parser:makename"); + if (iscdecl) { + String *storage = Getattr(n, "storage"); + if (Cmp(storage, "typedef") == 0) { + Setattr(n, "kind", "typedef"); + } else { + SwigType *type = Getattr(n, "type"); + String *value = Getattr(n, "value"); + Setattr(n, "kind", "variable"); + if (value && Len(value)) { + Setattr(n, "hasvalue", "1"); + } + if (type) { + SwigType *ty; + SwigType *tmp = 0; + if (decl) { + ty = tmp = Copy(type); + SwigType_push(ty, decl); + } else { + ty = type; + } + if (!SwigType_ismutable(ty)) { + SetFlag(n, "hasconsttype"); + SetFlag(n, "feature:immutable"); + } + if (tmp) + Delete(tmp); + } + if (!type) { + Printf(stderr, "notype name %s\n", name); + } + } + } + Swig_features_get(Swig_cparse_features(), 0, name, 0, n); + if (makename) { + symname = make_name(n, makename, 0); + Delattr(n, "parser:makename"); /* temporary information, don't leave it hanging around */ + } else { + makename = name; + symname = make_name(n, makename, 0); + } + + if (!symname) { + symname = Copy(Getattr(n, "unnamed")); + } + if (symname) { + wrn = Swig_name_warning(n, 0, symname, 0); + } + } else { + String *name = Getattr(n, "name"); + SwigType *fdecl = Copy(decl); + SwigType *fun = SwigType_pop_function(fdecl); + if (iscdecl) { + Setattr(n, "kind", "function"); + } + + Swig_features_get(Swig_cparse_features(), 0, name, fun, n); + + symname = make_name(n, name, fun); + wrn = Swig_name_warning(n, 0, symname, fun); + + Delete(fdecl); + Delete(fun); + + } + if (!symname) + return; + if (GetFlag(n, "feature:ignore")) { + /* Only add to C symbol table and continue */ + Swig_symbol_add(0, n); + } else if (strncmp(Char(symname), "$ignore", 7) == 0) { + char *c = Char(symname) + 7; + SetFlag(n, "feature:ignore"); + if (strlen(c)) { + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(0, Getfile(n), Getline(n), "%s\n", c + 1); + SWIG_WARN_NODE_END(n); + } + Swig_symbol_add(0, n); + } else { + Node *c; + if ((wrn) && (Len(wrn))) { + String *metaname = symname; + if (!Getmeta(metaname, "already_warned")) { + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(0, Getfile(n), Getline(n), "%s\n", wrn); + SWIG_WARN_NODE_END(n); + Setmeta(metaname, "already_warned", "1"); + } + } + c = Swig_symbol_add(symname, n); + + if (c != n) { + /* symbol conflict attempting to add in the new symbol */ + if (Getattr(n, "sym:weak")) { + Setattr(n, "sym:name", symname); + } else { + String *e = NewStringEmpty(); + String *en = NewStringEmpty(); + String *ec = NewStringEmpty(); + int redefined = Swig_need_redefined_warn(n, c, true); + if (redefined) { + Printf(en, "Identifier '%s' redefined (ignored)", symname); + Printf(ec, "previous definition of '%s'", symname); + } else { + Printf(en, "Redundant redeclaration of '%s'", symname); + Printf(ec, "previous declaration of '%s'", symname); + } + if (Cmp(symname, Getattr(n, "name"))) { + Printf(en, " (Renamed from '%s')", SwigType_namestr(Getattr(n, "name"))); + } + Printf(en, ","); + if (Cmp(symname, Getattr(c, "name"))) { + Printf(ec, " (Renamed from '%s')", SwigType_namestr(Getattr(c, "name"))); + } + Printf(ec, "."); + SWIG_WARN_NODE_BEGIN(n); + if (redefined) { + Swig_warning(WARN_PARSE_REDEFINED, Getfile(n), Getline(n), "%s\n", en); + Swig_warning(WARN_PARSE_REDEFINED, Getfile(c), Getline(c), "%s\n", ec); + } else { + Swig_warning(WARN_PARSE_REDUNDANT, Getfile(n), Getline(n), "%s\n", en); + Swig_warning(WARN_PARSE_REDUNDANT, Getfile(c), Getline(c), "%s\n", ec); + } + SWIG_WARN_NODE_END(n); + Printf(e, "%s:%d:%s\n%s:%d:%s\n", Getfile(n), Getline(n), en, Getfile(c), Getline(c), ec); + Setattr(n, "error", e); + Delete(e); + Delete(en); + Delete(ec); + } + } + } + Delete(symname); +} + +/* Strips C-style and C++-style comments from string in-place. */ +static void strip_comments(char *string) { + int state = 0; + /* + * 0 - not in comment + * 1 - in c-style comment + * 2 - in c++-style comment + * 3 - in string + * 4 - after reading / not in comments + * 5 - after reading * in c-style comments + * 6 - after reading \ in strings + */ + char *c = string; + while (*c) { + switch (state) { + case 0: + if (*c == '\"') + state = 3; + else if (*c == '/') + state = 4; + break; + case 1: + if (*c == '*') + state = 5; + *c = ' '; + break; + case 2: + if (*c == '\n') + state = 0; + else + *c = ' '; + break; + case 3: + if (*c == '\"') + state = 0; + else if (*c == '\\') + state = 6; + break; + case 4: + if (*c == '/') { + *(c - 1) = ' '; + *c = ' '; + state = 2; + } else if (*c == '*') { + *(c - 1) = ' '; + *c = ' '; + state = 1; + } else + state = 0; + break; + case 5: + if (*c == '/') + state = 0; + else + state = 1; + *c = ' '; + break; + case 6: + state = 3; + break; + } + ++c; + } +} + +// Create a %insert with a typedef to make a new name visible to C +static Node *create_insert(Node *n, bool noTypedef = false) { + // format a typedef + String *ccode = Getattr(n, "code"); + Push(ccode, " "); + if (noTypedef) { + Push(ccode, Getattr(n, "name")); + Push(ccode, " "); + Push(ccode, Getattr(n, "kind")); + } else { + Push(ccode, Getattr(n, "kind")); + Push(ccode, "typedef "); + Append(ccode, " "); + Append(ccode, Getattr(n, "tdname")); + } + Append(ccode, ";"); + + /* Strip comments - further code may break in presence of comments. */ + strip_comments(Char(ccode)); + + /* Make all SWIG created typedef structs/unions/classes unnamed else + redefinition errors occur - nasty hack alert. */ + if (!noTypedef) { + const char *types_array[3] = { "struct", "union", "class" }; + for (int i = 0; i < 3; i++) { + char *code_ptr = Char(ccode); + while (code_ptr) { + /* Replace struct name (as in 'struct name {...}' ) with whitespace + name will be between struct and opening brace */ + + code_ptr = strstr(code_ptr, types_array[i]); + if (code_ptr) { + char *open_bracket_pos; + code_ptr += strlen(types_array[i]); + open_bracket_pos = strchr(code_ptr, '{'); + if (open_bracket_pos) { + /* Make sure we don't have something like struct A a; */ + char *semi_colon_pos = strchr(code_ptr, ';'); + if (!(semi_colon_pos && (semi_colon_pos < open_bracket_pos))) + while (code_ptr < open_bracket_pos) + *code_ptr++ = ' '; + } + } + } + } + } + { + /* Remove SWIG directive %constant which may be left in the SWIG created typedefs */ + char *code_ptr = Char(ccode); + while (code_ptr) { + code_ptr = strstr(code_ptr, "%constant"); + if (code_ptr) { + char *directive_end_pos = strchr(code_ptr, ';'); + if (directive_end_pos) { + while (code_ptr <= directive_end_pos) + *code_ptr++ = ' '; + } + } + } + } + Node *newnode = NewHash(); + set_nodeType(newnode, "insert"); + Setfile(newnode, Getfile(n)); + Setline(newnode, Getline(n)); + String *code = NewStringEmpty(); + Wrapper_pretty_print(ccode, code); + Setattr(newnode, "code", code); + Delete(code); + Delattr(n, "code"); + return newnode; +} + +static void insertNodeAfter(Node *n, Node *c) { + Node *g = parentNode(n); + set_parentNode(c, g); + Node *ns = nextSibling(n); + if (Node *outer = Getattr(c, "nested:outer")) { + while (ns && outer == Getattr(ns, "nested:outer")) { + n = ns; + ns = nextSibling(n); + } + } + if (!ns) { + set_lastChild(g, c); + } else { + set_nextSibling(c, ns); + set_previousSibling(ns, c); + } + set_nextSibling(n, c); + set_previousSibling(c, n); +} + +void Swig_nested_name_unnamed_c_structs(Node *n) { + if (!classhash) + classhash = Getattr(n, "classes"); + Node *c = firstChild(n); + while (c) { + Node *next = nextSibling(c); + if (String *declName = Getattr(c, "nested:unnamed")) { + if (Node *outer = Getattr(c, "nested:outer")) { + // generate a name + String *name = NewStringf("%s_%s", Getattr(outer, "name"), declName); + Delattr(c, "nested:unnamed"); + // set the name to the class and symbol table + Setattr(c, "tdname", name); + Setattr(c, "name", name); + Swig_symbol_setscope(Getattr(c, "symtab")); + Swig_symbol_setscopename(name); + // now that we have a name - gather base symbols + if (List *publicBases = Getattr(c, "baselist")) { + List *bases = Swig_make_inherit_list(name, publicBases, 0); + Swig_inherit_base_symbols(bases); + Delete(bases); + } + Setattr(classhash, name, c); + Swig_symbol_popscope(); + // process declarations following this type (assign correct new type) + SwigType *ty = Copy(name); + Node *decl = nextSibling(c); + List *declList = NewList(); + while (decl && Getattr(decl, "nested:unnamedtype") == c) { + Setattr(decl, "type", ty); + Append(declList, decl); + Delattr(decl, "nested:unnamedtype"); + SetFlag(decl, "feature:immutable"); + add_symbols_c(decl); + decl = nextSibling(decl); + } + Delete(ty); + // Check for extensions +/* // TODO: we can save extensions hash like class hash and move check_extensions() after nesting processing + if (extendhash) { + if (Node *am = Getattr(extendhash, name)) { + // Merge the extension into the symbol table + merge_extensions(c, am); + append_previous_extension(c, am); + Delattr(extendhash, clsname); + } + }*/ + Swig_symbol_setscope(Swig_symbol_global_scope()); + add_symbols_c(c); + + Node *ins = create_insert(c); + insertNodeAfter(c, ins); + removeNode(c); + insertNodeAfter(n, c); + Delete(ins); + Delattr(c, "nested:outer"); + } else { + // global unnamed struct - ignore it + c = next; + continue; + } + } else if (cparse_cplusplusout) { + if (Getattr(c, "nested:outer")) { + Node *ins = create_insert(c, true); + insertNodeAfter(c, ins); + Delete(ins); + Delattr(c, "nested:outer"); + } + } + // process children + Swig_nested_name_unnamed_c_structs(c); + c = next; + } +} + +static void remove_outer_class_reference(Node *n) { + for (Node *c = firstChild(n); c; c = nextSibling(c)) { + if (GetFlag(c, "feature:flatnested")) { + Delattr(c, "nested:outer"); + remove_outer_class_reference(c); + } + } +} + +void Swig_nested_process_classes(Node *n) { + Node *c = firstChild(n); + while (c) { + Node *next = nextSibling(c); + if (!Getattr(c, "templatetype")) { + if (GetFlag(c, "nested") && GetFlag(c, "feature:flatnested")) { + removeNode(c); + if (!checkAttribute(c, "access", "public")) + SetFlag(c, "feature:ignore"); + else + insertNodeAfter(n, c); + } + Swig_nested_process_classes(c); + } + c = next; + } + remove_outer_class_reference(n); +} + diff --git a/Source/Modules/octave.cxx b/Source/Modules/octave.cxx index 65a1ad701..14118972d 100644 --- a/Source/Modules/octave.cxx +++ b/Source/Modules/octave.cxx @@ -12,6 +12,7 @@ * ----------------------------------------------------------------------------- */ #include "swigmod.h" +#include "cparse.h" static String *global_name = 0; static String *op_prefix = 0; @@ -132,6 +133,10 @@ public: SWIG_config_file("octave.swg"); SWIG_typemap_lang("octave"); allow_overloading(); + + // Octave API is C++, so output must be C++ compatibile even when wrapping C code + if (!cparse_cplusplus) + Swig_cparse_cplusplusout(1); } virtual int top(Node *n) { diff --git a/Source/Modules/swigmod.h b/Source/Modules/swigmod.h index 3a7e8a8d6..9e76b4d10 100644 --- a/Source/Modules/swigmod.h +++ b/Source/Modules/swigmod.h @@ -297,6 +297,16 @@ protected: /* Some language modules require additional wrappers for virtual methods not declared in sub-classes */ virtual bool extraDirectorProtectedCPPMethodsRequired() const; +public: + /* Does target language support nested classes? Default is 'false'. If 'false' is returned, then + %rename("$ignore", %$isnested) statement will be issued at the top, and the nested classes + will be ignored. Note that even if the target language does not support the notion of class + nesting, the language module may nevertheless return true from this function, and use + %feature "flatnested" to move nested classes to the global scope, instead of ignoring them. + */ + virtual bool nestedClassesSupported() const; + +protected: /* Identifies if a protected members that are generated when the allprotected option is used. This does not include protected virtual methods as they are turned on with the dirprot option. */ bool isNonVirtualProtectedAccess(Node *n) const; @@ -410,5 +420,7 @@ int Swig_contract_mode_get(); void Swig_browser(Node *n, int); void Swig_default_allocators(Node *n); void Swig_process_types(Node *n); +void Swig_nested_process_classes(Node *n); +void Swig_nested_name_unnamed_c_structs(Node *n); #endif diff --git a/Source/Modules/typepass.cxx b/Source/Modules/typepass.cxx index 7eebfe80b..3f8e33dae 100644 --- a/Source/Modules/typepass.cxx +++ b/Source/Modules/typepass.cxx @@ -178,6 +178,20 @@ class TypePass:private Dispatcher { } continue; } + // A case when both outer and nested classes inherit from the same parent. Constructor may be found instead of the class itself. + } else if (GetFlag(cls, "nested") && checkAttribute(bcls, "nodeType", "constructor")) { + bcls = Getattr(bcls, "parentNode"); + if (Getattr(bcls, "typepass:visit")) { + if (!Getattr(bcls, "feature:onlychildren")) { + if (!ilist) + ilist = alist = NewList(); + Append(ilist, bcls); + } else { + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bname), Getline(bname), "Base class '%s' has no name as it is an empty template instantiated with '%%template()'. Ignored.\n", SwigType_namestr(bname)); + Swig_warning(WARN_TYPE_UNDEFINED_CLASS, Getfile(bcls), Getline(bcls), "The %%template directive must be written before '%s' is used as a base class and be declared with a name.\n", SwigType_namestr(bname)); + } + } + break; } if (Strcmp(nodeType(bcls), "classforward") != 0) { Swig_error(Getfile(bname), Getline(bname), "'%s' is not a valid base class.\n", SwigType_namestr(bname)); @@ -462,6 +476,17 @@ class TypePass:private Dispatcher { if (unnamed && tdname && (Cmp(storage, "typedef") == 0)) { SwigType_typedef(unnamed, tdname); } + // name of the outer class should already be patched to contain it's outer classes names, but not to contain namespaces + // namespace name (if present) is added after processing child nodes + if (Getattr(n, "nested:outer") && name) { + String *outerName = Getattr(Getattr(n, "nested:outer"), "name"); + name = NewStringf("%s::%s", outerName, name); + Setattr(n, "name", name); + if (tdname) { + tdname = NewStringf("%s::%s", outerName, tdname); + Setattr(n, "tdname", tdname); + } + } if (nsname && name) { nname = NewStringf("%s::%s", nsname, name); @@ -479,7 +504,7 @@ class TypePass:private Dispatcher { SwigType_attach_symtab(Getattr(n, "symtab")); /* Inherit type definitions into the class */ - if (name) { + if (name && !(GetFlag(n, "nested") && GetFlag(n, "feature:flatnested") && !checkAttribute(n, "access", "public"))) { cplus_inherit_types(n, 0, nname ? nname : (fname ? fname : name)); } @@ -653,7 +678,7 @@ class TypePass:private Dispatcher { if (GetFlag(n, "conversion_operator")) { /* The call to the operator in the generated wrapper must be fully qualified in order to compile */ SwigType *name = Getattr(n, "name"); - SwigType *qualifiedname = Swig_symbol_string_qualify(name,0); + SwigType *qualifiedname = Swig_symbol_string_qualify(name, 0); Clear(name); Append(name, qualifiedname); Delete(qualifiedname); @@ -1090,8 +1115,7 @@ class TypePass:private Dispatcher { * list of overloaded methods we have just added in as child nodes to the "using" node. * The node will still exist, it is just the symbol table linked list of overloaded methods * which is hacked. */ - if (Getattr(n, "sym:overloaded")) - { + if (Getattr(n, "sym:overloaded")) { int cnt = 0; #ifdef DEBUG_OVERLOADED Node *debugnode = n; @@ -1154,7 +1178,7 @@ class TypePass:private Dispatcher { #ifdef DEBUG_OVERLOADED show_overloaded(debugnode); #endif - clean_overloaded(n); // Needed? + clean_overloaded(n); // Needed? } } } @@ -1258,3 +1282,4 @@ void Swig_process_types(Node *n) { return; TypePass::pass(n); } + diff --git a/Source/Swig/cwrap.c b/Source/Swig/cwrap.c index 6f8fa39e9..04845f3cf 100644 --- a/Source/Swig/cwrap.c +++ b/Source/Swig/cwrap.c @@ -13,8 +13,8 @@ * ----------------------------------------------------------------------------- */ #include "swig.h" +#include "cparse.h" -extern int cparse_cplusplus; static const char *cresult_variable_name = "result"; static Parm *nonvoid_parms(Parm *p) { @@ -775,7 +775,25 @@ String *Swig_cmemberset_call(const_String_or_char_ptr name, SwigType *type, Stri if (SwigType_type(type) != T_ARRAY) { if (!Strstr(type, "enum $unnamed")) { String *dref = Swig_wrapped_var_deref(type, pname1, varcref); - Printf(func, "if (%s) %s%s = %s", pname0, self, name, dref); + int extra_cast = 0; + if (cparse_cplusplusout) { + /* Required for C nested structs compiled as C++ as a duplicate of the nested struct is put into the global namespace. + * We could improve this by adding the extra casts just for nested structs rather than all structs. */ + String *base = SwigType_base(type); + extra_cast = SwigType_isclass(base); + Delete(base); + } + if (extra_cast) { + String *lstr; + SwigType *ptype = Copy(type); + SwigType_add_pointer(ptype); + lstr = SwigType_lstr(ptype, 0); + Printf(func, "if (%s) *(%s)&%s%s = %s", pname0, lstr, self, name, dref); + Delete(lstr); + Delete(ptype); + } else { + Printf(func, "if (%s) %s%s = %s", pname0, self, name, dref); + } Delete(dref); } else { Printf(func, "if (%s && sizeof(int) == sizeof(%s%s)) *(int*)(void*)&(%s%s) = %s", pname0, self, name, self, name, pname1); diff --git a/Source/Swig/misc.c b/Source/Swig/misc.c index 769882bf8..7d8180d1c 100644 --- a/Source/Swig/misc.c +++ b/Source/Swig/misc.c @@ -1147,6 +1147,55 @@ String *Swig_string_strip(String *s) { return ns; } +/* ----------------------------------------------------------------------------- + * Swig_offset_string() + * + * Insert number tabs before each new line in s + * ----------------------------------------------------------------------------- */ + +void Swig_offset_string(String *s, int number) { + char *res; + char *p; + char *end; + /* count a number of lines in s */ + int lines = 1; + int len = Len(s); + char *start = strchr(Char(s), '\n'); + while (start) { + ++lines; + start = strchr(start + 1, '\n'); + } + /* do not count pending new line */ + if ((Char(s))[len-1] == '\n') + --lines; + /* allocate a temporary storage for a padded string */ + res = (char*)malloc(len + lines * number * 2 + 1); + res[len + lines * number * 2] = 0; + + /* copy lines to res, prepending tabs to each line */ + p = res; /* output pointer */ + start = Char(s); /* start of a current line */ + end = strchr(start, '\n'); /* end of a current line */ + while (end) { + memset(p, ' ', number*2); + p += number*2; + memcpy(p, start, end - start + 1); + p += end - start + 1; + start = end + 1; + end = strchr(start, '\n'); + } + /* process the last line */ + if (*start) { + memset(p, ' ', number*2); + p += number*2; + strcpy(p, start); + } + /* replace 's' contents with 'res' */ + Clear(s); + Append(s, res); + free(res); +} + #ifdef HAVE_PCRE #include <pcre.h> diff --git a/Source/Swig/naming.c b/Source/Swig/naming.c index 119f816dc..9e2b4a436 100644 --- a/Source/Swig/naming.c +++ b/Source/Swig/naming.c @@ -774,7 +774,7 @@ void Swig_features_get(Hash *features, String *prefix, String *name, SwigType *d * concatenating the feature name plus ':' plus the attribute name. * ----------------------------------------------------------------------------- */ -void Swig_feature_set(Hash *features, const_String_or_char_ptr name, SwigType *decl, const_String_or_char_ptr featurename, String *value, Hash *featureattribs) { +void Swig_feature_set(Hash *features, const_String_or_char_ptr name, SwigType *decl, const_String_or_char_ptr featurename, const_String_or_char_ptr value, Hash *featureattribs) { Hash *n; Hash *fhash; @@ -1649,6 +1649,80 @@ void Swig_name_inherit(String *base, String *derived) { } /* ----------------------------------------------------------------------------- + * Swig_inherit_base_symbols() + * ----------------------------------------------------------------------------- */ + +void Swig_inherit_base_symbols(List *bases) { + if (bases) { + Iterator s; + for (s = First(bases); s.item; s = Next(s)) { + Symtab *st = Getattr(s.item, "symtab"); + if (st) { + Setfile(st, Getfile(s.item)); + Setline(st, Getline(s.item)); + Swig_symbol_inherit(st); + } + } + Delete(bases); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_make_inherit_list() + * ----------------------------------------------------------------------------- */ + +List *Swig_make_inherit_list(String *clsname, List *names, String *Namespaceprefix) { + int i, ilen; + String *derived; + List *bases = NewList(); + + if (Namespaceprefix) + derived = NewStringf("%s::%s", Namespaceprefix, clsname); + else + derived = NewString(clsname); + + ilen = Len(names); + for (i = 0; i < ilen; i++) { + String *base; + String *n = Getitem(names, i); + /* Try to figure out where this symbol is */ + Node *s = Swig_symbol_clookup(n, 0); + if (s) { + while (s && (Strcmp(nodeType(s), "class") != 0)) { + /* Not a class. Could be a typedef though. */ + String *storage = Getattr(s, "storage"); + if (storage && (Strcmp(storage, "typedef") == 0)) { + String *nn = Getattr(s, "type"); + s = Swig_symbol_clookup(nn, Getattr(s, "sym:symtab")); + } else { + break; + } + } + if (s && ((Strcmp(nodeType(s), "class") == 0) || (Strcmp(nodeType(s), "template") == 0))) { + String *q = Swig_symbol_qualified(s); + Append(bases, s); + if (q) { + base = NewStringf("%s::%s", q, Getattr(s, "name")); + Delete(q); + } else { + base = NewString(Getattr(s, "name")); + } + } else { + base = NewString(n); + } + } else { + base = NewString(n); + } + if (base) { + Swig_name_inherit(base, derived); + Delete(base); + } + } + return bases; +} + + +/* ----------------------------------------------------------------------------- * void Swig_name_str() * * Return a stringified version of a C/C++ symbol from a node. diff --git a/Source/Swig/scanner.c b/Source/Swig/scanner.c index 181d9aa74..a32828b58 100644 --- a/Source/Swig/scanner.c +++ b/Source/Swig/scanner.c @@ -1547,6 +1547,114 @@ int Scanner_skip_balanced(Scanner * s, int startchar, int endchar) { } /* ----------------------------------------------------------------------------- + * Scanner_get_raw_text_balanced() + * + * Returns raw text between 2 braces, does not change scanner state in any way + * ----------------------------------------------------------------------------- */ + +String *Scanner_get_raw_text_balanced(Scanner *s, int startchar, int endchar) { + String *result = 0; + char c; + int old_line = s->line; + String *old_text = Copy(s->text); + int position = Tell(s->str); + + int num_levels = 1; + int state = 0; + char temp[2] = { 0, 0 }; + temp[0] = (char) startchar; + Clear(s->text); + Setfile(s->text, Getfile(s->str)); + Setline(s->text, s->line); + Append(s->text, temp); + while (num_levels > 0) { + if ((c = nextchar(s)) == 0) { + Clear(s->text); + Append(s->text, old_text); + Delete(old_text); + s->line = old_line; + return 0; + } + switch (state) { + case 0: + if (c == startchar) + num_levels++; + else if (c == endchar) + num_levels--; + else if (c == '/') + state = 10; + else if (c == '\"') + state = 20; + else if (c == '\'') + state = 30; + break; + case 10: + if (c == '/') + state = 11; + else if (c == '*') + state = 12; + else if (c == startchar) { + state = 0; + num_levels++; + } + else + state = 0; + break; + case 11: + if (c == '\n') + state = 0; + else + state = 11; + break; + case 12: /* first character inside C comment */ + if (c == '*') + state = 14; + else + state = 13; + break; + case 13: + if (c == '*') + state = 14; + break; + case 14: /* possible end of C comment */ + if (c == '*') + state = 14; + else if (c == '/') + state = 0; + else + state = 13; + break; + case 20: + if (c == '\"') + state = 0; + else if (c == '\\') + state = 21; + break; + case 21: + state = 20; + break; + case 30: + if (c == '\'') + state = 0; + else if (c == '\\') + state = 31; + break; + case 31: + state = 30; + break; + default: + break; + } + } + Seek(s->str, position, SEEK_SET); + result = Copy(s->text); + Clear(s->text); + Append(s->text, old_text); + Delete(old_text); + s->line = old_line; + return result; +} +/* ----------------------------------------------------------------------------- * Scanner_isoperator() * * Returns 0 or 1 depending on whether or not a token corresponds to a C/C++ diff --git a/Source/Swig/swig.h b/Source/Swig/swig.h index b730ab04d..95d9189b3 100644 --- a/Source/Swig/swig.h +++ b/Source/Swig/swig.h @@ -286,6 +286,8 @@ extern int ParmList_is_compactdefargs(ParmList *p); extern Hash *Swig_name_namewarn_get(Node *n, String *prefix, String *name, SwigType *decl); extern void Swig_name_rename_add(String *prefix, String *name, SwigType *decl, Hash *namewrn, ParmList *declaratorparms); extern void Swig_name_inherit(String *base, String *derived); + extern List *Swig_make_inherit_list(String *clsname, List *names, String *Namespaceprefix); + extern void Swig_inherit_base_symbols(List *bases); extern int Swig_need_protected(Node *n); extern int Swig_need_name_warning(Node *n); extern int Swig_need_redefined_warn(Node *a, Node *b, int InClass); @@ -302,7 +304,7 @@ extern int ParmList_is_compactdefargs(ParmList *p); extern DOH *Swig_name_object_get(Hash *namehash, String *prefix, String *name, SwigType *decl); extern void Swig_name_object_inherit(Hash *namehash, String *base, String *derived); extern void Swig_features_get(Hash *features, String *prefix, String *name, SwigType *decl, Node *n); - extern void Swig_feature_set(Hash *features, const_String_or_char_ptr name, SwigType *decl, const_String_or_char_ptr featurename, String *value, Hash *featureattribs); + extern void Swig_feature_set(Hash *features, const_String_or_char_ptr name, SwigType *decl, const_String_or_char_ptr featurename, const_String_or_char_ptr value, Hash *featureattribs); /* --- Misc --- */ extern char *Swig_copy_string(const char *c); @@ -330,6 +332,7 @@ extern int ParmList_is_compactdefargs(ParmList *p); extern String *Swig_string_lower(String *s); extern String *Swig_string_upper(String *s); extern String *Swig_string_title(String *s); + extern void Swig_offset_string(String *s, int number); extern String *Swig_pcre_version(void); extern void Swig_init(void); extern int Swig_value_wrapper_mode(int mode); diff --git a/Source/Swig/swigscan.h b/Source/Swig/swigscan.h index 017ef58d5..6a181f86f 100644 --- a/Source/Swig/swigscan.h +++ b/Source/Swig/swigscan.h @@ -22,6 +22,7 @@ extern int Scanner_token(Scanner *); extern String *Scanner_text(Scanner *); extern void Scanner_skip_line(Scanner *); extern int Scanner_skip_balanced(Scanner *, int startchar, int endchar); +extern String *Scanner_get_raw_text_balanced(Scanner *, int startchar, int endchar); extern void Scanner_set_location(Scanner *, String *file, int line); extern String *Scanner_file(Scanner *); extern int Scanner_line(Scanner *); diff --git a/Source/Swig/swigtree.h b/Source/Swig/swigtree.h index 5decb79e3..acd0e5e90 100644 --- a/Source/Swig/swigtree.h +++ b/Source/Swig/swigtree.h @@ -38,6 +38,7 @@ extern void appendChild(Node *node, Node *child); extern void prependChild(Node *node, Node *child); extern void removeNode(Node *node); extern Node *copyNode(Node *node); +extern void appendSibling(Node *node, Node *child); /* Node restoration/restore functions */ diff --git a/Source/Swig/tree.c b/Source/Swig/tree.c index 784d3ab84..d817f1a85 100644 --- a/Source/Swig/tree.c +++ b/Source/Swig/tree.c @@ -171,6 +171,24 @@ void prependChild(Node *node, Node *chd) { } } +void appendSibling(Node *node, Node *chd) { + Node *parent; + Node *lc = node; + while (nextSibling(lc)) + lc = nextSibling(lc); + set_nextSibling(lc, chd); + set_previousSibling(chd, lc); + parent = parentNode(node); + if (parent) { + while (chd) { + lc = chd; + set_parentNode(chd, parent); + chd = nextSibling(chd); + } + set_lastChild(parent, lc); + } +} + /* ----------------------------------------------------------------------------- * removeNode() * |