Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 <string>

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<int> getNumber;

public int GetMaxValue()
{
return int.MaxValue;
}

public void ProcessException(Exception ex)
{
// Handle exception
}
}";
const string expectedResult = @"#include <cstdint>
#include <exception>
#include <functional>
#include <limits>
#include <string>

class Test
{
private: std::string message = 0;
private: std::function<int()> getNumber;

public: std::int32_t GetMaxValue()
{
return std::numeric_limits<std::int32_t>::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 <cstdint>

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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,14 @@ public class CSharpToCppTransformer : TextTransformer
(new Regex(@"\r?\n[ \t]*\r?\n(?<end>[ \t]*})"), Environment.NewLine + "${end}", 10),
}.Cast<ISubstitutionRule>().ToList();

/// <summary>
/// <para>
/// Gets or sets a value indicating whether to automatically generate include statements for std library features.
/// </para>
/// <para></para>
/// </summary>
public bool AutoGenerateIncludes { get; set; } = true;

/// <summary>
/// <para>
/// Initializes a new <see cref="CSharpToCppTransformer"/> instance.
Expand All @@ -773,5 +781,89 @@ public CSharpToCppTransformer(IList<ISubstitutionRule> extraRules) : base(FirstS
/// <para></para>
/// </summary>
public CSharpToCppTransformer() : base(FirstStage.Concat(LastStage).ToList()) { }

/// <summary>
/// <para>
/// Maps std library features to their required header files.
/// </para>
/// <para></para>
/// </summary>
private static readonly Dictionary<string, string> StdLibraryIncludes = new Dictionary<string, string>
{
{ "std::string", "<string>" },
{ "std::vector", "<vector>" },
{ "std::function", "<functional>" },
{ "std::tuple", "<tuple>" },
{ "std::numeric_limits", "<limits>" },
{ "std::exception", "<exception>" },
{ "std::mutex", "<mutex>" },
{ "std::lock_guard", "<mutex>" },
{ "std::ostream", "<ostream>" },
{ "std::int8_t", "<cstdint>" },
{ "std::int16_t", "<cstdint>" },
{ "std::int32_t", "<cstdint>" },
{ "std::int64_t", "<cstdint>" },
{ "std::uint8_t", "<cstdint>" },
{ "std::uint16_t", "<cstdint>" },
{ "std::uint32_t", "<cstdint>" },
{ "std::uint64_t", "<cstdint>" }
};

/// <summary>
/// <para>
/// Analyzes the transformed output and generates necessary include statements.
/// </para>
/// <para></para>
/// </summary>
/// <param name="transformedCode">
/// <para>The transformed C++ code.</para>
/// <para></para>
/// </param>
/// <returns>
/// <para>A string containing the necessary include statements.</para>
/// <para></para>
/// </returns>
private static string GenerateIncludes(string transformedCode)
{
var requiredIncludes = new HashSet<string>();

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;
}

/// <summary>
/// <para>
/// Transforms the specified text from C# to C++ and generates necessary includes.
/// </para>
/// <para></para>
/// </summary>
/// <param name="text">
/// <para>The text to transform.</para>
/// <para></para>
/// </param>
/// <returns>
/// <para>The transformed C++ text with necessary includes.</para>
/// <para></para>
/// </returns>
public string TransformWithIncludes(string text)
{
var transformed = Transform(text);
var includes = GenerateIncludes(transformed);
return includes + transformed;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Description>LinksPlatform's Platform.RegularExpressions.Transformer.CSharpToCpp Class Library</Description>
<Copyright>Konstantin Diachenko</Copyright>
<AssemblyTitle>Platform.RegularExpressions.Transformer.CSharpToCpp</AssemblyTitle>
<VersionPrefix>0.3.0</VersionPrefix>
<VersionPrefix>0.4.0</VersionPrefix>
<Authors>Konstantin Diachenko</Authors>
<TargetFramework>net8</TargetFramework>
<AssemblyName>Platform.RegularExpressions.Transformer.CSharpToCpp</AssemblyName>
Expand All @@ -23,7 +23,7 @@
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<LangVersion>latest</LangVersion>
<PackageReleaseNotes>Update target framework from net7 to net8.</PackageReleaseNotes>
<PackageReleaseNotes>Add automatic generation of necessary C++ standard library includes when using std library features. New TransformWithIncludes method provides transformation with required include statements.</PackageReleaseNotes>
<Nullable>enable</Nullable>
</PropertyGroup>

Expand Down
32 changes: 32 additions & 0 deletions experiments/Program.cs
Original file line number Diff line number Diff line change
@@ -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<int> 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("==============");
}
}
12 changes: 12 additions & 0 deletions experiments/test.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="../csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/Platform.RegularExpressions.Transformer.CSharpToCpp.csproj" />
</ItemGroup>

</Project>
28 changes: 28 additions & 0 deletions experiments/test_python_includes.py
Original file line number Diff line number Diff line change
@@ -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 <string>" 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()
42 changes: 42 additions & 0 deletions python/cs2cpp/cs2cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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": "<string>",
"std::vector": "<vector>",
"std::function": "<functional>",
"std::tuple": "<tuple>",
"std::numeric_limits": "<limits>",
"std::exception": "<exception>",
"std::mutex": "<mutex>",
"std::lock_guard": "<mutex>",
"std::ostream": "<ostream>",
"std::int8_t": "<cstdint>",
"std::int16_t": "<cstdint>",
"std::int32_t": "<cstdint>",
"std::int64_t": "<cstdint>",
"std::uint8_t": "<cstdint>",
"std::uint16_t": "<cstdint>",
"std::uint32_t": "<cstdint>",
"std::uint64_t": "<cstdint>"
}

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 = [
# // ...
Expand Down
Loading