diff --git a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp.Tests/CSharpToCppTransformerTests.cs b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp.Tests/CSharpToCppTransformerTests.cs index edca381..927e3f9 100644 --- a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp.Tests/CSharpToCppTransformerTests.cs +++ b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp.Tests/CSharpToCppTransformerTests.cs @@ -35,5 +35,105 @@ public static void Main(string[] args) var actualResult = transformer.Transform(helloWorldCode); Assert.Equal(expectedResult, actualResult); } + + [Fact] + public void IncludeGenerationBasicStringTest() + { + const string inputCode = @"class Test +{ + public static void Method(string text) + { + // Do something with text + } +}"; + const string expectedResult = @"#include + +class Test +{ + public: static void Method(std::string text) + { + } +};"; + var transformer = new CSharpToCppTransformer(); + var actualResult = transformer.TransformWithIncludes(inputCode); + Assert.Equal(expectedResult, actualResult); + } + + [Fact] + public void IncludeGenerationMultipleStdFeaturesTest() + { + const string inputCode = @"using System; + +class Test +{ + private string message; + private Func getNumber; + + public int GetMaxValue() + { + return int.MaxValue; + } + + public void ProcessException(Exception ex) + { + // Handle exception + } +}"; + const string expectedResult = @"#include +#include +#include +#include +#include + +class Test +{ + private: std::string message = 0; + private: std::function getNumber; + + public: std::int32_t GetMaxValue() + { + return std::numeric_limits::max(); + } + + public: void ProcessException(const std::exception& ex) + { + } +};"; + var transformer = new CSharpToCppTransformer(); + var actualResult = transformer.TransformWithIncludes(inputCode); + Assert.Equal(expectedResult, actualResult); + } + + [Fact] + public void IncludeGenerationNoStdFeaturesTest() + { + const string inputCode = @"class SimpleTest +{ + public void Method() + { + int x = 42; + } +}"; + const string expectedResult = @"#include + +class SimpleTest +{ + public: void Method() + { + std::int32_t x = 42; + } +};"; + var transformer = new CSharpToCppTransformer(); + var actualResult = transformer.TransformWithIncludes(inputCode); + Assert.Equal(expectedResult, actualResult); + } + + [Fact] + public void IncludeGenerationEmptyCodeTest() + { + var transformer = new CSharpToCppTransformer(); + var actualResult = transformer.TransformWithIncludes(""); + Assert.Equal("", actualResult); + } } } diff --git a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/CSharpToCppTransformer.cs b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/CSharpToCppTransformer.cs index 2f5dceb..205aac3 100644 --- a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/CSharpToCppTransformer.cs +++ b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/CSharpToCppTransformer.cs @@ -754,6 +754,14 @@ public class CSharpToCppTransformer : TextTransformer (new Regex(@"\r?\n[ \t]*\r?\n(?[ \t]*})"), Environment.NewLine + "${end}", 10), }.Cast().ToList(); + /// + /// + /// Gets or sets a value indicating whether to automatically generate include statements for std library features. + /// + /// + /// + public bool AutoGenerateIncludes { get; set; } = true; + /// /// /// Initializes a new instance. @@ -773,5 +781,89 @@ public CSharpToCppTransformer(IList extraRules) : base(FirstS /// /// public CSharpToCppTransformer() : base(FirstStage.Concat(LastStage).ToList()) { } + + /// + /// + /// Maps std library features to their required header files. + /// + /// + /// + private static readonly Dictionary StdLibraryIncludes = new Dictionary + { + { "std::string", "" }, + { "std::vector", "" }, + { "std::function", "" }, + { "std::tuple", "" }, + { "std::numeric_limits", "" }, + { "std::exception", "" }, + { "std::mutex", "" }, + { "std::lock_guard", "" }, + { "std::ostream", "" }, + { "std::int8_t", "" }, + { "std::int16_t", "" }, + { "std::int32_t", "" }, + { "std::int64_t", "" }, + { "std::uint8_t", "" }, + { "std::uint16_t", "" }, + { "std::uint32_t", "" }, + { "std::uint64_t", "" } + }; + + /// + /// + /// Analyzes the transformed output and generates necessary include statements. + /// + /// + /// + /// + /// The transformed C++ code. + /// + /// + /// + /// A string containing the necessary include statements. + /// + /// + private static string GenerateIncludes(string transformedCode) + { + var requiredIncludes = new HashSet(); + + foreach (var stdFeature in StdLibraryIncludes.Keys) + { + if (transformedCode.Contains(stdFeature)) + { + requiredIncludes.Add(StdLibraryIncludes[stdFeature]); + } + } + + if (requiredIncludes.Count == 0) + { + return string.Empty; + } + + var sortedIncludes = requiredIncludes.OrderBy(x => x).ToList(); + var includeStatements = sortedIncludes.Select(include => $"#include {include}").ToArray(); + return string.Join(Environment.NewLine, includeStatements) + Environment.NewLine + Environment.NewLine; + } + + /// + /// + /// Transforms the specified text from C# to C++ and generates necessary includes. + /// + /// + /// + /// + /// The text to transform. + /// + /// + /// + /// The transformed C++ text with necessary includes. + /// + /// + public string TransformWithIncludes(string text) + { + var transformed = Transform(text); + var includes = GenerateIncludes(transformed); + return includes + transformed; + } } } diff --git a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/Platform.RegularExpressions.Transformer.CSharpToCpp.csproj b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/Platform.RegularExpressions.Transformer.CSharpToCpp.csproj index 1f9c254..035ac61 100644 --- a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/Platform.RegularExpressions.Transformer.CSharpToCpp.csproj +++ b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/Platform.RegularExpressions.Transformer.CSharpToCpp.csproj @@ -4,7 +4,7 @@ LinksPlatform's Platform.RegularExpressions.Transformer.CSharpToCpp Class Library Konstantin Diachenko Platform.RegularExpressions.Transformer.CSharpToCpp - 0.3.0 + 0.4.0 Konstantin Diachenko net8 Platform.RegularExpressions.Transformer.CSharpToCpp @@ -23,7 +23,7 @@ true snupkg latest - Update target framework from net7 to net8. + Add automatic generation of necessary C++ standard library includes when using std library features. New TransformWithIncludes method provides transformation with required include statements. enable diff --git a/experiments/Program.cs b/experiments/Program.cs new file mode 100644 index 0000000..97576c4 --- /dev/null +++ b/experiments/Program.cs @@ -0,0 +1,32 @@ +using System; +using Platform.RegularExpressions.Transformer.CSharpToCpp; + +public class Debug2 +{ + public static void Main() + { + const string inputCode = @"using System; + +class Test +{ + private string message; + private Func getNumber; + + public int GetMaxValue() + { + return int.MaxValue; + } + + public void ProcessException(Exception ex) + { + // Handle exception + } +}"; + var transformer = new CSharpToCppTransformer(); + var actualResult = transformer.TransformWithIncludes(inputCode); + Console.WriteLine("ACTUAL OUTPUT:"); + Console.WriteLine("=============="); + Console.WriteLine(actualResult); + Console.WriteLine("=============="); + } +} \ No newline at end of file diff --git a/experiments/test.csproj b/experiments/test.csproj new file mode 100644 index 0000000..279a120 --- /dev/null +++ b/experiments/test.csproj @@ -0,0 +1,12 @@ + + + + Exe + net8 + + + + + + + \ No newline at end of file diff --git a/experiments/test_python_includes.py b/experiments/test_python_includes.py new file mode 100644 index 0000000..a65a4df --- /dev/null +++ b/experiments/test_python_includes.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +import sys +sys.path.append('../python') + +from cs2cpp.cs2cpp import CSharpToCpp + +def test_include_generation(): + print("Testing Python include generation...") + + transformer = CSharpToCpp() + + # Simple test with just std::string + test_code = "class Test { string name; }" + + try: + result = transformer.translate(test_code) + print(f"Input: {test_code}") + print(f"Output: {result}") + + if "#include " in result: + print("✓ Include generation working!") + else: + print("✗ Include generation not working") + except Exception as e: + print(f"Error: {e}") + +if __name__ == "__main__": + test_include_generation() \ No newline at end of file diff --git a/python/cs2cpp/cs2cpp.py b/python/cs2cpp/cs2cpp.py index 44ab7bb..6ad45b1 100644 --- a/python/cs2cpp/cs2cpp.py +++ b/python/cs2cpp/cs2cpp.py @@ -21,6 +21,48 @@ def __init__( self.rules.extend(CSharpToCpp.LAST_RULES) Translator.__init__(self, self.rules) + # Mapping of std library features to their required headers + STD_LIBRARY_INCLUDES = { + "std::string": "", + "std::vector": "", + "std::function": "", + "std::tuple": "", + "std::numeric_limits": "", + "std::exception": "", + "std::mutex": "", + "std::lock_guard": "", + "std::ostream": "", + "std::int8_t": "", + "std::int16_t": "", + "std::int32_t": "", + "std::int64_t": "", + "std::uint8_t": "", + "std::uint16_t": "", + "std::uint32_t": "", + "std::uint64_t": "" + } + + def _generate_includes(self, transformed_code: str) -> str: + """Analyzes the transformed output and generates necessary include statements.""" + required_includes = set() + + for std_feature in self.STD_LIBRARY_INCLUDES: + if std_feature in transformed_code: + required_includes.add(self.STD_LIBRARY_INCLUDES[std_feature]) + + if not required_includes: + return "" + + sorted_includes = sorted(required_includes) + include_statements = [f"#include {include}" for include in sorted_includes] + return "\n".join(include_statements) + "\n\n" + + def translate(self, text: str) -> str: + """Transforms C# code to C++ and generates necessary includes.""" + transformed = super().translate(text) + includes = self._generate_includes(transformed) + return includes + transformed + # Rules for translate code FIRST_RULES = [ # // ...