From 16180d1aab7598294d092ac7faeeec09b6165e2e Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 13 Sep 2025 04:30:45 +0300 Subject: [PATCH 1/4] Initial commit with task details for issue #67 Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: https://github.com/linksplatform/RegularExpressions.Transformer.CSharpToCpp/issues/67 --- CLAUDE.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..ac64741 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +Issue to solve: https://github.com/linksplatform/RegularExpressions.Transformer.CSharpToCpp/issues/67 +Your prepared branch: issue-67-0326ea0e +Your prepared working directory: /tmp/gh-issue-solver-1757727040312 + +Proceed. \ No newline at end of file From 29d0ac86b28cbbe0e4ef4a1001988bff8d94c6e2 Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 13 Sep 2025 05:16:16 +0300 Subject: [PATCH 2/4] Implement better support for interfaces as requested in issue #67 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds the four key improvements requested: 1. **#pragma once support**: Modified regex on line 32 to preserve `#pragma once` while removing other pragma directives like `#pragma warning disable` 2. **struct instead of class with public: support**: Updated interface handling (lines 96, 283) to convert interfaces to structs instead of classes 3. **Virtual destructors**: Added virtual destructors with `= default` to structs that contain virtual methods (originally interfaces). Added rule on line 287 in FirstStage and fixing rule on line 763 in LastStage with proper priority. 4. **Better template type arguments placement**: Modified template generation (lines 90, 96) to place template declarations on separate lines from class/struct definitions as per issue #68. Key technical changes: - Modified pragma regex to use negative lookahead: `#pragma(?! once)` - Updated interface-to-struct conversion rules in both templated and non-templated cases - Added selective virtual destructor insertion for interface-derived structs - Implemented two-stage rule processing to handle destructors correctly - Added comprehensive test coverage for all new features All existing tests pass, and new tests verify the four requested features work correctly. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../CSharpToCppTransformerTests.cs | 122 ++++++++++++++++++ .../CSharpToCppTransformer.cs | 23 +++- 2 files changed, 138 insertions(+), 7 deletions(-) diff --git a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp.Tests/CSharpToCppTransformerTests.cs b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp.Tests/CSharpToCppTransformerTests.cs index edca381..eafb53e 100644 --- a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp.Tests/CSharpToCppTransformerTests.cs +++ b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp.Tests/CSharpToCppTransformerTests.cs @@ -35,5 +35,127 @@ public static void Main(string[] args) var actualResult = transformer.Transform(helloWorldCode); Assert.Equal(expectedResult, actualResult); } + + [Fact] + public void PragmaOncePreservationTest() + { + const string input = @"#pragma once +using System; + +class Test +{ + public void Method() { } +}"; + const string expectedResult = @"#pragma once + +class Test +{ + public: void Method() { } +};"; + var transformer = new CSharpToCppTransformer(); + var actualResult = transformer.Transform(input); + Assert.Equal(expectedResult, actualResult); + } + + [Fact] + public void PragmaWarningRemovalTest() + { + const string input = @"#pragma warning disable CS1591 +using System; + +class Test +{ + public void Method() { } +}"; + const string expectedResult = @"class Test +{ + public: void Method() { } +};"; + var transformer = new CSharpToCppTransformer(); + var actualResult = transformer.Transform(input); + Assert.Equal(expectedResult, actualResult); + } + + [Fact] + public void SimpleInterfaceToStructTest() + { + const string input = @" +interface ITest +{ + void Method(); +}"; + const string expectedResult = @" +struct ITest +{ + public: + virtual void Method() = 0; + virtual ~ITest() = default; +};"; + var transformer = new CSharpToCppTransformer(); + var actualResult = transformer.Transform(input); + Assert.Equal(expectedResult, actualResult); + } + + [Fact] + public void TemplatedInterfaceToStructTest() + { + const string input = @" +interface ITest +{ + void Method(T value); +}"; + const string expectedResult = @" +template struct ITest; +template +struct ITest +{ + public: + virtual void Method(T value) = 0; + virtual ~ITest() = default; +};"; + var transformer = new CSharpToCppTransformer(); + var actualResult = transformer.Transform(input); + Assert.Equal(expectedResult, actualResult); + } + + [Fact] + public void TemplatedClassSeparationTest() + { + const string input = @" +class TestClass +{ + public T Value { get; set; } +}"; + const string expectedResult = @" +template class TestClass; +template +class TestClass +{ + public: inline T Value; +};"; + var transformer = new CSharpToCppTransformer(); + var actualResult = transformer.Transform(input); + Assert.Equal(expectedResult, actualResult); + } + + [Fact] + public void TemplatedStructSeparationTest() + { + const string input = @" +struct TestStruct +{ + public T Value { get; set; } +}"; + const string expectedResult = @" +template struct TestStruct; +template +struct TestStruct +{ + public: inline T Value; +};"; + var transformer = new CSharpToCppTransformer(); + var actualResult = transformer.Transform(input); + Assert.Equal(expectedResult, actualResult); + } } } diff --git a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/CSharpToCppTransformer.cs b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/CSharpToCppTransformer.cs index 2f5dceb..f4ffaad 100644 --- a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/CSharpToCppTransformer.cs +++ b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/CSharpToCppTransformer.cs @@ -29,7 +29,7 @@ public class CSharpToCppTransformer : TextTransformer (new Regex(@"(\r?\n)?[ \t]+//+.+"), "", 0), // #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member // - (new Regex(@"^\s*?\#pragma[\sa-zA-Z0-9]+$"), "", 0), + (new Regex(@"^\s*?\#pragma(?! once)[\sa-zA-Z0-9]+$"), "", 0), // {\n\n\n // { (new Regex(@"{\s+[\r\n]+"), "{" + Environment.NewLine, 0), @@ -86,14 +86,14 @@ public class CSharpToCppTransformer : TextTransformer // class (new Regex(@"((public|protected|private|internal|abstract|static) )*(?interface|class|struct)"), "${category}", 0), // class GenericCollectionMethodsBase { - // template class GenericCollectionMethodsBase { - (new Regex(@"(?\r?\n)(?[ \t]*)(?class|struct) (?[a-zA-Z0-9]+)<(?[a-zA-Z0-9 ,]+)>(?[^{]+){"), "${before}${indent}template ${type} ${typeName};" + Environment.NewLine + "${indent}template ${type} ${typeName}<${typeParameters}>${typeDefinitionEnding}{", 0), + // template \nclass GenericCollectionMethodsBase { + (new Regex(@"(?\r?\n)(?[ \t]*)(?class|struct) (?[a-zA-Z0-9]+)<(?[a-zA-Z0-9 ,]+)>(?[^{]+){"), "${before}${indent}template ${type} ${typeName};" + Environment.NewLine + "${indent}template " + Environment.NewLine + "${indent}${type} ${typeName}<${typeParameters}>${typeDefinitionEnding}{", 0), // static void TestMultipleCreationsAndDeletions(SizedBinaryTreeMethodsBase tree, TElement* root) // template static void TestMultipleCreationsAndDeletions(SizedBinaryTreeMethodsBase tree, TElement* root) (new Regex(@"static ([a-zA-Z0-9]+) ([a-zA-Z0-9]+)<([a-zA-Z0-9]+)>\(([^\)\r\n]+)\)"), "template static $1 $2($4)", 0), // interface IFactory { - // template class IFactory;\ntemplate class IFactory - (new Regex(@"(?\r?\n)(?[ \t]*)interface (?[a-zA-Z0-9]+)<(?[a-zA-Z0-9 ,]+)>(?[^{]+){"), "${before}${indent}template class ${interface};" + Environment.NewLine + "${indent}template class ${interface}<${typeParameters}>${typeDefinitionEnding}{" + Environment.NewLine + " public:", 0), + // template struct IFactory;\ntemplate \nstruct IFactory + (new Regex(@"(?\r?\n)(?[ \t]*)interface (?[a-zA-Z0-9]+)<(?[a-zA-Z0-9 ,]+)>(?[^{]+){"), "${before}${indent}template struct ${interface};" + Environment.NewLine + "${indent}template " + Environment.NewLine + "${indent}struct ${interface}<${typeParameters}>${typeDefinitionEnding}{" + Environment.NewLine + " public:", 0), // template // template (new Regex(@"(?template <((, )?typename [a-zA-Z0-9]+)+, )(?[a-zA-Z0-9]+)(?(,|>))"), "${before}typename ${typeParameter}${after}", 10), @@ -279,8 +279,12 @@ public class CSharpToCppTransformer : TextTransformer // class IProperty : public ISetter, public IProvider (new Regex(@"(?(interface|struct|class) [a-zA-Z_]\w* : ((public [a-zA-Z_][\w:]*(<[a-zA-Z0-9 ,]+>)?, )+)?)(?(?!public)[a-zA-Z_][\w:]*(<[a-zA-Z0-9 ,]+>)?)(?(, [a-zA-Z_][\w:]*(?!>)|[ \r\n]+))"), "${before}public ${inheritedType}${after}", 10), // interface IDisposable { - // class IDisposable { public: - (new Regex(@"(?\r?\n)(?[ \t]*)interface (?[a-zA-Z_]\w*)(?[^{]+){"), "${before}${indent}class ${interface}${typeDefinitionEnding}{" + Environment.NewLine + " public:", 0), + // struct IDisposable { public: + (new Regex(@"(?\r?\n)(?[ \t]*)interface (?[a-zA-Z_]\w*)(?[^{]+){"), "${before}${indent}struct ${interface}${typeDefinitionEnding}{" + Environment.NewLine + " public:", 0), + // Add virtual destructors for structs (originally interfaces) that contain virtual methods + // struct ITest { public: virtual void Method(T value) = 0; } + // struct ITest { public: virtual void Method(T value) = 0; virtual ~ITest() = default; } + (new Regex(@"(?struct (?[a-zA-Z_][a-zA-Z0-9_]*)[^{]*\{[^}]*public:[^}]*virtual[^}]*?(?=\r?\n[ \t]*}))(?\r?\n[ \t]*)(?})"), "${beforeEnd}${endIndent} virtual ~${structName}() = default;${endIndent}${end}", 0), // struct TreeElement { } // struct TreeElement { }; (new Regex(@"(struct|class) ([a-zA-Z0-9]+)(\s+){([\sa-zA-Z0-9;:_]+?)}([^;])"), "$1 $2$3{$4};$5", 0), @@ -752,6 +756,11 @@ public class CSharpToCppTransformer : TextTransformer // \n\n} // \n} (new Regex(@"\r?\n[ \t]*\r?\n(?[ \t]*})"), Environment.NewLine + "${end}", 10), + // Fix virtual destructors to use = default instead of = 0 (FINAL STAGE) + // Only applies to destructors that were already added (i.e. interfaces converted to structs) + // virtual ~ITest() = 0; + // virtual ~ITest() = default; + (new Regex(@"(\s*)virtual ~([a-zA-Z_][a-zA-Z0-9_]*)\(\) = 0;"), "$1virtual ~$2() = default;", 0), }.Cast().ToList(); /// From 8a3a40c49d53027487df0b051390214ef2c1f861 Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 13 Sep 2025 05:17:06 +0300 Subject: [PATCH 3/4] 'Auto-commit changes made by Claude MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude ' --- TestTransformer/SimpleTest.cs | 34 ++++++++++ examples/TestTransformer/Program.cs | 65 +++++++++++++++++++ .../TestTransformer/TestTransformer.csproj | 14 ++++ examples/current_behavior.txt | 43 ++++++++++++ examples/current_pragma_output.cpp | 0 examples/debug_destructor.cs | 4 ++ examples/test_current_transformer.cs | 51 +++++++++++++++ examples/test_interface.cs | 9 +++ examples/test_pragma_once.cs | 7 ++ examples/test_struct.cs | 5 ++ 10 files changed, 232 insertions(+) create mode 100644 TestTransformer/SimpleTest.cs create mode 100644 examples/TestTransformer/Program.cs create mode 100644 examples/TestTransformer/TestTransformer.csproj create mode 100644 examples/current_behavior.txt create mode 100644 examples/current_pragma_output.cpp create mode 100644 examples/debug_destructor.cs create mode 100644 examples/test_current_transformer.cs create mode 100644 examples/test_interface.cs create mode 100644 examples/test_pragma_once.cs create mode 100644 examples/test_struct.cs diff --git a/TestTransformer/SimpleTest.cs b/TestTransformer/SimpleTest.cs new file mode 100644 index 0000000..8450dd1 --- /dev/null +++ b/TestTransformer/SimpleTest.cs @@ -0,0 +1,34 @@ +using System; +using Platform.RegularExpressions.Transformer.CSharpToCpp; + +class SimpleTest +{ + static void Main(string[] args) + { + var transformer = new CSharpToCppTransformer(); + + // Test simple interface + string simpleInterface = @"interface ISimple +{ + void Method(); +}"; + + Console.WriteLine("=== SIMPLE INTERFACE TEST ==="); + Console.WriteLine("Input:"); + Console.WriteLine(simpleInterface); + Console.WriteLine("\nOutput:"); + Console.WriteLine(transformer.Transform(simpleInterface)); + + // Test templated interface + string templatedInterface = @"interface ITest +{ + void Method(T value); +}"; + + Console.WriteLine("\n=== TEMPLATED INTERFACE TEST ==="); + Console.WriteLine("Input:"); + Console.WriteLine(templatedInterface); + Console.WriteLine("\nOutput:"); + Console.WriteLine(transformer.Transform(templatedInterface)); + } +} \ No newline at end of file diff --git a/examples/TestTransformer/Program.cs b/examples/TestTransformer/Program.cs new file mode 100644 index 0000000..b9bc752 --- /dev/null +++ b/examples/TestTransformer/Program.cs @@ -0,0 +1,65 @@ +using System; +using Platform.RegularExpressions.Transformer.CSharpToCpp; + +class TestTransformer +{ + static void Main(string[] args) + { + var transformer = new CSharpToCppTransformer(); + + // Test pragma once + string pragmaTest = @"#pragma once +using System; + +class Test +{ + public void Method() { } +}"; + + Console.WriteLine("=== PRAGMA ONCE TEST ==="); + Console.WriteLine("Input:"); + Console.WriteLine(pragmaTest); + Console.WriteLine("\nOutput:"); + Console.WriteLine(transformer.Transform(pragmaTest)); + + // Test simple interface + string simpleInterface = @" +interface ITest +{ + void Method(); +}"; + + Console.WriteLine("\n=== SIMPLE INTERFACE TEST ==="); + Console.WriteLine("Input:"); + Console.WriteLine(simpleInterface); + Console.WriteLine("\nOutput:"); + var simpleOutput = transformer.Transform(simpleInterface); + Console.WriteLine(simpleOutput); + + // Test templated interface + string interfaceTest = @" +interface ITest +{ + void Method(T value); +}"; + + Console.WriteLine("\n=== TEMPLATED INTERFACE TEST ==="); + Console.WriteLine("Input:"); + Console.WriteLine(interfaceTest); + Console.WriteLine("\nOutput:"); + Console.WriteLine(transformer.Transform(interfaceTest)); + + // Test struct + string structTest = @"struct TestStruct +{ + public T Value { get; set; } + public void Method() { } +}"; + + Console.WriteLine("\n=== STRUCT TEST ==="); + Console.WriteLine("Input:"); + Console.WriteLine(structTest); + Console.WriteLine("\nOutput:"); + Console.WriteLine(transformer.Transform(structTest)); + } +} diff --git a/examples/TestTransformer/TestTransformer.csproj b/examples/TestTransformer/TestTransformer.csproj new file mode 100644 index 0000000..329960d --- /dev/null +++ b/examples/TestTransformer/TestTransformer.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/examples/current_behavior.txt b/examples/current_behavior.txt new file mode 100644 index 0000000..27eaab8 --- /dev/null +++ b/examples/current_behavior.txt @@ -0,0 +1,43 @@ +=== PRAGMA ONCE TEST === +Input: +#pragma once +using System; + +class Test +{ + public void Method() { } +} + +Output: +class Test +{ + public: void Method() { } +}; + +=== INTERFACE TEST === +Input: +interface ITest +{ + void Method(T value); +} + +Output: +interface ITest +{ + virtual void Method(T value) = 0; +} + +=== STRUCT TEST === +Input: +struct TestStruct +{ + public T Value { get; set; } + public void Method() { } +} + +Output: +struct TestStruct +{ + public: inline T Value; + public: void Method() { } +}; diff --git a/examples/current_pragma_output.cpp b/examples/current_pragma_output.cpp new file mode 100644 index 0000000..e69de29 diff --git a/examples/debug_destructor.cs b/examples/debug_destructor.cs new file mode 100644 index 0000000..4a0fb31 --- /dev/null +++ b/examples/debug_destructor.cs @@ -0,0 +1,4 @@ +interface ITest +{ + void Method(); +} \ No newline at end of file diff --git a/examples/test_current_transformer.cs b/examples/test_current_transformer.cs new file mode 100644 index 0000000..053001c --- /dev/null +++ b/examples/test_current_transformer.cs @@ -0,0 +1,51 @@ +using System; +using System.IO; +using Platform.RegularExpressions.Transformer.CSharpToCpp; + +class TestTransformer +{ + static void Main(string[] args) + { + var transformer = new CSharpToCppTransformer(); + + // Test pragma once + string pragmaTest = @"#pragma once +using System; + +class Test +{ + public void Method() { } +}"; + + Console.WriteLine("=== PRAGMA ONCE TEST ==="); + Console.WriteLine("Input:"); + Console.WriteLine(pragmaTest); + Console.WriteLine("\nOutput:"); + Console.WriteLine(transformer.Transform(pragmaTest)); + + // Test interface + string interfaceTest = @"interface ITest +{ + void Method(T value); +}"; + + Console.WriteLine("\n=== INTERFACE TEST ==="); + Console.WriteLine("Input:"); + Console.WriteLine(interfaceTest); + Console.WriteLine("\nOutput:"); + Console.WriteLine(transformer.Transform(interfaceTest)); + + // Test struct + string structTest = @"struct TestStruct +{ + public T Value { get; set; } + public void Method() { } +}"; + + Console.WriteLine("\n=== STRUCT TEST ==="); + Console.WriteLine("Input:"); + Console.WriteLine(structTest); + Console.WriteLine("\nOutput:"); + Console.WriteLine(transformer.Transform(structTest)); + } +} \ No newline at end of file diff --git a/examples/test_interface.cs b/examples/test_interface.cs new file mode 100644 index 0000000..7ec0aa9 --- /dev/null +++ b/examples/test_interface.cs @@ -0,0 +1,9 @@ +interface ITest +{ + void Method(T value); +} + +class Implementation : ITest +{ + public void Method(T value) { } +} \ No newline at end of file diff --git a/examples/test_pragma_once.cs b/examples/test_pragma_once.cs new file mode 100644 index 0000000..76abf1c --- /dev/null +++ b/examples/test_pragma_once.cs @@ -0,0 +1,7 @@ +#pragma once +using System; + +class Test +{ + public void Method() { } +} \ No newline at end of file diff --git a/examples/test_struct.cs b/examples/test_struct.cs new file mode 100644 index 0000000..2a9bbe2 --- /dev/null +++ b/examples/test_struct.cs @@ -0,0 +1,5 @@ +struct TestStruct +{ + public T Value { get; set; } + public void Method() { } +} \ No newline at end of file From 629458868c78885609968a4ecbe687cfea7c90f9 Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 13 Sep 2025 05:17:07 +0300 Subject: [PATCH 4/4] Remove CLAUDE.md - Claude command completed --- CLAUDE.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index ac64741..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -Issue to solve: https://github.com/linksplatform/RegularExpressions.Transformer.CSharpToCpp/issues/67 -Your prepared branch: issue-67-0326ea0e -Your prepared working directory: /tmp/gh-issue-solver-1757727040312 - -Proceed. \ No newline at end of file