using System.Text; using CodePlay.Core.Interfaces; using CodePlay.Core.Models; using CodePlay.Core.Common; namespace CodePlay.Core.Parsers; /// /// Java 语法解析器 (增强版) /// 支持注解、泛型、Lambda、Stream、Optional、记录类等高级特性 /// public class JavaParser : BaseParser { public override LanguageType SupportedLanguage => LanguageType.Java; public override Task ParseAsync(string sourceCode, CancellationToken cancellationToken = default) { var tree = CreateSyntaxTree(); tree.SourceCode = sourceCode; var root = new Interfaces.SyntaxNode { Type = SyntaxNodeType.CompilationUnit, Text = sourceCode, Metadata = new Dictionary() }; ExtractPackage(tree, sourceCode, root); ExtractImports(tree, sourceCode, root); ExtractTypes(tree, sourceCode, root); ExtractComments(tree, sourceCode); ExtractDocumentation(tree, sourceCode); ExtractAdvancedFeatures(tree, sourceCode, root); 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 { ["packageName"] = packageMatch.Groups[1].Value } }; root.Children.Add(packageNode); } } 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); var staticImports = new List(); var regularImports = new List(); foreach (System.Text.RegularExpressions.Match match in importMatches) { var importNode = new Interfaces.SyntaxNode { Type = SyntaxNodeType.Field, Text = match.Value, Metadata = new Dictionary { ["isStatic"] = !string.IsNullOrEmpty(match.Groups[1].Value), ["importName"] = match.Groups[2].Value } }; root.Children.Add(importNode); if (match.Groups[1].Success) staticImports.Add(match.Groups[2].Value); else regularImports.Add(match.Groups[2].Value); } root.Metadata["Imports"] = regularImports; root.Metadata["StaticImports"] = staticImports; } private void ExtractTypes(Interfaces.SyntaxTree tree, string sourceCode, Interfaces.SyntaxNode root) { ExtractClasses(sourceCode, root); ExtractInterfaces(sourceCode, root); ExtractEnums(sourceCode, root); ExtractRecords(sourceCode, root); } private void ExtractClasses(string sourceCode, Interfaces.SyntaxNode root) { var classPattern = @"(public|private|protected)?\s*(abstract|final|static|sealed)?\s*(class|record)\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 isRecord = match.Groups[3].Value == "record"; var classNode = new Interfaces.SyntaxNode { Type = isRecord ? SyntaxNodeType.Class : SyntaxNodeType.Class, Text = match.Value, Metadata = new Dictionary { ["accessModifier"] = match.Groups[1].Value, ["modifiers"] = match.Groups[2].Value, ["kind"] = isRecord ? "record" : "class", ["className"] = match.Groups[4].Value, ["typeParameters"] = match.Groups[5].Success ? match.Groups[5].Value : null, ["extends"] = match.Groups[6].Success ? match.Groups[6].Value : null, ["implements"] = match.Groups[7].Success ? match.Groups[7].Value : null, ["isRecord"] = isRecord } }; root.Children.Add(classNode); ExtractClassMembers(sourceCode, classNode, match.Groups[4].Value); } } private void ExtractInterfaces(string sourceCode, Interfaces.SyntaxNode root) { var interfacePattern = @"(public)?\s*(sealed|non-sealed)?\s*(interface|@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 isAnnotation = match.Groups[3].Value == "@interface"; var interfaceNode = new Interfaces.SyntaxNode { Type = SyntaxNodeType.Interface, Text = match.Value, Metadata = new Dictionary { ["accessModifier"] = match.Groups[1].Value, ["modifiers"] = match.Groups[2].Value, ["kind"] = isAnnotation ? "annotation" : "interface", ["interfaceName"] = match.Groups[4].Value, ["typeParameters"] = match.Groups[5].Success ? match.Groups[5].Value : null, ["extends"] = match.Groups[6].Success ? match.Groups[6].Value : null, ["isAnnotation"] = isAnnotation } }; 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, Text = match.Value, Metadata = new Dictionary { ["accessModifier"] = match.Groups[1].Value, ["enumName"] = match.Groups[3].Value } }; root.Children.Add(enumNode); } } private void ExtractRecords(string sourceCode, Interfaces.SyntaxNode root) { var recordPattern = @"(public)?\s*record\s+(\w+)(?:<([^>]+)>)?\s*\(([^)]*)\)"; var recordMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, recordPattern); foreach (System.Text.RegularExpressions.Match match in recordMatches) { var recordNode = new Interfaces.SyntaxNode { Type = SyntaxNodeType.Class, Text = match.Value, Metadata = new Dictionary { ["accessModifier"] = match.Groups[1].Value, ["recordName"] = match.Groups[2].Value, ["typeParameters"] = match.Groups[3].Success ? match.Groups[3].Value : null, ["components"] = match.Groups[4].Value } }; root.Children.Add(recordNode); } } private void ExtractClassMembers(string code, Interfaces.SyntaxNode classNode, string className) { ExtractMethods(code, classNode); ExtractFields(code, classNode); ExtractConstructors(code, classNode, className); ExtractAnnotations(code, classNode); } private void ExtractMethods(string code, Interfaces.SyntaxNode classNode) { var methodPattern = @"(public|private|protected)\s+(static\s+)?(final\s+)?(synchronized\s+)?(?:(\w+(?:<[^>]+>?)(?:\[\])?)\s+)?(\w+)\s*\(([^)]*)\)(?:\s+throws\s+([\w,\s]+))?"; var methodMatches = System.Text.RegularExpressions.Regex.Matches(code, methodPattern); var methodNames = new List(); foreach (System.Text.RegularExpressions.Match match in methodMatches) { var methodName = match.Groups[6].Value; if (methodName == "class" || methodName == "interface" || methodName == "enum" || methodName == "record") continue; methodNames.Add(methodName); var returnType = string.IsNullOrEmpty(match.Groups[5].Value) ? "void" : match.Groups[5].Value; var methodNode = new Interfaces.SyntaxNode { Type = SyntaxNodeType.Method, Text = match.Value, Metadata = new Dictionary { ["accessModifier"] = match.Groups[1].Value, ["isStatic"] = !string.IsNullOrEmpty(match.Groups[2].Value), ["isFinal"] = !string.IsNullOrEmpty(match.Groups[3].Value), ["isSynchronized"] = !string.IsNullOrEmpty(match.Groups[4].Value), ["returnType"] = returnType, ["methodName"] = methodName, ["parameters"] = match.Groups[7].Value, ["throws"] = match.Groups[8].Success ? match.Groups[8].Value : null } }; classNode.Children.Add(methodNode); ExtractParameters(match.Groups[7].Value, methodNode); } classNode.Metadata["Methods"] = methodNames; } private void ExtractFields(string code, Interfaces.SyntaxNode classNode) { var fieldPattern = @"(private|protected|public)\s+(static\s+)?(final\s+)?(transient\s+)?(volatile\s+)?(\w+(?:<[^>]+>)?(?:\[\])?)\s+(\w+)\s*[;=]"; var fieldMatches = System.Text.RegularExpressions.Regex.Matches(code, fieldPattern); var fieldNames = new List(); foreach (System.Text.RegularExpressions.Match match in fieldMatches) { fieldNames.Add(match.Groups[6].Value); var fieldNode = new Interfaces.SyntaxNode { Type = SyntaxNodeType.Field, Text = match.Value, Metadata = new Dictionary { ["accessModifier"] = match.Groups[1].Value, ["isStatic"] = !string.IsNullOrEmpty(match.Groups[2].Value), ["isFinal"] = !string.IsNullOrEmpty(match.Groups[3].Value), ["isTransient"] = !string.IsNullOrEmpty(match.Groups[4].Value), ["isVolatile"] = !string.IsNullOrEmpty(match.Groups[5].Value), ["type"] = match.Groups[5].Value, ["fieldName"] = match.Groups[6].Value } }; classNode.Children.Add(fieldNode); } classNode.Metadata["Fields"] = fieldNames; } private void ExtractConstructors(string code, Interfaces.SyntaxNode classNode, string className) { var constructorPattern = @"(public|private|protected)?\s+(\w+)\s*\(([^)]*)\)(?:\s+throws\s+([\w,\s]+))?"; var constructorMatches = System.Text.RegularExpressions.Regex.Matches(code, constructorPattern); foreach (System.Text.RegularExpressions.Match match in constructorMatches) { if (match.Groups[2].Value == className) { var constructorNode = new Interfaces.SyntaxNode { Type = SyntaxNodeType.Constructor, Text = match.Value, Metadata = new Dictionary { ["accessModifier"] = match.Groups[1].Value, ["constructorName"] = match.Groups[2].Value, ["parameters"] = match.Groups[3].Value, ["throws"] = match.Groups[4].Success ? match.Groups[4].Value : null } }; classNode.Children.Add(constructorNode); ExtractParameters(match.Groups[3].Value, constructorNode); } } } private void ExtractAnnotations(string code, Interfaces.SyntaxNode classNode) { var annotationPattern = @"@(\w+)(?:\(([^)]*)\))?"; var annotationMatches = System.Text.RegularExpressions.Regex.Matches(code, annotationPattern); var annotations = new List>(); foreach (System.Text.RegularExpressions.Match match in annotationMatches) { annotations.Add(new Dictionary { ["name"] = match.Groups[1].Value, ["parameters"] = match.Groups[2].Success ? match.Groups[2].Value : null }); } classNode.Metadata["Annotations"] = annotations; } private void ExtractParameters(string parametersText, Interfaces.SyntaxNode parentNode) { if (string.IsNullOrWhiteSpace(parametersText)) return; var paramPattern = @"(?:@(\w+)(?:\([^)]*\)))?\s*(final\s+)?(\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 { ["annotation"] = match.Groups[1].Success ? match.Groups[1].Value : null, ["isFinal"] = !string.IsNullOrEmpty(match.Groups[2].Value), ["type"] = match.Groups[3].Value, ["name"] = match.Groups[4].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(); var multiLineStart = 0; 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); multiLineStart = i + 1; continue; } if (inMultiLineComment) { multiLineComment.AppendLine(line); if (line.Contains("*/")) { inMultiLineComment = false; tree.Comments.Add(new SyntaxComment { Text = multiLineComment.ToString().Trim(), Type = CommentType.MultiLine, LineNumber = multiLineStart }); 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, @"@(interface|@interface|class|enum|record)\s+(\w+)"); tree.Documentation.Add(new SyntaxDocumentation { ElementName = elementMatch.Success ? elementMatch.Groups[2].Value : "Unknown", Content = content, Format = DocFormat.JavaDoc }); } } private void ExtractAdvancedFeatures(Interfaces.SyntaxTree tree, string sourceCode, Interfaces.SyntaxNode root) { // 检测 Lambda 表达式 var lambdaCount = System.Text.RegularExpressions.Regex.Matches(sourceCode, @"->").Count; root.Metadata["LambdaCount"] = lambdaCount; // 检测 Stream API 使用 var streamMethods = new[] { "stream()", "filter(", "map(", "flatMap(", "collect(", "reduce(", "forEach(" }; var streamUsage = streamMethods.Count(m => sourceCode.Contains(m)); root.Metadata["StreamUsage"] = streamUsage; // 检测 Optional 使用 var optionalCount = System.Text.RegularExpressions.Regex.Matches(sourceCode, @"Optional(?:<[^>]+>)?").Count; root.Metadata["OptionalUsage"] = optionalCount; // 检测泛型使用 var genericPattern = @"<([^>]+)>"; var genericMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, genericPattern); var typeParameters = genericMatches.Cast() .Select(m => m.Groups[1].Value) .Distinct() .ToList(); root.Metadata["TypeParameters"] = typeParameters; // 检测注解使用 var annotationPattern = @"@(\w+)"; var annotationMatches = System.Text.RegularExpressions.Regex.Matches(sourceCode, annotationPattern); var annotations = annotationMatches.Cast() .Select(m => m.Groups[1].Value) .Distinct() .ToList(); root.Metadata["Annotations"] = annotations; } private int GetLineNumber(string sourceCode, int index) { return sourceCode.Substring(0, index).Count(c => c == '\n') + 1; } }