Task 2.2 - Java 完整解析器: - JavaParser: 支持包声明、导入语句、类/接口/枚举提取 - 提取方法、字段、构造函数、参数 - 提取单行/多行注释和 JavaDoc 文档 - 10 个单元测试全部通过 Task 2.8 - 不可转换语法处理: - UnconvertibleSyntaxHandler: 检测 C# 特有语法 - 支持检测:async/await, LINQ, dynamic, var, yield, record 等 - 检测模式:空条件运算符.?,空合并??, 字符串插值$等 - 转换可行性评估:置信度评分和努力程度估算 - 自动生成 TODO 注释标记 - 3 个单元测试通过 Task 4.2 - API 认证: - AuthController: JWT 认证端点 (login, refresh, me) - Program.cs: JWT Bearer 认证配置 - Swagger 集成认证支持 总计:39 个测试全部通过 ✅ Co-authored-by: monkeycode-ai <[email protected]>
388 lines
14 KiB
C#
388 lines
14 KiB
C#
using System.Text;
|
|
using CodePlay.Core.Interfaces;
|
|
using CodePlay.Core.Models;
|
|
using CodePlay.Core.Common;
|
|
|
|
namespace CodePlay.Core.Parsers;
|
|
|
|
/// <summary>
|
|
/// Java 语法解析器(完整版)
|
|
/// </summary>
|
|
public class JavaParser : BaseParser
|
|
{
|
|
/// <summary>
|
|
/// 支持的语言类型
|
|
/// </summary>
|
|
public override LanguageType SupportedLanguage => LanguageType.Java;
|
|
|
|
/// <summary>
|
|
/// 解析 Java 源代码
|
|
/// </summary>
|
|
public override Task<Interfaces.SyntaxTree> ParseAsync(string sourceCode, CancellationToken cancellationToken = default)
|
|
{
|
|
var tree = CreateSyntaxTree();
|
|
tree.SourceCode = sourceCode;
|
|
|
|
var root = new Interfaces.SyntaxNode
|
|
{
|
|
Type = SyntaxNodeType.CompilationUnit,
|
|
Text = sourceCode
|
|
};
|
|
|
|
// 提取包声明
|
|
ExtractPackage(tree, sourceCode, root);
|
|
|
|
// 提取导入语句
|
|
ExtractImports(tree, sourceCode, root);
|
|
|
|
// 提取类和接口
|
|
ExtractTypes(tree, sourceCode, root);
|
|
|
|
// 提取注释
|
|
ExtractComments(tree, sourceCode);
|
|
|
|
// 提取文档注释
|
|
ExtractDocumentation(tree, sourceCode);
|
|
|
|
tree.Root = root;
|
|
|
|
return Task.FromResult(tree);
|
|
}
|
|
|
|
private void ExtractPackage(Interfaces.SyntaxTree tree, string sourceCode, Interfaces.SyntaxNode root)
|
|
{
|
|
var packageMatch = System.Text.RegularExpressions.Regex.Match(sourceCode, @"^package\s+([\w.]+)\s*;", System.Text.RegularExpressions.RegexOptions.Multiline);
|
|
if (packageMatch.Success)
|
|
{
|
|
var packageNode = new Interfaces.SyntaxNode
|
|
{
|
|
Type = SyntaxNodeType.Namespace,
|
|
Text = packageMatch.Value,
|
|
Metadata = new Dictionary<string, object?>
|
|
{
|
|
["packageName"] = packageMatch.Groups[1].Value
|
|
}
|
|
};
|
|
|
|
root.Children.Add(packageNode);
|
|
|
|
tree.Documentation.Add(new SyntaxDocumentation
|
|
{
|
|
ElementName = "package",
|
|
Content = packageMatch.Groups[1].Value,
|
|
Format = DocFormat.JavaDoc
|
|
});
|
|
}
|
|
}
|
|
|
|
private void ExtractImports(Interfaces.SyntaxTree tree, string sourceCode, Interfaces.SyntaxNode root)
|
|
{
|
|
var importPattern = @"^import\s+(static\s+)?([\w.*]+)\s*;";
|
|
var importMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, importPattern, System.Text.RegularExpressions.RegexOptions.Multiline);
|
|
|
|
foreach (System.Text.RegularExpressions.Match match in importMatches)
|
|
{
|
|
var importNode = new Interfaces.SyntaxNode
|
|
{
|
|
Type = SyntaxNodeType.Field, // 使用 Field 暂时表示导入
|
|
Text = match.Value,
|
|
Metadata = new Dictionary<string, object?>
|
|
{
|
|
["isStatic"] = !string.IsNullOrEmpty(match.Groups[1].Value),
|
|
["importName"] = match.Groups[2].Value
|
|
}
|
|
};
|
|
|
|
root.Children.Add(importNode);
|
|
}
|
|
}
|
|
|
|
private void ExtractTypes(Interfaces.SyntaxTree tree, string sourceCode, Interfaces.SyntaxNode root)
|
|
{
|
|
// 提取类
|
|
ExtractClasses(sourceCode, root);
|
|
|
|
// 提取接口
|
|
ExtractInterfaces(sourceCode, root);
|
|
|
|
// 提取枚举
|
|
ExtractEnums(sourceCode, root);
|
|
}
|
|
|
|
private void ExtractClasses(string sourceCode, Interfaces.SyntaxNode root)
|
|
{
|
|
// 先提取类定义(简化版本,不处理多行)
|
|
var classPattern = @"(public|private|protected)?\s*(abstract|final|static)?\s*class\s+(\w+)(\s+extends\s+[\w<>.,\s]+)?(\s+implements\s+[\w<>.,\s]+)?";
|
|
var classMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, classPattern);
|
|
|
|
foreach (System.Text.RegularExpressions.Match match in classMatches)
|
|
{
|
|
var classNode = new Interfaces.SyntaxNode
|
|
{
|
|
Type = SyntaxNodeType.Class,
|
|
Text = match.Value,
|
|
Metadata = new Dictionary<string, object?>
|
|
{
|
|
["modifiers"] = match.Groups[1].Value,
|
|
["typeModifiers"] = match.Groups[2].Value,
|
|
["className"] = match.Groups[3].Value
|
|
}
|
|
};
|
|
|
|
root.Children.Add(classNode);
|
|
|
|
// 从整个源代码中提取该类的成员
|
|
ExtractClassMembers(sourceCode, classNode);
|
|
}
|
|
}
|
|
|
|
private void ExtractInterfaces(string sourceCode, Interfaces.SyntaxNode root)
|
|
{
|
|
var interfacePattern = @"(public)?\s*(interface)\s+(\w+)(\s+extends\s+([\w<>.,\s]+))?";
|
|
var interfaceMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, interfacePattern);
|
|
|
|
foreach (System.Text.RegularExpressions.Match match in interfaceMatches)
|
|
{
|
|
var interfaceNode = new Interfaces.SyntaxNode
|
|
{
|
|
Type = SyntaxNodeType.Interface,
|
|
Text = match.Value,
|
|
Metadata = new Dictionary<string, object?>
|
|
{
|
|
["modifiers"] = match.Groups[1].Value,
|
|
["interfaceName"] = match.Groups[3].Value,
|
|
["extends"] = string.IsNullOrEmpty(match.Groups[5].Value) ? null : match.Groups[5].Value
|
|
}
|
|
};
|
|
|
|
root.Children.Add(interfaceNode);
|
|
}
|
|
}
|
|
|
|
private void ExtractEnums(string sourceCode, Interfaces.SyntaxNode root)
|
|
{
|
|
var enumPattern = @"(public)?\s*(enum)\s+(\w+)";
|
|
var enumMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, enumPattern);
|
|
|
|
foreach (System.Text.RegularExpressions.Match match in enumMatches)
|
|
{
|
|
var enumNode = new Interfaces.SyntaxNode
|
|
{
|
|
Type = SyntaxNodeType.Class, // 暂时使用 Class
|
|
Text = match.Value,
|
|
Metadata = new Dictionary<string, object?>
|
|
{
|
|
["modifiers"] = match.Groups[1].Value,
|
|
["enumName"] = match.Groups[3].Value
|
|
}
|
|
};
|
|
|
|
root.Children.Add(enumNode);
|
|
}
|
|
}
|
|
|
|
private void ExtractClassMembers(string code, Interfaces.SyntaxNode classNode)
|
|
{
|
|
// 提取方法
|
|
ExtractMethods(code, classNode);
|
|
|
|
// 提取字段
|
|
ExtractFields(code, classNode);
|
|
|
|
// 提取构造函数
|
|
ExtractConstructors(code, classNode);
|
|
}
|
|
|
|
private void ExtractMethods(string code, Interfaces.SyntaxNode classNode)
|
|
{
|
|
// 简化的方法匹配:查找方法签名
|
|
var methodPattern = @"(public|private|protected)\s+(static\s+)?(\w+)\s+(\w+)\s*\(([^)]*)\)";
|
|
var methodMatches = System.Text.RegularExpressions.Regex.Matches(code, methodPattern);
|
|
|
|
foreach (System.Text.RegularExpressions.Match match in methodMatches)
|
|
{
|
|
// 过滤掉类的声明
|
|
if (match.Groups[3].Value == "class" || match.Groups[3].Value == "interface" || match.Groups[3].Value == "enum")
|
|
continue;
|
|
|
|
var methodNode = new Interfaces.SyntaxNode
|
|
{
|
|
Type = SyntaxNodeType.Method,
|
|
Text = match.Value,
|
|
Metadata = new Dictionary<string, object?>
|
|
{
|
|
["accessModifier"] = match.Groups[1].Value,
|
|
["isStatic"] = !string.IsNullOrEmpty(match.Groups[2].Value),
|
|
["returnType"] = match.Groups[3].Value,
|
|
["methodName"] = match.Groups[4].Value,
|
|
["parameters"] = match.Groups[5].Value
|
|
}
|
|
};
|
|
|
|
classNode.Children.Add(methodNode);
|
|
|
|
// 提取参数
|
|
ExtractParameters(match.Groups[5].Value, methodNode);
|
|
}
|
|
}
|
|
|
|
private void ExtractFields(string code, Interfaces.SyntaxNode classNode)
|
|
{
|
|
// 简化的字段匹配
|
|
var fieldPattern = @"(private|protected|public)\s+(static\s+)?(final\s+)?(\w+)\s+(\w+)\s*[;=]";
|
|
var fieldMatches = System.Text.RegularExpressions.Regex.Matches(code, fieldPattern);
|
|
|
|
foreach (System.Text.RegularExpressions.Match match in fieldMatches)
|
|
{
|
|
var fieldNode = new Interfaces.SyntaxNode
|
|
{
|
|
Type = SyntaxNodeType.Field,
|
|
Text = match.Value,
|
|
Metadata = new Dictionary<string, object?>
|
|
{
|
|
["accessModifier"] = match.Groups[1].Value,
|
|
["type"] = match.Groups[4].Value,
|
|
["fieldName"] = match.Groups[5].Value
|
|
}
|
|
};
|
|
|
|
classNode.Children.Add(fieldNode);
|
|
}
|
|
}
|
|
|
|
private void ExtractConstructors(string code, Interfaces.SyntaxNode classNode)
|
|
{
|
|
var constructorPattern = @"(public|private|protected)?\s+(\w+)\s*\(([^)]*)\)\s*(throws\s+[\w,\s]+)?\s*(\{[^}]*\})";
|
|
var constructorMatches = System.Text.RegularExpressions.Regex.Matches(code, constructorPattern);
|
|
|
|
foreach (System.Text.RegularExpressions.Match match in constructorMatches)
|
|
{
|
|
var className = classNode.Metadata.ContainsKey("className") ? classNode.Metadata["className"]?.ToString() : null;
|
|
|
|
// 确认是构造函数(名称与类名相同)
|
|
if (className != null && match.Groups[2].Value == className)
|
|
{
|
|
var constructorNode = new Interfaces.SyntaxNode
|
|
{
|
|
Type = SyntaxNodeType.Constructor,
|
|
Text = match.Value,
|
|
Metadata = new Dictionary<string, object?>
|
|
{
|
|
["accessModifier"] = match.Groups[1].Value,
|
|
["constructorName"] = match.Groups[2].Value,
|
|
["parameters"] = match.Groups[3].Value,
|
|
["throws"] = string.IsNullOrEmpty(match.Groups[4].Value) ? null : match.Groups[4].Value
|
|
}
|
|
};
|
|
|
|
classNode.Children.Add(constructorNode);
|
|
|
|
// 提取参数
|
|
ExtractParameters(match.Groups[3].Value, constructorNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ExtractParameters(string parametersText, Interfaces.SyntaxNode parentNode)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(parametersText))
|
|
return;
|
|
|
|
var paramPattern = @"(\w+(?:<[^>]+>)?)\s+(\w+)";
|
|
var paramMatches = System.Text.RegularExpressions.Regex.Matches(parametersText, paramPattern);
|
|
|
|
foreach (System.Text.RegularExpressions.Match match in paramMatches)
|
|
{
|
|
var paramNode = new Interfaces.SyntaxNode
|
|
{
|
|
Type = SyntaxNodeType.Parameter,
|
|
Text = match.Value,
|
|
Metadata = new Dictionary<string, object?>
|
|
{
|
|
["type"] = match.Groups[1].Value,
|
|
["name"] = match.Groups[2].Value
|
|
}
|
|
};
|
|
|
|
parentNode.Children.Add(paramNode);
|
|
}
|
|
}
|
|
|
|
private void ExtractComments(Interfaces.SyntaxTree tree, string sourceCode)
|
|
{
|
|
var lines = sourceCode.Split('\n');
|
|
bool inMultiLineComment = false;
|
|
var multiLineComment = new StringBuilder();
|
|
|
|
for (int i = 0; i < lines.Length; i++)
|
|
{
|
|
var line = lines[i];
|
|
|
|
// 单行注释
|
|
var singleLineMatch = System.Text.RegularExpressions.Regex.Match(line, @"//\s*(.*)");
|
|
if (singleLineMatch.Success)
|
|
{
|
|
tree.Comments.Add(new SyntaxComment
|
|
{
|
|
Text = $"// {singleLineMatch.Groups[1].Value}",
|
|
Type = CommentType.SingleLine,
|
|
LineNumber = i + 1
|
|
});
|
|
}
|
|
|
|
// 多行注释开始
|
|
if (line.Contains("/*") && !line.Contains("*/"))
|
|
{
|
|
inMultiLineComment = true;
|
|
multiLineComment.AppendLine(line);
|
|
continue;
|
|
}
|
|
|
|
// 多行注释中
|
|
if (inMultiLineComment && line.Contains("*/"))
|
|
{
|
|
multiLineComment.AppendLine(line);
|
|
if (line.Contains("*/"))
|
|
{
|
|
inMultiLineComment = false;
|
|
tree.Comments.Add(new SyntaxComment
|
|
{
|
|
Text = multiLineComment.ToString().Trim(),
|
|
Type = CommentType.MultiLine,
|
|
LineNumber = i - multiLineComment.ToString().Split('\n').Length + 1
|
|
});
|
|
multiLineComment.Clear();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ExtractDocumentation(Interfaces.SyntaxTree tree, string sourceCode)
|
|
{
|
|
var javaDocPattern = @"/\*\*\s*((?:(?!\*/)[\s\S])*)\*/";
|
|
var javaDocMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, javaDocPattern);
|
|
|
|
foreach (System.Text.RegularExpressions.Match match in javaDocMatches)
|
|
{
|
|
var content = match.Groups[1].Value.Trim();
|
|
var lineNumber = GetLineNumber(sourceCode, match.Index);
|
|
|
|
// 查找相邻的元素名称
|
|
var afterDoc = sourceCode.Substring(match.Index + match.Length);
|
|
var elementMatch = System.Text.RegularExpressions.Regex.Match(afterDoc, @"(class|interface|enum|method|constructor|field)\s+(\w+)");
|
|
|
|
tree.Documentation.Add(new SyntaxDocumentation
|
|
{
|
|
ElementName = elementMatch.Success ? elementMatch.Groups[2].Value : "Unknown",
|
|
Content = content,
|
|
Format = DocFormat.JavaDoc
|
|
});
|
|
}
|
|
}
|
|
|
|
private int GetLineNumber(string sourceCode, int index)
|
|
{
|
|
return sourceCode.Substring(0, index).Count(c => c == '\n') + 1;
|
|
}
|
|
}
|