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/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(); /// 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