using System.Diagnostics; using System.Text; using System.Text.RegularExpressions; using CodePlay.Core.Interfaces; using CodePlay.Core.Models; using CodePlay.Core.Common; using CodePlay.Core.Pipeline; using CodePlay.Core.Pipeline.Converters; namespace CodePlay.Core.Converters; /// /// 命名风格转换器 - C# PascalCase → Java camelCase /// public class NamingConverter { /// /// 将 C# 命名转换为 Java 风格 /// PascalCase → camelCase (方法和变量名) /// PascalCase → PascalCase (类名保持不变) /// public string ConvertMethodName(string name) { if (string.IsNullOrEmpty(name) || char.IsLower(name[0])) return name; return char.ToLowerInvariant(name[0]) + name.Substring(1); } public string ConvertFieldName(string name) { if (string.IsNullOrEmpty(name) || char.IsLower(name[0])) return name; return char.ToLowerInvariant(name[0]) + name.Substring(1); } } /// /// C# 到 Java 转换策略 - 使用管道模式,每条转换规则独立 /// public class CSharpToJavaStrategy : IConversionStrategy { public LanguageType SourceLanguage => LanguageType.CSharp; public LanguageType TargetLanguage => LanguageType.Java; private readonly ConversionPipeline _pipeline; private readonly ITypeMapper _typeMapper; private readonly NamingConverter _namingConverter; public CSharpToJavaStrategy() { _pipeline = CreatePipeline(); _typeMapper = new CSharpJavaTypeMapper(); _namingConverter = new NamingConverter(); } /// /// 创建转换管道 - 按优先级顺序注册所有转换器 /// private ConversionPipeline CreatePipeline() { var pipeline = new ConversionPipeline(); // 按优先级顺序注册转换器 (数值越小优先级越高) // 5-15: 结构级转换 (Record) pipeline.Register(new RecordConverter()); // 20-35: 主构造函数 pipeline.Register(new PrimaryConstructorConverter()); // 10-30: 类型映射 pipeline.Register(new NullableTypeConverter()); pipeline.Register(new PrimitiveTypeConverter()); pipeline.Register(new CollectionTypeConverter()); // 40-55: 结构处理 + switch 表达式 pipeline.Register(new InheritanceConverter()); pipeline.Register(new NullCoalescingConverter()); pipeline.Register(new ModifierRemover()); pipeline.Register(new SwitchExpressionConverter()); // 50-70: 语法转换 pipeline.Register(new LambdaConverter()); pipeline.Register(new PatternMatchingConverter()); pipeline.Register(new PropertyConverter()); // 80-100: API 映射 pipeline.Register(new LinqToStreamConverter()); pipeline.Register(new AsyncConverter()); pipeline.Register(new RangeIndexConverter()); // 110+: 输出处理 pipeline.Register(new ConsoleConverter()); return pipeline; } public SyntaxNode ConvertNode(SyntaxNode node, ConversionContext context) { var newNode = new SyntaxNode { Type = node.Type, Text = ConvertText(node.Text ?? "", context), Children = new List() }; foreach (var child in node.Children) { var convertedChild = ConvertNode(child, context); convertedChild.Parent = newNode; newNode.Children.Add(convertedChild); } return newNode; } public string MapType(string sourceType) { return _typeMapper.MapType(sourceType); } private string ConvertText(string text, ConversionContext context) { if (string.IsNullOrWhiteSpace(text)) return text; var sw = Stopwatch.StartNew(); var packageName = ""; var imports = new HashSet(); var codeLines = new List(); var docStrings = new List<(int LineIndex, string Content)>(); var lines = text.Split('\n').ToList(); for (int i = 0; i < lines.Count; i++) { var line = lines[i]; var processedLine = line.Trim(); if (string.IsNullOrWhiteSpace(processedLine)) continue; // XML 文档注释 (/// ... ) if (processedLine.StartsWith("///")) { if (context.Options?.KeepDocStrings == true) { docStrings.Add((codeLines.Count, processedLine)); } continue; } // 单行注释 (//) if (processedLine.StartsWith("//")) { if (context.Options?.KeepComments == true) { codeLines.Add(processedLine); } continue; } // 多行注释 (/* ... */) if (processedLine.StartsWith("/*") || processedLine.StartsWith("*") || processedLine.StartsWith("*/")) { if (context.Options?.KeepComments == true) { codeLines.Add(processedLine); } continue; } // File-scoped namespace if (processedLine.StartsWith("namespace ") && !processedLine.Contains("{")) { var nsMatch = Regex.Match(processedLine, @"namespace\s+([\w.]+)"); if (nsMatch.Success) packageName = nsMatch.Groups[1].Value; continue; } // Braced namespace if (processedLine.StartsWith("namespace ") && processedLine.Contains("{")) { var nsMatch = Regex.Match(processedLine, @"namespace\s+([\w.]+)"); if (nsMatch.Success) packageName = nsMatch.Groups[1].Value; continue; } // Skip namespace block braces if (processedLine == "{" || processedLine == "}") continue; // Using statements if (processedLine.StartsWith("using ")) { var usingMatch = Regex.Match(processedLine, @"using\s+([\w.]+);"); if (usingMatch.Success) imports.Add($"import {usingMatch.Groups[1].Value};"); continue; } // 检测不可转换语法并记录 issue DetectUnconvertibleSyntax(processedLine, context); // 应用转换管道 var convertedLine = _pipeline.Execute(processedLine, context); // 在转换后的代码前插入文档注释 if (docStrings.Count > 0 && docStrings[0].LineIndex == codeLines.Count) { var pendingDocs = docStrings.Where(d => d.LineIndex == codeLines.Count).ToList(); foreach (var doc in pendingDocs) { // 将 XML Doc 转换为 JavaDoc 格式 var javadoc = ConvertXmlDocToJavadoc(doc.Content); codeLines.Add(javadoc); } docStrings.RemoveAll(d => d.LineIndex == codeLines.Count - pendingDocs.Count); } codeLines.Add(convertedLine); } sw.Stop(); // 生成输出 var output = new StringBuilder(); if (!string.IsNullOrEmpty(packageName)) output.AppendLine($"package {packageName};"); foreach (var imp in imports.OrderBy(i => i)) output.AppendLine(imp); if (imports.Count > 0 || !string.IsNullOrEmpty(packageName)) output.AppendLine(); foreach (var line in codeLines) { if (!string.IsNullOrWhiteSpace(line)) output.AppendLine(line); } return output.ToString().TrimEnd(); } /// /// 将 C# XML 文档注释转换为 JavaDoc 格式 /// private string ConvertXmlDocToJavadoc(string xmlDocLine) { return xmlDocLine .Replace("///", " *") .Replace("", "") .Replace("", "") .Replace("", "@return") .Replace("", "") .Replace("", "") .Trim(); } /// /// 检测不可直接转换的 C# 语法 /// private static void DetectUnconvertibleSyntax(string line, ConversionContext context) { // 检测 LINQ 链式调用 - 需要转换为 Stream API if (Regex.IsMatch(line, @"\.where\s*\(.*\)\s*\.select\s*\(", RegexOptions.IgnoreCase) || Regex.IsMatch(line, @"\.orderby\s*\(") || Regex.IsMatch(line, @"\.groupby\s*\(")) { context.Issues.Add(new ConversionIssue { Type = "UnconvertibleSyntax", Severity = "Low", Description = "LINQ method chain detected - auto-converted to Stream API", Suggestion = "Verify Stream API equivalence manually", SourceSyntax = line.Trim() }); } // 检测 async/await - 需要转换为 CompletableFuture 或回调 if (Regex.IsMatch(line, @"\basync\b|\bawait\b")) { context.Issues.Add(new ConversionIssue { Type = "UnconvertibleSyntax", Severity = "Medium", Description = "async/await pattern detected, converted to synchronous call", Suggestion = "Consider using CompletableFuture or Executor for async operations", SourceSyntax = line.Trim() }); } // 检测 record - 需确认转换正确性 if (Regex.IsMatch(line, @"\brecord\s+\w+")) { context.Issues.Add(new ConversionIssue { Type = "UnconvertibleSyntax", Severity = "Low", Description = "Record type converted to class", Suggestion = "Consider adding @Value annotation for immutability (Lombok)", SourceSyntax = line.Trim() }); } // 检测 init-only 属性 - 语义丢失警告 if (Regex.IsMatch(line, @"get;\s*init;")) { context.Issues.Add(new ConversionIssue { Type = "UnconvertibleSyntax", Severity = "Low", Description = "Init-only property: immutability is lost in Java setter", Suggestion = "Remove the setter or mark the field as @ReadOnly", SourceSyntax = line.Trim() }); } // 检测 var 隐式类型 - 警告 if (Regex.IsMatch(line, @"\bvar\s+\w+\s*=")) { context.Issues.Add(new ConversionIssue { Type = "UnconvertibleSyntax", Severity = "Low", Description = "Implicit type 'var' mapped to Object", Suggestion = "Use explicit type declaration", SourceSyntax = line.Trim() }); } // 检测 switch 表达式 - 需验证转换正确性 if (Regex.IsMatch(line, @"\bswitch\s*{")) { context.Issues.Add(new ConversionIssue { Type = "UnconvertibleSyntax", Severity = "Low", Description = "Switch expression converted to if-else chain", Suggestion = "Verify logic equivalence manually", SourceSyntax = line.Trim() }); } // 检测主构造函数 - 需验证 if (Regex.IsMatch(line, @"class\s+\w+\s*\(\s*\w+\s+\w+")) { context.Issues.Add(new ConversionIssue { Type = "UnconvertibleSyntax", Severity = "Low", Description = "Primary constructor converted to traditional constructor", Suggestion = "Verify field assignments in generated constructor", SourceSyntax = line.Trim() }); } } } /// /// C# 到 Java 类型映射器 /// public class CSharpJavaTypeMapper : ITypeMapper { private readonly Dictionary _mappings = new() { { "string", "String" }, { "int", "Integer" }, { "long", "Long" }, { "float", "Float" }, { "double", "Double" }, { "bool", "Boolean" }, { "byte", "Byte" }, { "char", "Character" }, { "short", "Short" }, { "void", "void" }, { "var", "Object" }, { "object", "Object" }, }; public string MapType(string sourceType) { return _mappings.TryGetValue(sourceType, out var target) ? target : sourceType; } public string MapGenericType(string sourceType) { var match = Regex.Match(sourceType, @"(\w+)<(.+)>"); if (match.Success) { var outer = MapType(match.Groups[1].Value); var inner = match.Groups[2].Value; return $"{outer}<{inner}>"; } return MapType(sourceType); } }