using System;
using System.Collections.Generic;
using System.Linq;
using MarketAlly.IronJava.Core.AST.Nodes;
using MarketAlly.IronJava.Core.AST.Visitors;
namespace MarketAlly.IronJava.Core.AST.Query
{
///
/// Provides LINQ-style querying capabilities for AST nodes.
///
public static class AstQuery
{
///
/// Find all nodes of a specific type in the AST.
///
public static IEnumerable FindAll(this JavaNode root) where T : JavaNode
{
var finder = new TypeFinder();
root.Accept(finder);
return finder.Results;
}
///
/// Find the first node of a specific type, or null if not found.
///
public static T? FindFirst(this JavaNode root) where T : JavaNode
{
return root.FindAll().FirstOrDefault();
}
///
/// Find all nodes matching a predicate.
///
public static IEnumerable Where(this JavaNode root, Func predicate) where T : JavaNode
{
return root.FindAll().Where(predicate);
}
///
/// Find the parent of a specific type.
///
public static T? FindParent(this JavaNode node) where T : JavaNode
{
var current = node.Parent;
while (current != null)
{
if (current is T typedParent)
{
return typedParent;
}
current = current.Parent;
}
return null;
}
///
/// Get all ancestors of a node.
///
public static IEnumerable Ancestors(this JavaNode node)
{
var current = node.Parent;
while (current != null)
{
yield return current;
current = current.Parent;
}
}
///
/// Get all descendants of a node.
///
public static IEnumerable Descendants(this JavaNode node)
{
var collector = new DescendantCollector();
node.Accept(collector);
return collector.Results.Skip(1); // Skip the root node itself
}
///
/// Check if a node contains another node.
///
public static bool Contains(this JavaNode ancestor, JavaNode descendant)
{
return descendant.Ancestors().Contains(ancestor);
}
///
/// Get the depth of a node in the tree.
///
public static int Depth(this JavaNode node)
{
return node.Ancestors().Count();
}
///
/// Find all method calls to a specific method name.
///
public static IEnumerable FindMethodCalls(this JavaNode root, string methodName)
{
return root.FindAll()
.Where(m => m.MethodName == methodName);
}
///
/// Find all references to a specific type.
///
public static IEnumerable FindTypeReferences(this JavaNode root, string typeName)
{
return root.FindAll()
.Where(t => t.Name == typeName || t.FullName == typeName);
}
///
/// Find all fields with a specific type.
///
public static IEnumerable FindFieldsOfType(this JavaNode root, string typeName)
{
return root.FindAll()
.Where(f => f.Type is ClassOrInterfaceType type &&
(type.Name == typeName || type.FullName == typeName));
}
///
/// Get the enclosing class of a node.
///
public static ClassDeclaration? GetEnclosingClass(this JavaNode node)
{
return node.FindParent();
}
///
/// Get the enclosing method of a node.
///
public static MethodDeclaration? GetEnclosingMethod(this JavaNode node)
{
return node.FindParent();
}
///
/// Check if a node is within a static context.
///
public static bool IsInStaticContext(this JavaNode node)
{
var method = node.GetEnclosingMethod();
if (method?.Modifiers.IsStatic() == true)
return true;
var field = node.FindParent();
if (field?.Modifiers.IsStatic() == true)
return true;
var initializer = node.FindParent();
return initializer?.IsStatic == true;
}
private class TypeFinder : JavaVisitorBase where T : JavaNode
{
public List Results { get; } = new();
protected override void DefaultVisit(JavaNode node)
{
if (node is T typedNode)
{
Results.Add(typedNode);
}
base.DefaultVisit(node);
}
}
private class DescendantCollector : JavaVisitorBase
{
public List Results { get; } = new();
protected override void DefaultVisit(JavaNode node)
{
Results.Add(node);
base.DefaultVisit(node);
}
}
}
///
/// Fluent query builder for complex AST queries.
///
public class AstQueryBuilder where T : JavaNode
{
private readonly JavaNode _root;
private readonly List> _predicates = new();
public AstQueryBuilder(JavaNode root)
{
_root = root;
}
public AstQueryBuilder Where(Func predicate)
{
_predicates.Add(predicate);
return this;
}
public AstQueryBuilder WithModifier(Modifiers modifier)
{
_predicates.Add(node =>
{
if (node is TypeDeclaration type)
return type.Modifiers.HasFlag(modifier);
if (node is MemberDeclaration member)
return member.Modifiers.HasFlag(modifier);
return false;
});
return this;
}
public AstQueryBuilder WithName(string name)
{
_predicates.Add(node =>
{
return node switch
{
TypeDeclaration type => type.Name == name,
MethodDeclaration method => method.Name == name,
VariableDeclarator variable => variable.Name == name,
Parameter parameter => parameter.Name == name,
IdentifierExpression identifier => identifier.Name == name,
_ => false
};
});
return this;
}
public AstQueryBuilder InClass(string className)
{
_predicates.Add(node =>
{
var enclosingClass = node.GetEnclosingClass();
return enclosingClass?.Name == className;
});
return this;
}
public AstQueryBuilder InMethod(string methodName)
{
_predicates.Add(node =>
{
var enclosingMethod = node.GetEnclosingMethod();
return enclosingMethod?.Name == methodName;
});
return this;
}
public IEnumerable Execute()
{
var results = _root.FindAll();
foreach (var predicate in _predicates)
{
results = results.Where(predicate);
}
return results;
}
public T? ExecuteFirst()
{
return Execute().FirstOrDefault();
}
public int Count()
{
return Execute().Count();
}
public bool Any()
{
return Execute().Any();
}
}
///
/// Extension methods for creating query builders.
///
public static class AstQueryBuilderExtensions
{
public static AstQueryBuilder Query(this JavaNode root) where T : JavaNode
{
return new AstQueryBuilder(root);
}
public static AstQueryBuilder QueryClasses(this JavaNode root)
{
return new AstQueryBuilder(root);
}
public static AstQueryBuilder QueryMethods(this JavaNode root)
{
return new AstQueryBuilder(root);
}
public static AstQueryBuilder QueryFields(this JavaNode root)
{
return new AstQueryBuilder(root);
}
}
///
/// Pattern matching for AST nodes.
///
public static class AstPattern
{
///
/// Match getter methods (methods starting with "get" that return a value and have no parameters).
///
public static bool IsGetter(this MethodDeclaration method)
{
return method.Name.StartsWith("get", StringComparison.Ordinal) &&
method.ReturnType != null &&
!method.Parameters.Any() &&
!method.Modifiers.IsStatic();
}
///
/// Match setter methods (methods starting with "set" that return void and have one parameter).
///
public static bool IsSetter(this MethodDeclaration method)
{
return method.Name.StartsWith("set", StringComparison.Ordinal) &&
method.ReturnType is PrimitiveType pt && pt.Kind == PrimitiveTypeKind.Void &&
method.Parameters.Count == 1 &&
!method.Modifiers.IsStatic();
}
///
/// Match main method pattern.
///
public static bool IsMainMethod(this MethodDeclaration method)
{
return method.Name == "main" &&
method.Modifiers.IsPublic() &&
method.Modifiers.IsStatic() &&
method.ReturnType is PrimitiveType pt && pt.Kind == PrimitiveTypeKind.Void &&
method.Parameters.Count == 1 &&
method.Parameters[0].Type is ArrayType arrayType &&
arrayType.ElementType is ClassOrInterfaceType classType &&
classType.Name == "String";
}
///
/// Match constructor pattern.
///
public static bool IsConstructor(this MethodDeclaration method)
{
return method.IsConstructor;
}
///
/// Match singleton pattern (private constructor, static instance field).
///
public static bool IsSingletonClass(this ClassDeclaration cls)
{
var hasPrivateConstructor = cls.Members
.OfType()
.Any(m => m.IsConstructor && m.Modifiers.IsPrivate());
var hasStaticInstanceField = cls.Members
.OfType()
.Any(f => f.Modifiers.IsStatic() &&
f.Type is ClassOrInterfaceType type &&
type.Name == cls.Name);
return hasPrivateConstructor && hasStaticInstanceField;
}
}
}